added support for kind 40/42 messages, and displayed if any chat room are there. Messages not displayed yet

This commit is contained in:
vishalxl 2022-08-24 03:36:08 +05:30
parent 1fa49b8251
commit dff3ff70b0
4 changed files with 124 additions and 27 deletions

View File

@ -56,7 +56,8 @@ Future<void> otherMenuUi(Tree node, var contactList) async {
'Change number of days printed', // 2
'Show a user profile', // 3
'Show tweets containg word', // 4
'Go back to main menu'], // 5
'Chat rooms', // 5
'Go back to main menu'], // 6
"Other Menu");
print('You picked: $option');
switch(option) {
@ -132,6 +133,10 @@ Future<void> otherMenuUi(Tree node, var contactList) async {
break;
case 5:
node.showChatRooms();
break;
case 6:
continueOtherMenu = false;
break;

View File

@ -34,10 +34,6 @@ const String notificationColor = "\x1b[36m"; // cyan
const String warningColor = "\x1B[31m"; // red
const String colorEndMarker = "\x1B[0m";
// translate flag
const int gNumTranslateDays = 4;
bool gTranslate = false;
//String defaultServerUrl = 'wss://relay.damus.io';
String defaultServerUrl = 'wss://nostr-relay.untethr.me';
@ -60,6 +56,9 @@ Map< String, List<List<String>> > gReactions = {};
// is updated as kind 3 events are received
Map< String, List<Contact>> gContactLists = {};
// chat rooms , mappint from chat room kind 40 event to its information as list where even = key, odd = value
Map<String, List<String>> gChatRooms = {};
// bots ignored to reduce spam
List<String> gBots = [ "3b57518d02e6acfd5eb7198530b2e351e5a52278fb2499d14b66db2b5791c512", // robosats orderbook
"887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072", // bestofhn
@ -70,11 +69,9 @@ List<String> gBots = [ "3b57518d02e6acfd5eb7198530b2e351e5a52278fb2499d14b66db2
//const String gDefaultEventsFilename = "events_store_nostr.txt";
String gEventsFilename = ""; // is set in arguments, and if set, then file is read from and written to
// translate for this number of days
const int gTranslateForDays = 2;
final translator = GoogleTranslator();
const int gNumTranslateDays = 4;// translate for this number of days
bool gTranslate = false; // translate flag
int gDebug = 0;
@ -221,7 +218,7 @@ class EventData {
contactList.add(c);
}
} else {
if ( json['kind'] == 1 || json['kind'] == 7) {
if ( json['kind'] == 1 || json['kind'] == 7 || json['kind'] == 42 ) {
for( int i = 0; i < numTags; i++) {
var tag = jsonTags[i];
//stdout.write(tag);
@ -307,7 +304,7 @@ class EventData {
//final input = "Здравствуйте. Ты в порядке?";
// Using the Future API
if( DateTime.fromMillisecondsSinceEpoch(createdAt *1000).compareTo( DateTime.now().subtract(Duration(days:gTranslateForDays)) ) > 0 ) {
if( DateTime.fromMillisecondsSinceEpoch(createdAt *1000).compareTo( DateTime.now().subtract(Duration(days:gNumTranslateDays)) ) > 0 ) {
if( gDebug > 0) print("Sending google request: translating $content");
try {
translator
@ -322,6 +319,19 @@ class EventData {
}
}
// only applicable for kind 42 event
String getChatRoomId() {
if( kind != 42) {
return "";
}
for(int i = 0; i < tags.length; i++) {
if( tags[i][0] == "#e") {
return tags[i][1];
}
}
return "";
}
// prints event data in the format that allows it to be shown in tree form by the Tree class
void printEventData(int depth) {
int n = 3;
@ -434,6 +444,19 @@ class Event {
}
}
class ChatRoom {
String chatRoomId; // id of the kind 40 start event
String name;
String about;
String picture;
List<String> messageIds; // all the 42 kind events in this
ChatRoom(this.chatRoomId, this.name, this.about, this.picture, this.messageIds);
void insertMessage(String msg) {
messageIds.add(msg);
}
}
List<String> getpTags(List<Event> events) {
List<String> pTags = [];
for(int i = 0; i < events.length; i++) {
@ -492,6 +515,7 @@ List<Event> readEventsFromFile(String filename) {
return events;
}
// From the list of events provided, lookup the lastst contact information for the given user/pubkey
Event? getContactEvent(List<Event> events, String pubkey) {
// get the latest kind 3 event for the user, which lists his 'follows' list

View File

@ -1,4 +1,5 @@
import 'dart:io';
import 'dart:convert';
import 'package:nostr_console/event_ds.dart';
@ -15,23 +16,25 @@ class Tree {
Map<String, Tree> allChildEventsMap;
List<String> eventsWithoutParent;
bool whetherTopMost;
Tree(this.e, this.children, this.allChildEventsMap, this.eventsWithoutParent, this.whetherTopMost);
Map<String, ChatRoom> chatRooms = {};
Tree(this.e, this.children, this.allChildEventsMap, this.eventsWithoutParent, this.whetherTopMost, this.chatRooms);
static const List<int> typesInEventMap = [0, 1, 3, 7]; // 0 meta, 1 post, 3 follows list, 7 reactions
static const List<int> typesInEventMap = [0, 1, 3, 7, 40, 42]; // 0 meta, 1 post, 3 follows list, 7 reactions
// @method create top level Tree from events.
// first create a map. then process each element in the map by adding it to its parent ( if its a child tree)
factory Tree.fromEvents(List<Event> events) {
if( events.isEmpty) {
return Tree(Event("","",EventData("non","", 0, 0, "", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], false);
return Tree(Event("","",EventData("non","", 0, 0, "", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], false, {});
}
// create a map from list of events, key is eventId and value is event itself
Map<String, Tree> allChildEventsMap = {};
events.forEach((event) {
// only add in map those kinds that are supported or supposed to be added ( 0 1 3 7)
// 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}" );
if( typesInEventMap.contains(event.eventData.kind)) {
allChildEventsMap[event.eventData.id] = Tree(event, [], {}, [], false);
allChildEventsMap[event.eventData.id] = Tree(event, [], {}, [], false, {});
}
});
@ -39,10 +42,49 @@ class Tree {
List<Tree> topLevelTrees = [];
List<String> tempWithoutParent = [];
allChildEventsMap.forEach((key, value) {
Map<String, ChatRoom> rooms = {};
// only posts areadded to this tree structure
if( value.e.eventData.kind != 1) {
allChildEventsMap.forEach((key, value) {
String eId = value.e.eventData.id;
int eKind = value.e.eventData.kind;
if(eKind == 42) {
String chatRoomId = value.e.eventData.getChatRoomId();
if( chatRoomId != "") {
if( rooms.containsKey(chatRoomId)) {
rooms[chatRoomId]?.insertMessage(eId);
if( gDebug > 0) print("Added new message to a chat room $chatRoomId. ");
} else {
List<String> temp = [];
temp.add(eId);
ChatRoom room = ChatRoom(chatRoomId, "", "", "", temp);
rooms[chatRoomId] = room;
if( gDebug > 0) print("Added new chat room object $chatRoomId and added message to it. ");
}
} else {
if( gDebug > 0) print("Could not get chat room id for event $eId, its original json: ");
if( gDebug > 0) print(value.e.originalJson);
}
}
if(eKind == 40) {
String chatRoomId = eId;
if( rooms.containsKey(chatRoomId)) {
if( rooms[chatRoomId]?.name == "") {
dynamic json = jsonDecode(value.e.eventData.content);
if( gDebug > 0) print('Added room name = ${json['name']} for $chatRoomId' );
rooms[chatRoomId]?.name = json['name'];
}
} else {
List<String> temp = [];
temp.add(eId);
ChatRoom room = ChatRoom(chatRoomId, "", "", "", temp);
rooms[chatRoomId] = room;
if( gDebug > 0) print("Added new chat room $chatRoomId.");
}
}
// only posts, of kind 1, are added to the main tree structure
if( eKind != 1) {
return;
}
@ -64,7 +106,10 @@ class Tree {
} else {
// in case where the parent of the new event is not in the pool of all events,
// then we create a dummy event and put it at top ( or make this a top event?) TODO handle so that this can be replied to, and is fetched
Tree dummyTopNode = Tree(Event("","",EventData("Unk" ,gDummyAccountPubkey, value.e.eventData.createdAt , 1, "Unknown parent event", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], false);
Tree dummyTopNode = Tree(Event("","",
EventData("Unk" ,gDummyAccountPubkey, value.e.eventData.createdAt , 1, "Unknown parent event", [], [], [], [[]], {}),
[""], "[json]"),
[], {}, [], false, {});
dummyTopNode.addChildNode(value);
tempWithoutParent.add(value.e.eventData.id);
@ -82,10 +127,12 @@ class Tree {
}
}
if( gDebug != 0) print("at end of tree from events: Total number of chat rooms: ${rooms.length}");
if(gDebug != 0) print("number of events without parent in fromEvents = ${tempWithoutParent.length}");
// create a dummy top level tree and then create the main Tree object
Event dummy = Event("","", EventData("non","", 0, 1, "Dummy Top event. Should not be printed.", [], [], [], [[]], {}), [""], "[json]");
return Tree( dummy, topLevelTrees, allChildEventsMap, tempWithoutParent, true); // TODO remove events[0]
return Tree( dummy, topLevelTrees, allChildEventsMap, tempWithoutParent, true, rooms);
} // end fromEvents()
/*
@ -125,7 +172,7 @@ class Tree {
newEvent.eventData.translateAndExpandMentions();
if( gDebug > 0) print("In insertEvents: adding event to main children map");
allChildEventsMap[newEvent.eventData.id] = Tree(newEvent, [], {}, [], false);
allChildEventsMap[newEvent.eventData.id] = Tree(newEvent, [], {}, [], false, {});
newEventsId.add(newEvent.eventData.id);
});
@ -317,6 +364,27 @@ class Tree {
print("\n");
}
void showChatRooms() {
print("\n\nChat Rooms:");
printChatRoomInfo();
}
void printChatRoomInfo() {
chatRooms.forEach((key, value) {
String name = "";
if( value.name == "") {
name = value.chatRoomId;
} else {
name = value.name;
}
int numMessages = value.messageIds.length;
print("-----------$name---------");
print("Total number of messages: $numMessages");
print("\n\n");
});
}
// Write the tree's events to file as one event's json per line
Future<void> writeEventsToFile(String filename) async {
//print("opening $filename to write to");
@ -420,7 +488,7 @@ class Tree {
void addChild(Event child) {
Tree node;
node = Tree(child, [], {}, [], false);
node = Tree(child, [], {}, [], false, {});
children.add(node);
}
@ -622,7 +690,7 @@ void processReactions(List<Event> events) {
Tree getTree(List<Event> events) {
if( events.isEmpty) {
print("Warning: In printEventsAsTree: events length = 0");
return Tree(Event("","",EventData("non","", 0, 0, "", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], true);
return Tree(Event("","",EventData("non","", 0, 0, "", [], [], [], [[]], {}), [""], "[json]"), [], {}, [], true, {});
}
// populate the global with display names which can be later used by Event print
@ -631,7 +699,7 @@ Tree getTree(List<Event> events) {
// process NIP 25, or event reactions by adding them to a global map
processReactions(events);
// remove all events other than kind 0, 1, 3 and 7
// remove all events other than kind 0, 1, 3, 7 and 40 (chat rooms)
events.removeWhere( (item) => !Tree.typesInEventMap.contains(item.eventData.kind));
// remove bot events

View File

@ -9,8 +9,8 @@ EventData exampleEdataChild = EventData("id2", "pubkey", 1111111, 1, "content ch
Event exampleEvent = Event('event', 'id3', exampleEdata, ['relay name'], "[json]");
Event exampleEventChild = Event('event', 'id4', exampleEdataChild, ['relay name'], "[json]");
Tree exampleNode = Tree(exampleEvent, [], {}, [], false);
Tree exampleNodeChild = Tree(exampleEventChild, [], {}, [], false);
Tree exampleNode = Tree(exampleEvent, [], {}, [], false, {});
Tree exampleNodeChild = Tree(exampleEventChild, [], {}, [], false, {});
void main() {
test('PrintEmptyEvent', () {