From 91ddb3911ba9193b41f235ed277d3254ff92d3ea Mon Sep 17 00:00:00 2001 From: Vishal <64505169+vishalxl@users.noreply.github.com> Date: Thu, 22 Dec 2022 06:58:02 +0530 Subject: [PATCH] improved fetching or requests added zbd relay and more added more default initial users to fetch --- bin/nostr_console.dart | 60 +++++++++++++++++++------------- lib/console_ui.dart | 9 +++++ lib/event_ds.dart | 9 +++-- lib/relays.dart | 33 +++++------------- lib/settings.dart | 57 ++++++++++++++++++++++++++----- lib/tree_ds.dart | 13 ++++--- lib/utils.dart | 77 ++++++++++++++++++++++++++++++++---------- 7 files changed, 179 insertions(+), 79 deletions(-) diff --git a/bin/nostr_console.dart b/bin/nostr_console.dart index ed970db..0c4dec8 100644 --- a/bin/nostr_console.dart +++ b/bin/nostr_console.dart @@ -65,7 +65,6 @@ Future main(List arguments) async { // start application printIntro("Nostr"); - if( argResults["debug"]) { gDebug = 1; } @@ -133,11 +132,13 @@ Future main(List arguments) async { // verify that there is at least one valid relay they provided, otherwise keep defaults if (parsedRelays.length > 0) { gListRelayUrls1 = parsedRelays; + defaultServerUrl = gListRelayUrls1.first; } else { print("No valid relays were provided, using the default relay list"); } } - printSet( gListRelayUrls1, "Relay List: "); + printSet( gListRelayUrls1, "Primary relays that will be used: "); + print("From among them, default relay: $defaultServerUrl"); if( argResults[lastdaysArg] != null) { gNumLastDays = int.parse(argResults[lastdaysArg]); @@ -251,8 +252,8 @@ Future main(List arguments) async { //log.info("after reading events"); // count events - initialEvents.forEach((element) { element.eventData.kind == 1? numFilePosts++: numFilePosts;}); - print("read $numFilePosts posts from file $gEventsFilename"); + initialEvents.forEach((element) { numFileEvents++;}); + print("read $numFileEvents events from file $gEventsFilename"); } // process request string. If this is blank then the application only reads from file and does not connect to internet. @@ -292,40 +293,46 @@ Future main(List arguments) async { // then get the events of user-id's mentioned in p-tags of received events and the contact list // then display them all - int limitFollowPosts = gLimitFollowPosts; - int limitMetaInfoEvents = 300; int limitSelfEvents = 300; + int limitOthersEvents = 20; int limitPerSubscription = gLimitPerSubscription; // if more than 1000 posts have already been read from the file, then don't get too many day's events. Only for last 3 days. if(numFilePosts > 1000) { limitPerSubscription = 5000; - limitSelfEvents = 5; - limitMetaInfoEvents = 3; - limitFollowPosts = 3; + limitSelfEvents = 10; + limitOthersEvents = 3; gDefaultNumWaitSeconds = gDefaultNumWaitSeconds ~/5 ; + } else { + printInfoForNewUser(); } // get event for user if( userPublicKey!= "") { getUserEvents(gListRelayUrls1, userPublicKey, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents)); - getMentionEvents(gListRelayUrls2, {userPublicKey}, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents), "#p"); // from relay group 2 + getMentionEvents(gListRelayUrls1, {userPublicKey}, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents), "#p"); } + //getKindEvents([gSecretMessageKind], gListRelayUrls1, limitPerSubscription, getSecondsDaysAgo( limitSelfEvents)); + Set usersFetched = {userPublicKey}; + // remove user from default list if he exists in it. because theyv'e already been fetched. + gDefaultFollows = gDefaultFollows.difference(usersFetched); + + //print("getting defaultfollows. usersFetched len = ${usersFetched.length} "); // get other user events - getMultiUserEvents(gListRelayUrls1, gDefaultFollows, limitPerSubscription, getSecondsDaysAgo(limitFollowPosts)); + getMultiUserEvents(gListRelayUrls1, gDefaultFollows, 4 * limitPerSubscription, getSecondsDaysAgo(limitOthersEvents)); + usersFetched = usersFetched.union(gDefaultFollows); // get group and meta info events - getKindEvents([0, 3, 40, 41], gListRelayUrls1, 3 * limitPerSubscription, getSecondsDaysAgo(limitMetaInfoEvents)); // get all type 3 etc - getKindEvents([42], gListRelayUrls1, limitPerSubscription * 3, getSecondsDaysAgo( limitFollowPosts)); // get all type 3 etc + getKindEvents([40, 41], gListRelayUrls1, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents)); + getKindEvents([42], gListRelayUrls1, 3 * limitPerSubscription, 40000); - getKindEvents([gSecretMessageKind], gListRelayUrls1, limitPerSubscription * 3, getSecondsDaysAgo( 3)); // get all type 3 etc + getMultiUserEvents(gListRelayUrls1, usersFetched, 4 * limitPerSubscription, getSecondsDaysAgo(limitSelfEvents), {0,3}); - // TODO get all 40 events, and then get all #e for them ( responses to them) - stdout.write('Waiting for user posts to come in.....'); Future.delayed( Duration(milliseconds: gDefaultNumWaitSeconds), () { + //print("total users fetched: ${usersFetched.length}"); initialEvents.addAll(getRecievedEvents()); clearEvents(); @@ -333,30 +340,37 @@ Future main(List arguments) async { initialEvents.forEach((element) { element.eventData.kind == 1? numUserPosts++: numUserPosts;}); numUserPosts -= numFilePosts; stdout.write("...done\n");//received $numUserPosts new posts made by the user\n"); - if( gDebug > 0) log.info("Received user events."); initialEvents.forEach((e) => processKind3Event(e)); // first process the kind 3 event + Set contacts = {}; if( userPublicKey != "") { // 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; 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}"); contactEvent.eventData.contactList.forEach((contact) { contacts.add(contact.id); }); + contacts = contacts.difference(usersFetched); // remove already fetched users from this list + getContactFeed(gListRelayUrls1, contacts, 3 * gLimitPerSubscription, getSecondsDaysAgo( limitOthersEvents)); + usersFetched = usersFetched.union(contacts); + } else { + print("Could not find your contact list."); } - getContactFeed(gListRelayUrls1, contacts, gLimitPerSubscription, getSecondsDaysAgo(2 * limitFollowPosts)); } // calculate top mentioned ptags, and then get the events for those users - List pTags = getpTags(initialEvents, gMaxPtagsToGet); - getMultiUserEvents(gListRelayUrls1, pTags, gLimitPerSubscription, getSecondsDaysAgo(limitFollowPosts)); - + Set pTags = getpTags(initialEvents, gMaxPtagsToGet); + + pTags = pTags.difference(usersFetched); + getMultiUserEvents(gListRelayUrls1, pTags, 4 * gLimitPerSubscription, getSecondsDaysAgo(limitOthersEvents)); + usersFetched = usersFetched.union(pTags); + + //print("total users fetched: ${usersFetched.length}"); + stdout.write('Waiting for feed to come in..............'); Future.delayed(Duration(milliseconds: gDefaultNumWaitSeconds * 1), () { diff --git a/lib/console_ui.dart b/lib/console_ui.dart index 0ecdef2..2cac14b 100644 --- a/lib/console_ui.dart +++ b/lib/console_ui.dart @@ -49,6 +49,14 @@ String mySign(String privateKey, String msg) { return sign(privateKey, msg, randomSeed); } +Future mySleep(int duration) async { + Future foo() async { + await Future.delayed(Duration(milliseconds: duration)); + return; + } + await foo(); +} + /* @function sendReplyPostLike Used to send Reply, Post and Like ( event 1 for reply and post, and event 7 for like/reaction) * If replyToId is blank, then it does not reference any e/p tags, and thus becomes a top post * otherwise e and p tags are found for the given event being replied to, if that event data is available @@ -92,6 +100,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"}]'; //print("sending $toSendMessage"); sendRequest( gListRelayUrls1, toSendMessage); + await mySleep(200); } // Sends a public channel message diff --git a/lib/event_ds.dart b/lib/event_ds.dart index 2c260ca..6fe0458 100644 --- a/lib/event_ds.dart +++ b/lib/event_ds.dart @@ -956,6 +956,11 @@ class Event { factory Event.fromJson(String d, String relay, [bool fromFile = false]) { try { + if( d.length > gMaxEventLenthAccepted) { + //throw Exception("Event json is larger than max len"); + + } + dynamic json = jsonDecode(d); if( json.length < 3) { @@ -1010,7 +1015,7 @@ void addToHistogram(Map histogram, List pTags) { } // return the numMostFrequent number of most frequent p tags ( user pubkeys) in the given events -List getpTags(Set events, int numMostFrequent) { +Set getpTags(Set events, int numMostFrequent) { List listHistogram = []; Map histogramMap = {}; for(var event in events) { @@ -1024,7 +1029,7 @@ List getpTags(Set events, int numMostFrequent) { ptags.add(listHistogram[i].str); } - return ptags; + return ptags.toSet(); } // From the list of events provided, lookup the lastst contact information for the given user/pubkey diff --git a/lib/relays.dart b/lib/relays.dart index 422c615..f33bef5 100644 --- a/lib/relays.dart +++ b/lib/relays.dart @@ -80,6 +80,7 @@ class Relays { } String request = getUserRequest(subscriptionId, publicKey, limit, sinceWhen); + //print("In relay: getKind events: request = $request"); sendRequest(relayUrl, request); } @@ -100,29 +101,12 @@ class Relays { * @connect Connect to given relay and get all events for multiple users/publicKey and insert the * received events in the given List */ - void getMultiUserEvents(String relayUrl, List publicKeys, int limit, int sinceWhen) { - - Set reqKeys = {}; - if( relays.containsKey(relayUrl)) { - List? users = relays[relayUrl]?.users; - if( users != null) { - // following is too restrictive. TODO improve it - for(int i = 0; i < publicKeys.length; i++) { - if( users.any( (u) => u == publicKeys[i])) { - continue; - } - if( gBots.any( (bot) => bot == publicKeys[i] )) { - continue; - } - users.add(publicKeys[i]); - reqKeys.add(publicKeys[i]); - } - } - } // if relay exists and has a user list + void getMultiUserEvents(String relayUrl, List publicKeys, int limit, int sinceWhen, [Set? kind = null]) { + //print("In relays: getmulti events kind = $kind len ${publicKeys.length}"); String subscriptionId = "multiple_user" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6); - String request = getMultiUserRequest( subscriptionId, reqKeys, limit, sinceWhen); + String request = getMultiUserRequest( subscriptionId, publicKeys.toSet(), limit, sinceWhen, kind); sendRequest(relayUrl, request); } @@ -233,7 +217,7 @@ void getContactFeed(Set relayUrls, Set setContacts, int numEvent groupContacts.add(contacts[i + j]); } - //print( "i = $i upperLimit = $upperLimit") ; + //print( "in getcontact feed . i = $i upperLimit = $upperLimit") ; relayUrls.forEach((relayUrl) { relays.getMultiUserEvents(relayUrl, groupContacts, numEventsToGet, sinceWhen); }); @@ -262,7 +246,8 @@ getKindEvents(List kind, Set serverUrls, int limit, int sinceWhen) }); } -void getMultiUserEvents(Set serverUrls, List publicKeys, int numUserEvents, int sinceWhen) { +void getMultiUserEvents(Set serverUrls, Set setPublicKeys, int numUserEvents, int sinceWhen, [Set? kind]) { + List publicKeys = setPublicKeys.toList(); if( gDebug > 0) print("Sending multi user request for ${publicKeys.length} users"); for(var serverUrl in serverUrls) { @@ -271,9 +256,9 @@ void getMultiUserEvents(Set serverUrls, List publicKeys, int num if( publicKeys.length - i <= gMaxAuthorsInOneRequest) { getUserRequests = publicKeys.length - i; } - //print(" sending request form $i to ${i + getUserRequests} "); + //print("In getMultiuserevents: sending request form $i to ${i + getUserRequests} "); List partialList = publicKeys.sublist(i, i + getUserRequests); - relays.getMultiUserEvents(serverUrl, partialList, numUserEvents, sinceWhen); + relays.getMultiUserEvents(serverUrl, partialList, numUserEvents, sinceWhen, kind); } } } diff --git a/lib/settings.dart b/lib/settings.dart index 94dcfa3..0b7470a 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -13,7 +13,8 @@ final log = Logger('ExampleLogger'); // for debugging String gCheckEventId = "x98821b082a1d322e8cba84e8d430da300dea043348f422229f929059d1a9bb05"; -int gDefaultNumWaitSeconds = 8000; // is used in main() + +int gMaxEventLenthAccepted = 80000; // max event size. events larger than this are rejected. //////////////////////////////////////////////////////////////////////////////////////////////////////////////// encrypted Group settings const int gSecretMessageKind = 104; @@ -39,11 +40,12 @@ const int gLimitPerSubscription = 10000; // applicable only for notifications and not for search results. Search results set a flag in EventData and don't use this variable const int gDontHighlightEventsOlderThan = 4; -const int gMaxAuthorsInOneRequest = 100; // number of author requests to send in one request -const int gMaxPtagsToGet = 150; // maximum number of p tags that are taken from the comments of feed ( the top most, most frequent) +int gDefaultNumWaitSeconds = 12000; // is used in main() +const int gMaxAuthorsInOneRequest = 200; // number of author requests to send in one request +const int gMaxPtagsToGet = 200; // 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; +int numFileEvents = 0, numFilePosts = 0, numUserPosts = 0, numFeedPosts = 0, numOtherPosts = 0; //String defaultServerUrl = 'wss://relay.damus.io'; //const String nostrRelayUnther = 'wss://nostr-relay.untethr.me'; not working @@ -52,12 +54,15 @@ String defaultServerUrl = "wss://relay.damus.io"; Set gListRelayUrls1 = { defaultServerUrl, relayNostrInfo, - "wss://nostr-relay.wlvs.space" + "wss://nostr.semisol.dev", + "wss://nostr-2.zebedee.cloud", + "wss://nostr.onsats.org" + }; Set gListRelayUrls2 = { "wss://nostr.oxtr.dev", - "wss://nostr.ono.re" + "wss://nostr.bitcoiner.social" }; // well known disposable test private key @@ -66,9 +71,36 @@ String userPrivateKey = ""; String userPublicKey = gDefaultPublicKey; // default follows; taken from nostr.io/stats -List gDefaultFollows = [ +Set gDefaultFollows = { + // 21 dec 2022 + "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2", // Jack Dorsey + "c4eabae1be3cf657bc1855ee05e69de9f059cb7a059227168b80b89761cbc4e0", // Mallers + "a341f45ff9758f570a21b000c17d4e53a3a497c8397f26c0e6d61e5acffc7a98", // Saylor + //"703e26b4f8bc0fa57f99d815dbb75b086012acc24fc557befa310f5aa08d1898", // Adam Back not sure + "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9", // ODELL + "e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411", // NVK + "85080d3bad70ccdcd7f74c29a44f55bb85cbcd3dd0cbb957da1d215bdb931204", // Preston + "83e818dfbeccea56b0f551576b3fd39a7a50e1d8159343500368fa085ccd964b", // Jeff Booth + "f728d9e6e7048358e70930f5ca64b097770d989ccd86854fe618eda9c8a38106", // Lopp + "bf2376e17ba4ec269d10fcc996a4746b451152be9031fa48e74553dde5526bce", // CARLA + "e33fe65f1fde44c6dc17eeb38fdad0fceaf1cae8722084332ed1e32496291d42", // wiz + "472f440f29ef996e92a186b8d320ff180c855903882e59d50de1b8bd5669301e", // MartyBent + "1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", // yegorPetrov + "be1d89794bf92de5dd64c1e60f6a2c70c140abac9932418fee30c5c637fe9479", // walletofsatoshi + "eaf27aa104833bcd16f671488b01d65f6da30163b5848aea99677cc947dd00aa", // grubles + "b9003833fabff271d0782e030be61b7ec38ce7d45a1b9a869fbdb34b9e2d2000", // brockm + "51b826cccd92569a6582e20982fd883fccfa78ad03e0241f7abec1830d7a2565", // Jonas Schnelli + "92de68b21302fa2137b1cbba7259b8ba967b535a05c6d2b0847d9f35ff3cf56a", // Susie bdds + "c48e29f04b482cc01ca1f9ef8c86ef8318c059e0e9353235162f080f26e14c11", // walker + "a9b9525992a486aa16b3c1d3f9d3604bca08f3c15b712d70711b9aecd8c3dc44", // Alana + + "24e37c1e5b0c8ba8dde2754bcffc63b5b299f8064f8fb928bcf315b9c4965f3b", // lunaticoin + "4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0", // martii malmi + "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322", // hodlbod + + // pre dec 2022 "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681", //damus - "6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964", // dergigi + "6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964", // dergigi "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245", // jb55 "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", // fiatjaf "2ef93f01cd2493e04235a6b87b10d3c4a74e2a7eb7c3caf168268f6af73314b5", // unclebobmarting @@ -89,7 +121,8 @@ List gDefaultFollows = [ "f43c1f9bff677b8f27b602725ea0ad51af221344f69a6b352a74991a4479bac3", // manfromhighcastle "80482e60178c2ce996da6d67577f56a2b2c47ccb1c84c81f2b7960637cb71b78", // Leo "42a0825e980b9f97943d2501d99c3a3859d4e68cd6028c02afe58f96ba661a9d", // zerosequioso - "3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c"]; // vishalxl ]; + + "3235036bd0957dfb27ccda02d452d7c763be40c91a1ac082ba6983b25238388c"}; // vishalxl ]; // dummy account pubkey @@ -368,6 +401,12 @@ lines.forEach((line) {print(line.length > terminalColumns ? line.substring(0, te } +void printInfoForNewUser() { + print("""\nFor new users: The app only gets kind 1 events from people you follow or some popular well known pubkeys. + If you see a message such as 'event not loaded' it implies its from someone you don't follow. Such events + are eventually loaded; however, the ideal way to use this app is to follow people whose posts you want to read or follow.\n"""); +} + /////////////////////////////////////////////////////////other settings related functions void printUsage() { diff --git a/lib/tree_ds.dart b/lib/tree_ds.dart index f9e4692..8405dc6 100644 --- a/lib/tree_ds.dart +++ b/lib/tree_ds.dart @@ -1948,7 +1948,7 @@ class Store { for( var tree in allChildEventsMap.values) { if( tree.event.eventData.isDeleted) { // dont write those deleted - //continue; + continue; } if( gOverWriteFile == false) { @@ -1958,19 +1958,24 @@ class Store { } if( gDummyAccountPubkey == tree.event.eventData.pubkey) { - print("not writing dummy event pubkey"); continue; // dont write dummy events } - String line = "${tree.event.originalJson}\n"; + if( tree.event.originalJson.length < 10) { + continue; + } + + String temp = tree.event.originalJson.trim(); + String line = "${temp}\n"; nLinesStr += line; eventCounter++; if( tree.event.eventData.kind == 1) { countPosts++; } - + //if( temp.length < 10) print('len < 10'); if( eventCounter % numLinesTogether == 0) { await file.writeAsString(nLinesStr, mode: FileMode.append).then( (file) => file); + //print("nLineStr len = ${nLinesStr.length}"); nLinesStr = ""; linesWritten += numLinesTogether; } diff --git a/lib/utils.dart b/lib/utils.dart index 3f11bd9..ee174e1 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -331,7 +331,32 @@ String getJsonList(Set publicKeys) { return s; } +String getCommaSeparatedInts(Set? kind) { + if( kind == null) { + return ""; + } + + if( kind.length == 0) { + return ""; + } + + String strKind = ""; + int i = 0; + + kind.forEach((k) { + String comma = ","; + if( i == kind.length-1) { + comma = ""; + } + strKind = strKind + k.toString() + comma; + i++; + }); + + return strKind; +} + String getKindRequest(String subscriptionId, List kind, int limit, int sinceWhen) { + //print("in getkindrequest: kind = $kind"); String strTime = ""; if( sinceWhen != 0) { strTime = ', "since":${sinceWhen.toString()}'; @@ -339,27 +364,35 @@ String getKindRequest(String subscriptionId, List kind, int limit, int sinc var strSubscription1 = '["REQ","$subscriptionId",{"kinds":['; var strSubscription2 ='], "limit":$limit$strTime } ]'; - String strKind = ""; - for(int i = 0; i < kind.length; i++) { - String comma = ","; - if( i == kind.length-1) { - comma = ""; - } - strKind = strKind + kind[i].toString() + comma; - } + String strKind = getCommaSeparatedInts(kind.toSet()); + String strRequest = strSubscription1 + strKind + strSubscription2; - //print(strRequest); + //print("returning $strRequest"); return strRequest; } -String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen) { +String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen, [Set? _kind = null]) { + Set kind = {}; + if( _kind != null) { + kind = _kind; + } + + String strKind = getCommaSeparatedInts(kind); + + String strKindSection = ""; + if( strKind.length > 0) { + strKindSection = '"kinds":[$strKind],'; + } + String strTime = ""; if( sinceWhen != 0) { strTime = ', "since": ${sinceWhen.toString()}'; } var strSubscription1 = '["REQ","$subscriptionId",{ "authors": ["'; - var strSubscription2 ='"], "limit": $numUserEvents $strTime } ]'; - return strSubscription1 + publicKey.toLowerCase() + strSubscription2; + var strSubscription2 ='"],$strKindSection"limit": $numUserEvents $strTime } ]'; + String request = strSubscription1 + publicKey.toLowerCase() + strSubscription2; + //print("In getUserRequest: $request"); + return request; } String getMentionRequest(String subscriptionId, Set ids, int numUserEvents, int sinceWhen, String tagToGet) { @@ -372,27 +405,36 @@ String getMentionRequest(String subscriptionId, Set ids, int numUserEven return strSubscription1 + getJsonList(ids) + strSubscription2; } -String getMultiUserRequest(String subscriptionId, Set publicKeys, int numUserEvents, int sinceWhen) { +String getMultiUserRequest(String subscriptionId, Set publicKeys, int numUserEvents, int sinceWhen, [Set? kind = null]) { String strTime = ""; if( sinceWhen != 0) { strTime = ', "since": ${sinceWhen.toString()}'; } + String strKind = getCommaSeparatedInts(kind); + + String strKindSection = ""; + if( strKind.length > 0) { + strKindSection = '"kinds":[$strKind],'; + } + var strSubscription1 = '["REQ","$subscriptionId",{ "authors": ['; - var strSubscription2 ='], "limit": $numUserEvents $strTime } ]'; + var strSubscription2 ='],$strKindSection"limit": $numUserEvents $strTime } ]'; String s = ""; s = getJsonList(publicKeys); - return strSubscription1 + s + strSubscription2; + String request = strSubscription1 + s + strSubscription2; + //print("In getMultiUserRequest kind = $kind strKindSection = $strKindSection: request = $request"); + return request; } // ends with a newline -void printSet( Set toPrint, [ String prefix = ""]) { +void printSet( Set toPrint, [ String prefix = "", String separator = ""]) { stdout.write(prefix); int i = 0; toPrint.forEach((element) { if( i != 0) { - stdout.write(", "); + stdout.write(separator); } stdout.write(element); @@ -400,3 +442,4 @@ void printSet( Set toPrint, [ String prefix = ""]) { }); stdout.write("\n"); } +