diff --git a/bin/nostr_console.dart b/bin/nostr_console.dart index ded4848..091e3ff 100644 --- a/bin/nostr_console.dart +++ b/bin/nostr_console.dart @@ -215,7 +215,7 @@ Future main(List arguments) async { if( argResults[requestArg] != "") { stdout.write('Sending request ${argResults[requestArg]} and waiting for events...'); - sendRequest(gListRelayUrls, argResults[requestArg]); + sendRequest(gListRelayUrls1, argResults[requestArg]); } else { numWaitSeconds = 0; gEventsFilename = ""; // so it wont write it back to keep it faster ( and since without internet no new event is there to be written ) @@ -237,11 +237,13 @@ Future main(List arguments) async { return; } - getUserEvents(gListRelayUrls, userPublicKey, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); + getUserEvents(gListRelayUrls1, userPublicKey, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); + getMentionEvents(gListRelayUrls2, userPublicKey, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); // from relay group 2 + getKindEvents([0,3], gListRelayUrls1, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor* 10)); // the default in case no arguments are given is: - // get a user's events, then from its type 3 event, gets events of its follows, - // then get the events of user-id's mentioned in p-tags of received events + // get a user's events, and get all kind 0, 3 events + // then get the events of user-id's mentioned in p-tags of received events and the contact list // then display them all stdout.write('Waiting for user posts to come in.....'); Future.delayed(const Duration(milliseconds: gDefaultNumWaitSeconds), () { @@ -258,42 +260,27 @@ Future main(List arguments) async { // get the latest kind 3 event for the user, which lists his 'follows' list Event? contactEvent = getContactEvent(userPublicKey); - // if contact list was found, get user's feed, and keep the contact list for later use + // if contact list was found, get user's feed; also get some default contacts + Set contacts = {}; + contacts.addAll(gDefaultFollows); if (contactEvent != null ) { if(gDebug > 0) print("In main: found contact list: \n ${contactEvent.originalJson}"); - getContactFeed(gListRelayUrls, contactEvent.eventData.contactList, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); - - if( !gContactLists.containsKey(userPublicKey)) { - gContactLists[userPublicKey] = contactEvent.eventData.contactList; - } - } else { - if( gDebug > 0) log.info( "Could not find contact list"); + contactEvent.eventData.contactList.forEach((contact) { + contacts.add(contact.relay); + }); } + getContactFeed(gListRelayUrls1, contacts, gLimitPerSubscription, getSecondsDaysAgo(2 * gDaysToGetEventsFor)); + + // calculate top mentioned ptags, and then get the events for those users + List pTags = getpTags(initialEvents, gMaxPtagsToGet); + getMultiUserEvents(gListRelayUrls1, pTags, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); stdout.write('Waiting for feed to come in..............'); Future.delayed(const Duration(milliseconds: gDefaultNumWaitSeconds * 1), () { - initialEvents.addAll(getRecievedEvents()); - clearEvents(); - - // count feed events - initialEvents.forEach((element) { element.eventData.kind == 1? numFeedPosts++: numFeedPosts;}); - numFeedPosts = numFeedPosts - numUserPosts - numFilePosts; - stdout.write("done\n");//received $numFeedPosts new posts from the follows\n"); - - // get mentioned ptags, and then get the events for those users - List pTags = getpTags(initialEvents, gMaxPtagsToGet); - getMultiUserEvents(gListRelayUrls, pTags, gLimitPerSubscription, getSecondsDaysAgo(gDaysToGetEventsFor)); - - stdout.write('Waiting for rest of posts to come in.....'); - Future.delayed(const Duration(milliseconds: gDefaultNumWaitSeconds * 2), () { - initialEvents.addAll(getRecievedEvents()); clearEvents(); - // count other events - initialEvents.forEach((element) { element.eventData.kind == 1? numOtherPosts++: numOtherPosts;}); - numOtherPosts = numOtherPosts - numFeedPosts - numUserPosts - numFilePosts; stdout.write("done\n"); if( gDebug > 0) log.info("Received ptag events events."); @@ -303,10 +290,7 @@ Future main(List arguments) async { clearEvents(); mainMenuUi(node); }); - }); }); - - } on FormatException catch (e) { print(e.message); return; diff --git a/lib/console_ui.dart b/lib/console_ui.dart index fa0b94a..2d24d6b 100644 --- a/lib/console_ui.dart +++ b/lib/console_ui.dart @@ -69,7 +69,7 @@ Future sendReplyPostLike(Store node, String replyToId, String replyKind, S String toSendMessage = '["EVENT",{"id":"$id","pubkey":"$userPublicKey","created_at":$createdAt,"kind":$replyKind,"tags":[$vanityTag],"content":"$content","sig":"$sig"}]'; //relays.sendRequest(defaultServerUrl, toSendMessage); - sendRequest( gListRelayUrls, toSendMessage); + sendRequest( gListRelayUrls1, toSendMessage); } // is same as above. remove it TODO @@ -85,7 +85,7 @@ Future sendChatMessage(Store node, String channelId, String messageToSend) String toSendMessage = '["EVENT",{"id":"$id","pubkey":"$userPublicKey","created_at":$createdAt,"kind":$replyKind,"tags":[$strTags],"content":"$messageToSend","sig":"$sig"}]'; //relays.sendRequest(defaultServerUrl, toSendMessage); - sendRequest( gListRelayUrls, toSendMessage); + sendRequest( gListRelayUrls1, toSendMessage); } // send DM @@ -108,7 +108,7 @@ Future sendDirectMessage(Store node, String otherPubkey, String messageToS String sig = sign(userPrivateKey, id, "12345612345612345612345612345612"); String eventStrToSend = '["EVENT",{"id":"$id","pubkey":"$userPublicKey","created_at":$createdAt,"kind":$replyKind,"tags":[$strTags],"content":"$encryptedMessageToSend","sig":"$sig"}]'; - sendRequest( gListRelayUrls, eventStrToSend); + sendRequest( gListRelayUrls1, eventStrToSend); } // sends event e; used to send kind 3 event @@ -144,7 +144,7 @@ Future sendEvent(Store node, Event e) async { String toSendMessage = '["EVENT",{"id":"$id","pubkey":"$userPublicKey","created_at":$createdAt,"kind":${e.eventData.kind.toString()},"tags":[$strTags],"content":"$content","sig":"$sig"}]'; //print("in send event: calling sendrequiest"); - sendRequest(gListRelayUrls, toSendMessage); + sendRequest(gListRelayUrls1, toSendMessage); } bool sendDeleteEvent(Store node, String eventIdToDelete) { @@ -163,7 +163,7 @@ bool sendDeleteEvent(Store node, String eventIdToDelete) { String sig = sign(userPrivateKey, id, "12345612345612345612345612345612"); String toSendMessage = '["EVENT",{"id":"$id","pubkey":"$userPublicKey","created_at":$createdAt,"kind":$replyKind,"tags":[$strTags],"content":"$content","sig":"$sig"}]'; - sendRequest( gListRelayUrls, toSendMessage); + sendRequest( gListRelayUrls1, toSendMessage); print("sent event delete request with id = $id"); print(toSendMessage); } else { diff --git a/lib/relays.dart b/lib/relays.dart index b39cc23..1418c74 100644 --- a/lib/relays.dart +++ b/lib/relays.dart @@ -83,6 +83,32 @@ class Relays { sendRequest(relayUrl, request); } + void getMentionEvents(String relayUrl, String publicKey, int limit, int sinceWhen) { + for(int i = 0; i < gBots.length; i++) { // ignore bots + if( publicKey == gBots[i]) { + return; + } + } + + String subscriptionId = "mention" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6); + if( relays.containsKey(relayUrl)) { + List? users = relays[relayUrl]?.users; + if( users != null) { // get a user only if it has not already been requested + // following is too restrictive casuse changed sinceWhen is not considered. TODO improve it + for(int i = 0; i < users.length; i++) { + if( users[i] == publicKey) { + return; + } + } + users.add(publicKey); + } + } + + String request = getMentionRequest(subscriptionId, publicKey, limit, sinceWhen); + sendRequest(relayUrl, request); + } + + /* * @connect Connect to given relay and get all events for multiple users/publicKey and insert the * received events in the given List @@ -231,6 +257,7 @@ String getKindRequest(String subscriptionId, List kind, int limit, int sinc //print(strRequest); return strRequest; } + String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen) { String strTime = ""; if( sinceWhen != 0) { @@ -241,6 +268,17 @@ String getUserRequest(String subscriptionId, String publicKey, int numUserEvents return strSubscription1 + publicKey + strSubscription2; } + +String getMentionRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen) { + String strTime = ""; + if( sinceWhen != 0) { + strTime = ', "since": ${sinceWhen.toString()}'; + } + var strSubscription1 = '["REQ","$subscriptionId",{ "#p": ["'; + var strSubscription2 ='"], "limit": $numUserEvents $strTime } ]'; + return strSubscription1 + publicKey + strSubscription2; +} + String getMultiUserRequest(String subscriptionId, List publicKeys, int numUserEvents, int sinceWhen) { String strTime = ""; if( sinceWhen != 0) { @@ -260,8 +298,9 @@ String getMultiUserRequest(String subscriptionId, List publicKeys, int n return strSubscription1 + s + strSubscription2; } -void getContactFeed(List relayUrls, List contacts, int numEventsToGet, int sinceWhen) { +void getContactFeed(List relayUrls, Set setContacts, int numEventsToGet, int sinceWhen) { + List contacts = setContacts.toList(); for( int i = 0; i < contacts.length; i += gMaxAuthorsInOneRequest) { @@ -291,6 +330,13 @@ void getUserEvents(List serverUrls, String publicKey, int numUserEvents, }); } +void getMentionEvents(List serverUrls, String publicKey, int numUserEvents, int sinceWhen) { + serverUrls.forEach((serverUrl) { + relays.getMentionEvents(serverUrl, publicKey, numUserEvents, sinceWhen); + }); +} + + getKindEvents(List kind, List serverUrls, int limit, int sinceWhen) { serverUrls.forEach((serverUrl) { relays.getKindEvents(kind, serverUrl, limit, sinceWhen); diff --git a/lib/settings.dart b/lib/settings.dart index c2ce8ff..7387f39 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -15,7 +15,7 @@ const int gDontSaveBeforeDays = 100; // dont save events older than this m bool gOverWriteFile = false; // overwrite the file, and don't just append. Will write all events in memory. -const int gDaysToGetEventsFor = 30; // when getting events, this is the since field (unless a fully formed request is given in command line) +const int gDaysToGetEventsFor = 70; // when getting events, this is the since field (unless a fully formed request is given in command line) const int gLimitPerSubscription = 5000; // don't show notifications for events that are older than 5 days and come when program is running @@ -23,7 +23,7 @@ const int gLimitPerSubscription = 5000; const int gDontHighlightEventsOlderThan = 4; const int gMaxAuthorsInOneRequest = 100; // number of author requests to send in one request -const int gMaxPtagsToGet = 100; // maximum number of p tags that are taken from the comments of feed ( the top most, most frequent) +const int gMaxPtagsToGet = 150; // maximum number of p tags that are taken from the comments of feed ( the top most, most frequent) // global counters of total events read or processed int numFilePosts = 0, numUserPosts = 0, numFeedPosts = 0, numOtherPosts = 0; @@ -33,9 +33,12 @@ int numFilePosts = 0, numUserPosts = 0, numFeedPosts = 0, numOtherPosts = 0; const String relayNostrInfo = 'wss://relay.nostr.info'; String defaultServerUrl = "wss://relay.damus.io"; -List gListRelayUrls = [ defaultServerUrl, +List gListRelayUrls1 = [ defaultServerUrl, relayNostrInfo, - "wss://nostr-verified.wellorder.net", + "wss://nostr-verified.wellorder.net" + ]; + +List gListRelayUrls2 = [ "wss://nostr-relay.wlvs.space", "wss://nostr.ono.re" ]; @@ -61,10 +64,16 @@ List gDefaultFollows = [ "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437", // balas "46fcbe3065eaf1ae7811465924e48923363ff3f526bd6f73d7c184b16bd8ce4d", // Giszmo "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168", // monlovesmango - "3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c", // vishalxl "c5072866b41d6b88ab2ffee16ad7cb648f940867371a7808aaa94cf7d01f4188", // randymcmillan "2183e94758481d0f124fbd93c56ccaa45e7e545ceeb8d52848f98253f497b975", // Brill - "c7eda660a6bc8270530e82b4a7712acdea2e31dc0a56f8dc955ac009efd97c86" ]; // shawn + "00000000827ffaa94bfea288c3dfce4422c794fbb96625b6b31e9049f729d700", // cameri + "dd81a8bacbab0b5c3007d1672fb8301383b4e9583d431835985057223eb298a5", // plantimals + "1c6b3be353041dd9e09bb568a4a92344e240b39ef5eb390f5e9e821273f0ae6f", // johnonchain + "52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8bd", // semisol + "47bae3a008414e24b4d91c8c170f7fce777dedc6780a462d010761dca6482327", // slaninas + "c7eda660a6bc8270530e82b4a7712acdea2e31dc0a56f8dc955ac009efd97c86", // shawn + "b2d670de53b27691c0c3400225b65c35a26d06093bcc41f48ffc71e0907f9d4a", // 0xtr + "3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c"]; // vishalxl ]; // dummy account pubkey