From 6515958cd800acdffc7e23a644d5ab14f3696668 Mon Sep 17 00:00:00 2001 From: vishalxl <> Date: Fri, 26 Aug 2022 12:41:30 +0530 Subject: [PATCH] fixed json decode issue. added more profile info including distance. added search by client --- bin/nostr_console.dart | 24 ++++--- lib/console_ui.dart | 26 ++++++- lib/event_ds.dart | 3 +- lib/relays.dart | 7 +- lib/tree_ds.dart | 152 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 183 insertions(+), 29 deletions(-) diff --git a/bin/nostr_console.dart b/bin/nostr_console.dart index 591bf20..495e0c5 100644 --- a/bin/nostr_console.dart +++ b/bin/nostr_console.dart @@ -132,20 +132,23 @@ Future main(List arguments) async { //stdout.write("Got argument request: ${argResults[requestArg]}"); stdout.write('Sending request and waiting for events...'); - sendRequest(defaultServerUrl, argResults[requestArg]); + sendRequest(gListRelayUrls, argResults[requestArg]); Future.delayed(const Duration(milliseconds: 6000), () { List receivedEvents = getRecievedEvents(); - stdout.write("received ${receivedEvents.length - numFileEvents} events from $defaultServerUrl\n"); + stdout.write("received ${receivedEvents.length - numFileEvents} events\n"); // remove bots receivedEvents.removeWhere((e) => gBots.contains(e.eventData.pubkey)); // create tree - Tree node = getTree(getRecievedEvents()); - clearEvents(); // cause we have consumed them above - + Future node = getTree(getRecievedEvents()); + //clearEvents(); // cause we have consumed them above + node.then((value) { + clearEvents(); + mainMenuUi(value, []); + }); // call main menu - mainMenuUi(node, []); + }); return; } @@ -216,11 +219,14 @@ Future main(List arguments) async { stdout.write("received $numOtherEvents other posts\n"); // get all events in Tree form - Tree node = getTree(getRecievedEvents()); - clearEvents(); + Future node = getTree(getRecievedEvents()); // call the mein UI function - mainMenuUi(node, contactList); + node.then((value) { + clearEvents(); + mainMenuUi(value, contactList); + }); + }); }); }); diff --git a/lib/console_ui.dart b/lib/console_ui.dart index f041105..1832d69 100644 --- a/lib/console_ui.dart +++ b/lib/console_ui.dart @@ -120,7 +120,8 @@ Future otherMenuUi(Tree node, var contactList) async { 'Rebroadcast an event', // 6 'Applicatoin stats', // 7 'Help and About', // 8 - 'Go back to main menu'], // 9 + 'Go back to main menu', // 9 + 'Search by client'], "Other Menu"); // menu name print('You picked: $option'); switch(option) { @@ -237,9 +238,19 @@ Future otherMenuUi(Tree node, var contactList) async { // if contact list was found, get user's feed, and keep the contact list for later use String authorName = getAuthorName(pubkey.first); List contactList = []; - print("\nShowing the profile page for ${pubkey.first} ($authorName), whose contact list has ${ (contactEvent?.eventData.contactList.length)??0} profiles.\n "); + print("\nShowing the profile page for ${pubkey.first} ($authorName).\n"); if (contactEvent != null ) { + print("The account follows ${contactEvent.eventData.contactList.length} accounts:"); + contactEvent.eventData.contactList.forEach((x) => stdout.write("${getAuthorName(x.id)}, ")); + List followers = node.getFollowers(pubkey.first); + + print("\n\nThe account has ${followers.length} followers: "); + + followers.forEach((x) => stdout.write("${getAuthorName(x)}, ")); + + // print social distance info. + node.printSocialDistance(pubkey.first, authorName); } print(""); } @@ -255,6 +266,7 @@ Future otherMenuUi(Tree node, var contactList) async { node.printTree(0, DateTime.now().subtract(Duration(days:gNumLastDays)), onlyWords); // search for last gNumLastDays only } break; + case 6: print("TBD"); break; @@ -286,6 +298,16 @@ Future otherMenuUi(Tree node, var contactList) async { continueOtherMenu = false; break; + case 10: + stdout.write("Enter client name whose events you want to see: "); + String? $tempWords = stdin.readLineSync(); + String clientName = $tempWords??""; + if( clientName != "") { + bool fromClient (Tree t) => t.fromClientSelector(clientName); + node.printTree(0, DateTime.now().subtract(Duration(days:gNumLastDays)), fromClient); // search for last gNumLastDays only + } + break; + default: break; } diff --git a/lib/event_ds.dart b/lib/event_ds.dart index f54d62a..79a9e21 100644 --- a/lib/event_ds.dart +++ b/lib/event_ds.dart @@ -301,7 +301,7 @@ class EventData { int n = 4; String maxN(String v) => v.length > n? v.substring(0,n) : v.substring(0, v.length); void printInColor(String s, String commentColor) => stdout.supportsAnsiEscapes ?stdout.write("$commentColor$s$colorEndMarker"):stdout.write(s); - + DateTime dTime = DateTime.fromMillisecondsSinceEpoch(createdAt *1000); // TODO do it in one call @@ -592,3 +592,4 @@ Set getPublicKeyFromName(String userName) { return pubkeys; } + diff --git a/lib/relays.dart b/lib/relays.dart index 967cab0..f808acc 100644 --- a/lib/relays.dart +++ b/lib/relays.dart @@ -263,8 +263,10 @@ void getMultiUserEvents(serverUrl, List publicKeys, numUserEvents) { } } -void sendRequest(serverUrl, request) { - relays.sendRequest(serverUrl, request); +void sendRequest(List serverUrls, request) { + for(int i = 0; i < serverUrls.length; i++) { + relays.sendRequest(serverUrls[i], request); + } } List getRecievedEvents() { @@ -273,6 +275,7 @@ List getRecievedEvents() { void clearEvents() { relays.rEvents = []; + if( gDebug > 0) print("clearEvents(): returning"); } void setRelaysIntialEvents(eventsFromFile) { diff --git a/lib/tree_ds.dart b/lib/tree_ds.dart index a00c137..079ff00 100644 --- a/lib/tree_ds.dart +++ b/lib/tree_ds.dart @@ -34,6 +34,7 @@ class Tree { events.forEach((event) { // only add in map those kinds that are supported or supposed to be added ( 0 1 3 7 40) //if( event.eventData.kind == 40 || event.eventData.kind == 42) if( gDebug > 0) print("in from Events: got a kind 40/42 event of id ${event.eventData.id} and kind ${event.eventData.kind}" ); + //event.printEvent(0); if( typesInEventMap.contains(event.eventData.kind)) { tempChildEventsMap[event.eventData.id] = Tree(event, [], {}, [], false, {}); } @@ -45,6 +46,8 @@ class Tree { List tempWithoutParent = []; Map rooms = {}; + if( gDebug > 0) print("In from Events: size of tempChildEventsMap = ${tempChildEventsMap.length} "); + tempChildEventsMap.forEach((key, value) { String eId = value.e.eventData.id; int eKind = value.e.eventData.kind; @@ -71,20 +74,42 @@ class Tree { } if(eKind == 40) { + //print("Processing type 40"); String chatRoomId = eId; - dynamic json = jsonDecode(value.e.eventData.content); + try { + //print("Processing type 40 json"); + dynamic json = jsonDecode(value.e.eventData.content); + //print("Processed type 40 json"); - if( rooms.containsKey(chatRoomId)) { - if( rooms[chatRoomId]?.name == "") { - if( gDebug > 0) print('Added room name = ${json['name']} for $chatRoomId' ); - rooms[chatRoomId]?.name = json['name']; + if( rooms.containsKey(chatRoomId)) { + //print("in if chatRoomId key in rooms"); + if( rooms[chatRoomId]?.name == "") { + if( gDebug > 0) print('Added room name = ${json['name']} for $chatRoomId' ); + rooms[chatRoomId]?.name = json['name']; + } + } else { + List temp = []; + //temp.add(eId); + //print("in else"); + //print("json = $json"); + + String roomName = "", roomAbout = ""; + + if( json.containsKey('name') ) { + roomName = json['name']; + } + + if( json.containsKey('about')) { + roomAbout = json['about']; + } + + ChatRoom room = ChatRoom(chatRoomId, roomName, roomAbout, "", []); + rooms[chatRoomId] = room; + if( gDebug > 0) print("Added new chat room $chatRoomId with name ${json['name']} ."); } - } else { - List temp = []; - //temp.add(eId); - ChatRoom room = ChatRoom(chatRoomId, json['name'], json['about'], "", []); - rooms[chatRoomId] = room; - if( gDebug > 0) print("Added new chat room $chatRoomId with name ${json['name']} ."); + + } on Exception catch(e) { + if( gDebug > 0) print("In From Event. Event type 40. Json Decode error for event id ${value.e.eventData.id}"); } } @@ -671,14 +696,13 @@ class Tree { return true; } for( int i = 0; i < children.length; i++ ) { - if( children[i].hasUserPost(pubkey)) { + if( children[i].hasUserPostAndLike(pubkey)) { return true; } } return false; } - // returns true if the given words exists in it or its children bool hasWords(String word) { //if(gDebug > 0) print("In tree selector hasWords: this id = ${e.eventData.id} word = $word"); @@ -689,6 +713,7 @@ class Tree { if( e.eventData.content.toLowerCase().contains(word)) { return true; } + for( int i = 0; i < children.length; i++ ) { //if(gDebug > 0) print("this id = ${e.eventData.id} word = $word i = $i "); @@ -697,13 +722,38 @@ class Tree { continue; } - if( children[i].e.eventData.content.toLowerCase().contains(word)) { + if( children[i].hasWords(word)) { return true; } } return false; } + // returns true if the event or any of its children were made from the given client, and they are marked for notification + bool fromClientSelector(String clientName) { + //if(gDebug > 0) print("In tree selector hasWords: this id = ${e.eventData.id} word = $word"); + + List> tags = e.eventData.tags; + for( int i = 0; i < tags.length; i++) { + if( tags[i].length < 2) { + continue; + } + + if( tags[i][0] == "client" && tags[i][1].contains(clientName)) { + e.eventData.isNotification = true; + return true; + } + } + + for( int i = 0; i < children.length; i++ ) { + if( children[i].fromClientSelector(clientName)) { + return true; + } + } + return false; + } + + Event? getContactEvent(String pkey) { // get the latest kind 3 event for the user, which lists his 'follows' list @@ -729,6 +779,77 @@ class Tree { return null; } + //void create + + List getFollowers(String pubkey) { + if( gDebug > 0) print("Finding followrs for $pubkey"); + List followers = []; + + Set usersWithContactList = {}; + allChildEventsMap.forEach((key, value) { + if( value.e.eventData.kind == 3) { + usersWithContactList.add(value.e.eventData.pubkey); + } + }); + + usersWithContactList.forEach((x) { + Event? contactEvent = getContactEvent(x); + + if( contactEvent != null) { + List contacts = contactEvent.eventData.contactList; + for(int i = 0; i < contacts.length; i ++) { + if( contacts[i].id == pubkey) { + followers.add(x); + return; + } + } + } + }); + + return followers; + } + + void printSocialDistance(String otherPubkey, String otherName) { + String otherName = getAuthorName(otherPubkey); + + List contactList = []; + Event? contactEvent = this.getContactEvent(userPublicKey); + bool isFollow = false; + int numSecond = 0; // number of your follows who follow the other + + int numContacts = 0; + if( contactEvent != null) { + List contacts = contactEvent.eventData.contactList; + numContacts = contacts.length; + for(int i = 0; i < contacts.length; i ++) { + // check if you follow the other account + if( contacts[i].id == otherPubkey) { + isFollow = true; + } + // count the number of your contacts who know or follow the other account + List followContactList = []; + Event? followContactEvent = this.getContactEvent(contacts[i].id); + if( followContactEvent != null) { + followContactList = followContactEvent.eventData.contactList; + for(int j = 0; j < followContactList.length; j++) { + if( followContactList[j].id == otherPubkey) { + numSecond++; + break; + } + } + } + }// end for loop through users contacts + print("\n\n"); + if( isFollow) { + print("* You follow $otherName "); + } + + print("* Of the $numContacts people you follow, $numSecond follow $otherName"); + + } // end if contact event was found +} + + } // end Tree void addMessageToChannel(String channelId, String messageId, var tempChildEventsMap, var chatRooms) { @@ -829,10 +950,11 @@ void processReactions(List events) { return; } + /* * @function getTree Creates a Tree out of these received List of events. */ -Tree getTree(List events) { +Future getTree(List events) async { if( events.isEmpty) { print("Warning: In printEventsAsTree: events length = 0"); return Tree(Event("","",EventData("non","", 0, 0, "", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], true, {});