added analysis_options.yaml and ran lint and applied changes

This commit is contained in:
Vishal 2024-03-31 17:14:01 +05:30
parent 626a2f66c5
commit b9ac5538b3
11 changed files with 436 additions and 352 deletions

26
analysis_options.yaml Normal file
View File

@ -0,0 +1,26 @@
# reference : https://dart.dev/tools/analysis
include: package:lints/recommended.yaml
analyzer:
exclude: [build/**]
language:
strict-raw-types: true
strict-inference: true
# not including
# strict-casts: true
linter:
rules:
- use_super_parameters
- cancel_subscriptions
- close_sinks
- combinators_ordering
- comment_references
- invalid_case_patterns
- library_annotations
- one_member_abstracts
- only_throw_errors

View File

@ -92,7 +92,7 @@ Future<void> main(List<String> arguments) async {
userPrivateKey = "";
}
if( gUserLocation.length > 0){
if( gUserLocation.isNotEmpty){
print("Going to add $gUserLocation as the location tag with each post.");
}
@ -118,7 +118,7 @@ Future<void> main(List<String> arguments) async {
// write informative message in case user is not using proper keys
if( userPublicKey == gDefaultPublicKey) {
print("You should ideally create your own private key and use it with ${gWarningColor}--prikey$gColorEndMarker program argument. ");
print("You should ideally create your own private key and use it with $gWarningColor--prikey$gColorEndMarker program argument. ");
print("Create a private key from ${gWarningColor}astral.ninja, @damusapp, or even from command line using `openssl rand -hex 32`.$gColorEndMarker.\n");
print("npub/nsec keys can be converted to hex key format using https://damus.io/key");
}
@ -127,16 +127,16 @@ Future<void> main(List<String> arguments) async {
if( argResults[relayArg] != null) {
Set<String> userRelayList = Set.from(argResults[relayArg].split(","));
Set<String> parsedRelays = {};
userRelayList.forEach((relay) {
for (var relay in userRelayList) {
if(relay.startsWith(RegExp(r'^ws[s]?:\/\/'))) {
parsedRelays.add(relay);
} else {
printWarning("The provided relay entry: \"$relay\" does not start with ws:// or wss://, omitting");
}
});
}
// verify that there is at least one valid relay they provided, otherwise keep defaults
if (parsedRelays.length > 0) {
if (parsedRelays.isNotEmpty) {
gListRelayUrls = parsedRelays;
defaultServerUrl = gListRelayUrls.first;
} else {
@ -174,8 +174,9 @@ Future<void> main(List<String> arguments) async {
try {
var terminalColumns = gDefaultTextWidth;
if( stdout.hasTerminal )
if( stdout.hasTerminal ) {
terminalColumns = stdout.terminalColumns;
}
// can be computed only after textWidth has been found
if( gTextWidth > terminalColumns) {
@ -184,7 +185,7 @@ Future<void> main(List<String> arguments) async {
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
} on StdoutException catch (e) {
print("Cannot find terminal size. Left aligning by default.");
if( gDebug > 0) log.info("${e.message}");
if( gDebug > 0) log.info(e.message);
gNumLeftMarginSpaces = 0;
}
// undo above if left option is given
@ -262,10 +263,10 @@ Future<void> main(List<String> arguments) async {
stdout.write('Reading events from ${whetherDefault}file.......');
// read file events and give the events to relays from where they're picked up later
initialEvents = await readEventsFromFile(gEventsFilename);
initialEvents = readEventsFromFile(gEventsFilename);
// count events
initialEvents.forEach((element) { numFileEvents++;});
for (var element in initialEvents) { numFileEvents++;}
print("read $numFileEvents events from file $gEventsFilename");
}
@ -338,7 +339,7 @@ Future<void> main(List<String> arguments) async {
clearEvents();
initialEvents.forEach((element) { element.eventData.kind == 1? numUserPosts++: numUserPosts;});
for (var element in initialEvents) { element.eventData.kind == 1? numUserPosts++: numUserPosts;}
numUserPosts -= numFilePosts;
stdout.write("...done\n");//received $numUserPosts new posts made by the user\n");
@ -353,7 +354,9 @@ Future<void> main(List<String> arguments) async {
getKindEvents([40, 41], gListRelayUrls, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents));
getKindEvents([42], gListRelayUrls, 3 * limitPerSubscription, getSecondsDaysAgo(limitOthersEvents));
initialEvents.forEach((e) => processKind3Event(e)); // first process the kind 3 event ; basically populate the global structure that holds this info
for (var e in initialEvents) {
processKind3Event(e);
} // first process the kind 3 event ; basically populate the global structure that holds this info
Set<String> contacts = {};
Set<String> pTags = {};
@ -365,9 +368,9 @@ Future<void> main(List<String> arguments) async {
// if contact list was found, get user's feed; also get some default contacts
if (contactEvent != null ) {
if(gDebug > 0) print("In main: found contact list: \n ${contactEvent.originalJson}");
contactEvent.eventData.contactList.forEach((contact) {
for (var contact in contactEvent.eventData.contactList) {
contacts.add(contact.contactPubkey);
});
}
} else {
print("Could not find your contact list.");
}

View File

@ -93,7 +93,7 @@ Future<void> sendReplyPostLike(Store node, String replyToId, String replyKind, S
int numShaDone = 0;
for( numShaDone = 0; numShaDone < 100000000; numShaDone++) {
vanityTag = strTags + ',["nonce","$numShaDone","$gDifficulty"]';
vanityTag = '$strTags,["nonce","$numShaDone","$gDifficulty"]';
id = getShaId(userPublicKey, createdAt.toString(), replyKind, vanityTag, content);
if( id.substring(0, numBytes) == zeroString) {
break;
@ -160,7 +160,7 @@ Future<void> sendChannelReply(Store node, Channel channel, String replyTo, Strin
// send DM
Future<void> sendDirectMessage(Store node, String otherPubkey, String messageToSend, {String replyKind = "4"}) async {
//messageToSend = addEscapeChars(messageToSend); since this get encrypted , it does not need escaping
String otherPubkey02 = "02" + otherPubkey;
String otherPubkey02 = "02$otherPubkey";
String encryptedMessageToSend = myEncrypt(userPrivateKey, otherPubkey02, messageToSend);
//print("in sendDirectMessage: replyKind = $replyKind");
@ -271,7 +271,7 @@ bool sendDeleteEvent(Store node, String eventIdToDelete) {
} else {
print("Event not found. Kindly ensure you have entered a valid event id.");
}
};
}
return false;
}
@ -282,8 +282,9 @@ void reAdjustAlignment() {
try {
var terminalColumns = gDefaultTextWidth;
if( stdout.hasTerminal )
if( stdout.hasTerminal ) {
terminalColumns = stdout.terminalColumns;
}
if( gTextWidth > terminalColumns) {
gTextWidth = terminalColumns - 5;
@ -291,7 +292,7 @@ void reAdjustAlignment() {
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
} on StdoutException catch (e) {
print("Terminal information not available");
if( gDebug>0) print("${e.message}");
if( gDebug>0) print(e.message);
gNumLeftMarginSpaces = 0;
}
}
@ -317,7 +318,7 @@ void printProfile(Store node, String profilePubkey) {
String picture = gKindONames[profilePubkey]?.picture??"";
String lud06 = gKindONames[profilePubkey]?.lud06??"";
String lud16 = gKindONames[profilePubkey]?.lud16??"";
String display_name= gKindONames[profilePubkey]?.display_name??"";
String displayName= gKindONames[profilePubkey]?.display_name??"";
String website = gKindONames[profilePubkey]?.website??"";
int dateLastUpdated = gKindONames[profilePubkey]?.createdAt??0;
bool verified = gKindONames[profilePubkey]?.nip05Verified??false;
@ -334,7 +335,7 @@ void printProfile(Store node, String profilePubkey) {
// print LNRUL lud06 if it exists
if( lud06.length > gMinLud06AddressLength) {
try {
String lud06LNString = "lightning:" + lud06;
String lud06LNString = "lightning:$lud06";
List<int>? typesAndModule = getTypeAndModule(lud06LNString);
if( typesAndModule != null) {
@ -349,7 +350,7 @@ void printProfile(Store node, String profilePubkey) {
// print LNRUL lud16 if it exists
if( lud16.length > gMinLud16AddressLength) {
try {
String lud16LNString = "" + lud16;
String lud16LNString = lud16;
List<int>? typesAndModule = getTypeAndModule(lud16LNString);
if( typesAndModule != null) {
print("Printing lud16 address as QR:\n\n");
@ -360,14 +361,14 @@ void printProfile(Store node, String profilePubkey) {
}
}
print("\nName : $authorName ( ${profilePubkey} ).");
print("\nName : $authorName ( $profilePubkey ).");
print("About : $about");
print("Picture : $picture");
print("display_name: $display_name");
print("display_name: $displayName");
print("Website : $website");
print("Lud06 : $lud06");
print("Lud16 : $lud16");
print("Nip 05 : ${verified?"yes. ${nip05Id}":"no"}");
print("Nip 05 : ${verified?"yes. $nip05Id":"no"}");
print("\nLast Updated: ${getPrintableDate(dateLastUpdated)}\n");
// get the latest kind 3 event for the user, which lists his 'follows' list
@ -389,7 +390,9 @@ void printProfile(Store node, String profilePubkey) {
// print follow list
stdout.write("$pronoun follow ${profileContactEvent.eventData.contactList.length} accounts: ");
profileContactEvent.eventData.contactList.sort();
profileContactEvent.eventData.contactList.forEach((x) => stdout.write("${getAuthorName(x.contactPubkey)}, "));
for (var x in profileContactEvent.eventData.contactList) {
stdout.write("${getAuthorName(x.contactPubkey)}, ");
}
print("\n");
}
@ -397,7 +400,9 @@ void printProfile(Store node, String profilePubkey) {
List<String> followers = node.getFollowers(profilePubkey);
stdout.write("$pronoun have ${followers.length} followers: ");
followers.sort((a, b) => getAuthorName(a).compareTo(getAuthorName(b)));
followers.forEach((x) => stdout.write("${getAuthorName(x)}, "));
for (var x in followers) {
stdout.write("${getAuthorName(x)}, ");
}
print("");
print("");
}
@ -436,11 +441,13 @@ void printMenu(List<String> menuOptions) {
var terminalColumns = gDefaultTextWidth;
if( stdout.hasTerminal )
if( stdout.hasTerminal ) {
terminalColumns = stdout.terminalColumns;
}
if( longestMenuOption + 5> gMenuWidth )
if( longestMenuOption + 5> gMenuWidth ) {
gMenuWidth = longestMenuOption + 8;
}
if( terminalColumns~/gMenuWidth > 4) {
terminalColumns = gMenuWidth * 4;
@ -463,7 +470,7 @@ void printMenu(List<String> menuOptions) {
int showMenu(List<String> menuOptions, String menuName, [String menuInfo = ""]) {
if(menuInfo.length > 0) {
if(menuInfo.isNotEmpty) {
print("\n$menuInfo\n");
}
@ -531,13 +538,15 @@ Do you want to proceed. Press y/Y or n/N: """, "n");
void printPubkeys(Set<String> pubkey) {
print("${myPadRight("pubkey",64)} ${myPadRight("name", 20)} ${myPadRight("about", 40)} ${myPadRight("Nip05", 30)}");
pubkey.forEach( (x) => print("$x ${myPadRight(getAuthorName(x), 20)} ${myPadRight(gKindONames[x]?.about??"", 40)} ${myPadRight(gKindONames[x]?.nip05Id??"No", 30)}"));
for (var x in pubkey) {
print("$x ${myPadRight(getAuthorName(x), 20)} ${myPadRight(gKindONames[x]?.about??"", 40)} ${myPadRight(gKindONames[x]?.nip05Id??"No", 30)}");
}
print("");
}
void printPubkeyResult(Set<String> pubkey) {
if( pubkey.length == 0) {
if( pubkey.isEmpty) {
print("There is no pubkey for that given name.");
return;
} else {
@ -599,18 +608,18 @@ Future<void> otherOptionsMenuUi(Store node) async {
String userName = getStringFromUser("Enter your new name : ", getAuthorName(userPublicKey));
String userAbout = getStringFromUser("Enter new 'about me' for yourself : ", gKindONames[userPublicKey]?.about??"");
String userPic = getStringFromUser("Enter url to your new display picture: ", gKindONames[userPublicKey]?.picture??"https://placekitten.com/200/200");
String display_name = getStringFromUser("Enter your new display name : ", gKindONames[userPublicKey]?.display_name??"");
String displayName = getStringFromUser("Enter your new display name : ", gKindONames[userPublicKey]?.display_name??"");
String website = getStringFromUser("Enter your new website : ", gKindONames[userPublicKey]?.website??"");
String nip05id = getStringFromUser("Enter your nip 05 id. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.nip05Id??"");
String lud06 = getStringFromUser("Enter your lud06 or lnurl. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.lud06??"");
String lud16 = getStringFromUser("Enter your lud16 address. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.lud16??"");
String strLud06 = lud06.length > 0? '"lud06":"$lud06",': '';
String strLud16 = lud16.length > 0? '"lud16":"$lud16",': '';
String strDispName = display_name.length > 0? '"display_name":"$display_name",': '';
String strWebsite = website.length > 0? '"website":"$website",': '';
String strLud06 = lud06.isNotEmpty? '"lud06":"$lud06",': '';
String strLud16 = lud16.isNotEmpty? '"lud16":"$lud16",': '';
String strDispName = displayName.isNotEmpty? '"display_name":"$displayName",': '';
String strWebsite = website.isNotEmpty? '"website":"$website",': '';
String content = "{\"name\": \"$userName\", \"about\": \"$userAbout\", \"picture\": \"$userPic\"${ nip05id.length >0 ? ", $strDispName $strWebsite $strLud06 $strLud16 \"nip05\": \"$nip05id\"":""}}";
String content = "{\"name\": \"$userName\", \"about\": \"$userAbout\", \"picture\": \"$userPic\"${ nip05id.isNotEmpty ? ", $strDispName $strWebsite $strLud06 $strLud16 \"nip05\": \"$nip05id\"":""}}";
int createdAt = DateTime.now().millisecondsSinceEpoch ~/1000;
EventData eventData = EventData('id', userPublicKey, createdAt, 0, content, [], [], [], [], {}, );
@ -633,11 +642,11 @@ Future<void> otherOptionsMenuUi(Store node) async {
if( eventIdToDelete.length == 1) {
String toDeleteId = eventIdToDelete.first;
print("Going to send a delete event for the following event with id ${toDeleteId}");
print("Going to send a delete event for the following event with id $toDeleteId");
sendDeleteEvent(node, eventIdToDelete.first);
await processAnyIncomingEvents(node, false); // get latest event, this takes 300 ms
} else {
if( eventIdToDelete.length == 0) {
if( eventIdToDelete.isEmpty) {
printWarning("Could not find the given event id. Kindly try again, by entering a 64 byte long hex event id, or by entering a unique prefix for the given event id.");
} else {
printWarning("Invalid Event Id(s). Kindly enter a more unique id.");
@ -802,8 +811,9 @@ Future<void> channelMenuUI(Store node) async {
Channel? channel = node.getChannelFromId(node.channels, fullChannelId);
String actualMessage = messageToSend.substring(7);
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length)
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length) {
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
}
if( channel != null) {
await sendChannelReply(node, channel, replyTo, actualMessage, getPostKindFrom( channel.roomType));
@ -945,7 +955,7 @@ String encryptChannelMessage(Store node, String channelId, String messageToSend)
}
String priKey = keys[0], pubKey = keys[1];
encryptedMessage = myEncrypt(priKey, "02" + pubKey, messageToSend);
encryptedMessage = myEncrypt(priKey, "02$pubKey", messageToSend);
return encryptedMessage;
}
@ -983,9 +993,9 @@ Future<void> addUsersToEncryptedChannel(Store node, String fullChannelId, Set<St
String content = channelEvent.eventData.content;
String tags = '["e","$fullChannelId"]';
participants.forEach((participant) {
tags += ',["p","${participant}"]';
});
for (var participant in participants) {
tags += ',["p","$participant"]';
}
int numNewUsers = participants.length;
@ -1142,8 +1152,9 @@ Future<void> encryptedChannelMenuUI(Store node) async {
String replyTo = tokens[1];
String actualMessage = messageToSend.substring(7);
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length)
if( messageToSend.indexOf(tokens[1]) + tokens[1].length < messageToSend.length) {
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
}
String encryptedMessageToSend = encryptChannelMessage(node, fullChannelId, actualMessage);
if( encryptedMessageToSend != "") {
@ -1439,7 +1450,9 @@ Future<void> socialMenuUi(Store node) async {
if( numPrinted[0] == 0) {
print("\nNot found in the last $gHoursDefaultPrint hours. Try increasing the number of days printed, from social network options to search further back into history.\n");
}
} else printWarning("Blank word entered. Try again.");
} else {
printWarning("Blank word entered. Try again.");
}
break;
@ -1542,7 +1555,7 @@ Future<void> socialMenuUi(Store node) async {
stdout.write("Printing profile of a user; type username or first few letters of user's public key( or full public key): ");
String? $tempUserName = stdin.readLineSync();
String userName = $tempUserName??"";
stdout.write( "user name: " + userName);
stdout.write( "user name: $userName");
if( userName != "") {
Set<String> pubkey = getPublicKeyFromName(userName);
@ -1578,7 +1591,7 @@ Future<void> socialMenuUi(Store node) async {
continue;
} on Exception catch (e) {
printWarning("Invalid input. Kindly try again.");
if( gDebug > 0) print(" ${e}");
if( gDebug > 0) print(" $e");
continue;
}
break;
@ -1600,8 +1613,9 @@ void directRoomNotifications(Store node, [int x = 0, int y = 0]) {
bool showNotifications (ScrollableMessages room) => room.selectorNotifications();
int numDirectRoomsPrinted = node.printDirectRoomsOverview( showNotifications, 100, node.allChildEventsMap);
if( numDirectRoomsPrinted > 0)
print("\n");
if( numDirectRoomsPrinted > 0) {
print("\n");
}
int totalNotifications = numPrinted[2] + numDirectRoomsPrinted;
if( totalNotifications > 0) {
@ -1691,7 +1705,7 @@ Future<void> mainMenuUi(Store node) async {
mainMenuContinue = false;
String authorName = getAuthorName(userPublicKey);
clearScreen();
print("\nFinished Nostr session for user: ${authorName} ($userPublicKey)");
print("\nFinished Nostr session for user: $authorName ($userPublicKey)");
if( gEventsFilename != "") {
await node.writeEventsToFile(gEventsFilename);
}

View File

@ -38,7 +38,7 @@ class UserNameInfo {
Event ?latestContactEvent;
bool nip05Verified;
String? nip05Id;
UserNameInfo(this.createdAt, this.name, this.about, this.picture, this.lud06, this.lud16, this.display_name, this.website, this.nip05Id , this.latestContactEvent, [this.createdAtKind3 = null, this.nip05Verified = false]);
UserNameInfo(this.createdAt, this.name, this.about, this.picture, this.lud06, this.lud16, this.display_name, this.website, this.nip05Id , this.latestContactEvent, [this.createdAtKind3, this.nip05Verified = false]);
}
/*
@ -59,7 +59,7 @@ Set<String> getReactorPubkeys(String eventId) {
List<List<String>>? reactions = gReactions[eventId];
if( reactions != null) {
reactions.forEach((reaction) { reactorIds.add(reaction[0]);});
for (var reaction in reactions) { reactorIds.add(reaction[0]);}
}
return reactorIds;
@ -157,22 +157,22 @@ class EventData {
}
// then depending on the numbers and values ( of root and replyto) return the parent
if( replyId.length > 0) {
if( replyId.isNotEmpty) {
if( numReply == 1) {
return replyId;
} else {
// if there are multiply reply's we can't tell which is which, so we return the one at top
if( replyId.length > 0) {
if( replyId.isNotEmpty) {
return replyId;
} else {
// this is case when there is no reply id . should not actually happen given if conditions
if( rootId.length > 0) {
if( rootId.isNotEmpty) {
return rootId;
}
}
}
} else {
if( rootId.length > 0) {
if( rootId.isNotEmpty) {
//printWarning("returning root id. no reply id found.");
return rootId;
}
@ -209,7 +209,7 @@ class EventData {
}
List<String>? getTTags() {
List<String>? tTags = null;
List<String>? tTags;
for( int i = 0; i < tags.length; i++) {
List<String> tag = tags[i];
@ -217,9 +217,7 @@ class EventData {
continue;
}
if( tag[0] == 't') {
if( tTags == null ) {
tTags = [];
}
tTags ??= [];
tTags.add(tag[1]);
}
@ -268,7 +266,7 @@ class EventData {
try {
verifyEvent(json);
} on Exception catch(e) {
} on Exception {
//printWarning("verify gave exception $e");
throw Exception("in Event constructor: sig verify gave exception");
}
@ -364,7 +362,7 @@ class EventData {
String author = getAuthorName(mentionedId);
return "@$author";
} else {
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData??null;
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData;
if( eventData != null) {
String quotedAuthor = getAuthorName(eventData.pubkey);
String prefixId = mentionedId.substring(0, 3);
@ -401,7 +399,7 @@ class EventData {
}
// replace the mentions, if any are found
String mentionStr = "(\#\[[0-9]+\])";
String mentionStr = "(#[[0-9]+])";
RegExp mentionRegExp = RegExp(mentionStr);
content = content.replaceAllMapped(mentionRegExp, replaceMentions);
return content;
@ -468,7 +466,7 @@ class EventData {
return null;
}
if(!isValidDirectMessage(this, acceptableKind: this.kind)) {
if(!isValidDirectMessage(this, acceptableKind: kind)) {
return null;
}
@ -577,19 +575,19 @@ class EventData {
int ivIndex = content.indexOf("?iv=");
if( ivIndex > 0) {
var iv = content.substring( ivIndex + 4, content.length);
var enc_str = content.substring(0, ivIndex);
var encStr = content.substring(0, ivIndex);
String userKey = userPrivateKey ;
String otherUserPubKey = "02" + pubkey;
String otherUserPubKey = "02$pubkey";
if( pubkey == userPublicKey) { // if user themselve is the sender change public key used to decrypt
userKey = userPrivateKey;
int numPtags = 0;
tags.forEach((tag) {
for (var tag in tags) {
if(tag[0] == "p" ) {
otherUserPubKey = "02" + tag[1];
otherUserPubKey = "02${tag[1]}";
numPtags++;
}
});
}
// if there are more than one p tags, we don't know who its for
if( numPtags != 1) {
if( gDebug >= 0) printInColor(" in translateAndExpand: got event $id with number of p tags != one : $numPtags . not decrypting", redColor);
@ -597,7 +595,7 @@ class EventData {
}
}
var decrypted = myPrivateDecrypt( userKey, otherUserPubKey, enc_str, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
var decrypted = myPrivateDecrypt( userKey, otherUserPubKey, encStr, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
return decrypted;
} else {
if(gDebug > 0) print("Invalid content for dm, could not get ivIndex: $content");
@ -629,7 +627,7 @@ class EventData {
return null;
}
var iv = content.substring( ivIndex + 4, content.length);
var enc_str = content.substring(0, ivIndex);
var encStr = content.substring(0, ivIndex);
String channelId = getChannelIdForKind4x();
List<String> keys = [];
@ -642,9 +640,9 @@ class EventData {
}
String priKey = keys[0];
String pubKey = "02" + keys[1];
String pubKey = "02${keys[1]}";
var decrypted = myPrivateDecrypt( priKey, pubKey, enc_str, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
var decrypted = myPrivateDecrypt( priKey, pubKey, encStr, iv); // use bob's privatekey and alic's publickey means bob can read message from alic
return decrypted;
}
@ -657,7 +655,7 @@ class EventData {
// get first e tag, which should be the channel of which this is part of
for( int i = 0; i < eTags.length; i++) {
List tag = eTags[i];
if( tag.length >= 1) {
if( tag.isNotEmpty) {
return tag[0];
}
}
@ -665,7 +663,7 @@ class EventData {
}
String getChannelIdForTTagRoom(String tagValue) {
return tagValue + " #t";
return "$tagValue #t";
}
// only applicable for kind 42/142 event; returns the channel 40/140 id of which the event is part of
@ -687,9 +685,9 @@ class EventData {
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
if( tempChildEventsMap != null )
if(kind == 4)
if(kind == 4) {
translateAndDecryptKind4( tempChildEventsMap);
else if ([1, 42].contains(kind)) {
} else if ([1, 42].contains(kind)) {
translateAndExpandMentions(tempChildEventsMap);
} else if ([142].contains(kind)) {
if( secretMessageIds != null && encryptedChannels != null) {
@ -752,7 +750,7 @@ class EventData {
strToPrint += "";
}
strToPrint += "${name}: ";
strToPrint += "$name: ";
const int typicalxLen = "|id: 82b5 , 12:04 AM Sep 19".length + 5; // not sure where 5 comes from
List<dynamic> reactionString = getReactionStr(depth);
//print("\n|${reactionString[0]}|\n ${ reactionString[1]}\n }");
@ -781,8 +779,9 @@ class EventData {
// effective len of last line is used to calcluate where the idDateLikes str is affixed at the end
int effectiveLastLineLen = lastLineLen - gSpacesPerDepth * depth - effectiveNameFieldLen - gNumLeftMarginSpaces;
if( contentShifted.length <= maxLineLen )
if( contentShifted.length <= maxLineLen ) {
effectiveLastLineLen = contentShifted.length;
}
// needed to use this because the color padding in notifications reactions will mess up the length calculation in the actual reaction string
int colorStrLen = reactionString[0].length - reactionString[1];
@ -791,20 +790,20 @@ class EventData {
if( (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen + idDateLikes.length ) <= gTextWidth) {
idDateLikes = idDateLikes.padLeft((gTextWidth ) + colorStrLen - (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen));
} else {
idDateLikes = "\n" + idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen);
idDateLikes = "\n${idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen)}";
}
// print content and the dateslikes string
strToPrint += getStrInColor(contentShifted + idDateLikes + "\n", commentColor);
strToPrint += getStrInColor("$contentShifted$idDateLikes\n", commentColor);
stdout.write(strToPrint);
}
String getAsLine(var tempChildEventsMap, Set<String>? secretMessageIds, List<Channel>? encryptedChannels, {int len = 20}) {
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
if(kind == 4)
if(kind == 4) {
translateAndDecryptKind4( tempChildEventsMap);
else if ([1, 42].contains(kind)) {
} else if ([1, 42].contains(kind)) {
translateAndExpandMentions(tempChildEventsMap);
} else if ([142].contains(kind)) {
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
@ -839,12 +838,12 @@ class EventData {
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
if(kind == 4)
if(kind == 4) {
translateAndDecryptKind4( tempChildEventsMap);
else if ([1, 42].contains(kind)) {
} else if ([1, 42].contains(kind)) {
translateAndExpandMentions(tempChildEventsMap);
} else if ([142].contains(kind)) {
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
if( secretMessageIds != null && encryptedChannels != null) {
//print('decrypting 14x in getStrForChannel');
translateAndDecrypt14x(secretMessageIds, encryptedChannels, tempChildEventsMap);
}
@ -867,8 +866,9 @@ class EventData {
tempEvaluatedContent = tempContent = content; // content would be changed so show that
}
if( tempEvaluatedContent=="")
if( tempEvaluatedContent=="") {
tempEvaluatedContent = tempContent;
}
const int nameWidthDepth = 16~/gSpacesPerDepth; // how wide name will be in depth spaces
const int timeWidthDepth = 18~/gSpacesPerDepth;
@ -900,13 +900,13 @@ class EventData {
if( replyToEvent.eventData.evaluatedContent.length <= gReplyLengthPrinted){
replyToPrint = replyToEvent.eventData.evaluatedContent;
} else {
replyToPrint = replyToEvent.eventData.evaluatedContent.substring(0, gReplyLengthPrinted) + "...";
replyToPrint = "${replyToEvent.eventData.evaluatedContent.substring(0, gReplyLengthPrinted)}...";
}
strReplyTo = 'In reply to:"${getAuthorName(replyToEvent.eventData.pubkey)}: $replyToPrint"';
strReplyTo = makeParagraphAtDepth(strReplyTo, finalContentDepthInSpaces + 6); // one extra for content
// add reply to string to end of the content. How it will show:
contentShifted += ( "\n" + getNumSpaces( contentPlacementColumn + gSpacesPerDepth) + strReplyTo);
contentShifted += ( "\n${getNumSpaces( contentPlacementColumn + gSpacesPerDepth)}$strReplyTo");
}
}
} else {
@ -916,10 +916,10 @@ class EventData {
String msgId = id.substring(0, 3).padLeft(gSpacesPerDepth~/2).padRight(gSpacesPerDepth) ;
if( isNotification) {
strToPrint = "$gNotificationColor${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $gNotificationColor" + contentShifted + gColorEndMarker;
strToPrint = "$gNotificationColor${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $gNotificationColor$contentShifted$gColorEndMarker";
isNotification = false;
} else {
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: " + contentShifted;
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $contentShifted";
}
return strToPrint;
}
@ -956,8 +956,9 @@ class EventData {
firstEntry = false;
} else {
// this is normal printing of the reaction. only print for + for now
if( reactors[i][1] == "+")
if( reactors[i][1] == "+") {
authorName = getAuthorName(reactorId);
}
reactorNames += comma + authorName;
len += (2 + authorName.length);
firstEntry = false;
@ -979,14 +980,14 @@ class EventData {
// returns the last e tag as reply to event for kind 42 and 142 events
Event? getReplyToChannelEvent(Map<String, Tree> tempChildEventsMap) {
switch (this.kind) {
switch (kind) {
case 42:
case 142:
for(int i = tags.length - 1; i >= 0; i--) {
List tag = tags[i];
if( tag[0] == 'e') {
String replyToEventId = tag[1];
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event)??null;
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event);
if( eventInReplyTo != null) {
// add 1 cause 42 can reply to or tag kind 1, and we'll show that kind 1
if ( [1,42,142].contains( eventInReplyTo.eventData.kind)) {
@ -1039,14 +1040,15 @@ class Event {
}
EventData newEventData = EventData.fromJson(json[2]);
if( !fromFile)
if( !fromFile) {
newEventData.isNotification = true;
}
return Event(json[0] as String, json[1] as String, newEventData, [relay], d, fromFile );
} on Exception catch(e) {
if( gDebug > 0) {
print("Could not create event. $e\nproblem str: $d\n");
}
throw e;
rethrow;
}
}
@ -1115,7 +1117,7 @@ bool processKind0Event(Event e) {
String picture = "";
String lud06 = "";
String lud16 = "";
String display_name = "";
String displayName = "";
String website = "";
String nip05 = "";
@ -1126,7 +1128,7 @@ bool processKind0Event(Event e) {
picture = json["picture"]??"";
lud06 = json["lud06"]??"";
lud16 = json["lud16"]??"";
display_name = json["display_name"]??"";
displayName = json["display_name"]??"";
website = json["website"]??"";
nip05 = json['nip05']??"";
//String twitterId = json['twitter']??"";
@ -1137,12 +1139,12 @@ bool processKind0Event(Event e) {
bool newEntry = false, entryModified = false;
if( !gKindONames.containsKey(e.eventData.pubkey)) {
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website, nip05, null);
newEntry = true;;
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website, nip05, null);
newEntry = true;
} else {
int oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
if( oldTime < e.eventData.createdAt) {
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website, nip05, null);
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website, nip05, null);
entryModified = true;
}
}
@ -1154,13 +1156,13 @@ bool processKind0Event(Event e) {
bool localDebug = false; //e.eventData.pubkey == "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"? true: false;
if( newEntry || entryModified) {
if(nip05.length > 0) {
if(nip05.isNotEmpty) {
List<String> urlSplit = nip05.split("@");
if( urlSplit.length == 2) {
String urlNip05 = urlSplit[1] + "/.well-known/nostr.json?name=" + urlSplit[0];
String urlNip05 = "${urlSplit[1]}/.well-known/nostr.json?name=${urlSplit[0]}";
if( !urlNip05.startsWith("http")) {
urlNip05 = "http://"+ urlNip05;
urlNip05 = "http://$urlNip05";
}
fetchNip05Info(urlNip05)
@ -1178,7 +1180,7 @@ bool processKind0Event(Event e) {
int oldTime = 0;
if( !gKindONames.containsKey(e.eventData.pubkey)) {
//printWarning("in response handing. creating user info");
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, display_name, website,null, null);
gKindONames[e.eventData.pubkey] = UserNameInfo(e.eventData.createdAt, name, about, picture, lud06, lud16, displayName, website,null, null);
} else {
oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
//print("in response handing. user info exists with old time = $oldTime and this event time = ${e.eventData.createdAt}");
@ -1215,23 +1217,23 @@ bool processKind3Event(Event newContactEvent) {
bool newEntry = false, entryModified = false;
if( !gKindONames.containsKey(newContactEvent.eventData.pubkey)) {
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(null, null, null, null, null, null, null, null, null, newContactEvent, newContactEvent.eventData.createdAt);
newEntry = true;;
newEntry = true;
} else {
// if entry already exists, then check its old time and update only if we have a newer entry now
int oldTime = gKindONames[newContactEvent.eventData.pubkey]?.createdAtKind3??0;
if( oldTime < newContactEvent.eventData.createdAt) {
int? createdAt = gKindONames[newContactEvent.eventData.pubkey]?.createdAt??null;
int? createdAt = gKindONames[newContactEvent.eventData.pubkey]?.createdAt;
String? name = gKindONames[newContactEvent.eventData.pubkey]?.name,
about = gKindONames[newContactEvent.eventData.pubkey]?.about,
picture = gKindONames[newContactEvent.eventData.pubkey]?.picture,
lud06 = gKindONames[newContactEvent.eventData.pubkey]?.lud06,
lud16 = gKindONames[newContactEvent.eventData.pubkey]?.lud16,
display_name = gKindONames[newContactEvent.eventData.pubkey]?.display_name,
displayName = gKindONames[newContactEvent.eventData.pubkey]?.display_name,
website = gKindONames[newContactEvent.eventData.pubkey]?.website,
nip05id = gKindONames[newContactEvent.eventData.pubkey]?.nip05Id??"";
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(createdAt, name, about, picture, lud06, lud16, display_name, website, nip05id, newContactEvent, newContactEvent.eventData.createdAt );
entryModified = true;;
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(createdAt, name, about, picture, lud06, lud16, displayName, website, nip05id, newContactEvent, newContactEvent.eventData.createdAt );
entryModified = true;
}
}
@ -1260,16 +1262,16 @@ String getNip05Name( String pubkey) {
// returns name by looking up global list gKindONames, which is populated by kind 0 events
String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkeyLenShown = 5}) {
if( gFollowList.length == 0) {
if( gFollowList.isEmpty) {
gFollowList = getFollows(userPublicKey);
}
bool isFollow = gFollowList.contains(pubkey) && (pubkey != userPublicKey);
String maxLen(String pubkey) => pubkey.length > pubkeyLenShown? pubkey.substring(0,pubkeyLenShown) : pubkey.substring(0, pubkey.length);
String name = "";
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0)
name = maxLen(pubkey);
else {
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0) {
name = maxLen(pubkey);
} else {
name = (gKindONames[pubkey]?.name)??maxLen(pubkey);
}
@ -1291,7 +1293,7 @@ String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkey
// returns full public key(s) for the given username( which can be first few letters of pubkey, or the user name)
Set<String> getPublicKeyFromName(String inquiredName) {
if( inquiredName.length < 1) {
if( inquiredName.isEmpty) {
return {};
}
Set<String> pubkeys = {};
@ -1337,8 +1339,9 @@ void printDepth(int d) {
void printCenteredHeadline(displayName) {
int numDashes = 10; // num of dashes on each side
int startText = gNumLeftMarginSpaces + ( gTextWidth - (displayName.length + 2 * numDashes)) ~/ 2;
if( startText < 0)
if( startText < 0) {
startText = 0;
}
String str = getNumSpaces(startText) + getNumDashes(numDashes) + displayName + getNumDashes(numDashes);
print(str);
@ -1369,7 +1372,7 @@ String makeParagraphAtDepth(String s, int depthInSpaces) {
String line = listCulledLine[0];
int lenReturned = listCulledLine[1] as int;
if( line.length == 0 || lenReturned == 0) break;
if( line.isEmpty || lenReturned == 0) break;
newString += line;
startIndex += lenReturned;
@ -1381,8 +1384,9 @@ String makeParagraphAtDepth(String s, int depthInSpaces) {
// returns from string[startIndex:] the first len number of chars. no newline is added.
List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesString, List<List<int>> urlRanges) {
if( startIndex >= s.length)
if( startIndex >= s.length) {
return ["", 0];
}
String line = ""; // is returned
@ -1420,7 +1424,9 @@ List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesSt
int i = line.length - 1;
// find a whitespace character
for( ; i > 0 && !isWordSeparater(line[i]); i--);
for( ; i > 0 && !isWordSeparater(line[i]); i--) {
{}
}
// for ended
if( line.length - i < gMaxLenUnbrokenWord) {
@ -1428,9 +1434,10 @@ List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesSt
// break the line here if its a word separator
if( isWordSeparater(line[i])) {
int newLineStart = i + 1;
if( line[i] != ' ')
if( line[i] != ' ') {
newLineStart = i;
line = line.substring(0, i) + "\n" + spacesString + line.substring(newLineStart, line.length);
}
line = "${line.substring(0, i)}\n$spacesString${line.substring(newLineStart, line.length)}";
lineBroken = true;
}
}
@ -1494,16 +1501,16 @@ bool isValidDirectMessage(EventData directMessageData, {int acceptableKind = 4})
bool validUserMessage = false;
List<String> allPtags = [];
directMessageData.tags.forEach((tag) {
for (var tag in directMessageData.tags) {
if( tag.length < 2 ) {
return;
continue;
}
if( tag[0] == "p" && tag[1].length == 64) { // basic length sanity test
allPtags.add(tag[1]);
}
});
}
if(gDebug >= 0 && gCheckEventId == directMessageData.id) print("In isvalid direct message: ptags len: ${allPtags.length}, ptags = ${allPtags}");
if(gDebug >= 0 && gCheckEventId == directMessageData.id) print("In isvalid direct message: ptags len: ${allPtags.length}, ptags = $allPtags");
if( directMessageData.pubkey == userPublicKey && allPtags.length == 1) {
if( allPtags[0].substring(0, 32) != "0".padLeft(32, '0')) { // check that the message hasn't been sent to an invalid pubkey
@ -1524,16 +1531,16 @@ bool isValidDirectMessage(EventData directMessageData, {int acceptableKind = 4})
String getRandomPrivKey() {
FortunaRandom fr = FortunaRandom();
final _sGen = Random.secure();;
final sGen = Random.secure();
fr.seed(KeyParameter(
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
BigInt randomNumber = fr.nextBigInteger(256);
String strKey = randomNumber.toRadixString(16);
if( strKey.length < 64) {
int numZeros = 64 - strKey.length;
for(int i = 0; i < numZeros; i++) {
strKey = "0" + strKey;
strKey = "0$strKey";
}
}
return strKey;
@ -1568,7 +1575,7 @@ Uint8List myPrivateDecryptRaw( String privateString,
}
if( byteSecret.isEmpty) {
byteSecret = Kepler.byteSecret(privateString, publicString);;
byteSecret = Kepler.byteSecret(privateString, publicString);
gMapByteSecret[publicString] = byteSecret;
}
@ -1578,11 +1585,11 @@ Uint8List myPrivateDecryptRaw( String privateString,
? convert.base64.decode(b64IV)
: Uint8List.fromList(secretIV[1]);
CipherParameters params = new PaddedBlockCipherParameters(
new ParametersWithIV(new KeyParameter(key), iv), null);
CipherParameters params = PaddedBlockCipherParameters(
ParametersWithIV(KeyParameter(key), iv), null);
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
PKCS7Padding(), CBCBlockCipher(AESEngine()));
cipherImpl.init(false,
params as PaddedBlockCipherParameters<CipherParameters?,
@ -1620,16 +1627,16 @@ String myEncryptRaw( String privateString,
// generate iv https://stackoverflow.com/questions/63630661/aes-engine-not-initialised-with-pointycastle-securerandom
FortunaRandom fr = FortunaRandom();
final _sGen = Random.secure();;
final sGen = Random.secure();
fr.seed(KeyParameter(
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
final iv = fr.nextBytes(16);
CipherParameters params = new PaddedBlockCipherParameters(
new ParametersWithIV(new KeyParameter(key), iv), null);
CipherParameters params = PaddedBlockCipherParameters(
ParametersWithIV(KeyParameter(key), iv), null);
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
PKCS7Padding(), CBCBlockCipher(AESEngine()));
cipherImpl.init(true, // means to encrypt
params as PaddedBlockCipherParameters<CipherParameters?,
@ -1647,16 +1654,14 @@ String myEncryptRaw( String privateString,
offset += cipherImpl.doFinal(uintInputText, offset, outputEncodedText, offset);
final Uint8List finalEncodedText = outputEncodedText.sublist(0, offset);
String stringIv = convert.base64.encode(iv);;
String stringIv = convert.base64.encode(iv);
String outputPlainText = convert.base64.encode(finalEncodedText);
outputPlainText = outputPlainText + "?iv=" + stringIv;
outputPlainText = "$outputPlainText?iv=$stringIv";
return outputPlainText;
}
/**
* Read events from file. a flag is set for such events, so that when writing events back, the ones read from file aren't added, and only
* new events from relays are written to file.
*/
/// Read events from file. a flag is set for such events, so that when writing events back, the ones read from file aren't added, and only
/// new events from relays are written to file.
Set<Event> readEventsFromFile(String filename) {
Set<Event> events = {};
final File file = File(filename);
@ -1709,7 +1714,7 @@ String myGetPublicKey(String prikey) {
if( pubkey.length < 64) {
int numZeros = 64 - pubkey.length;
for(int i = 0; i < numZeros; i++) {
pubkey = "0" + pubkey;
pubkey = "0$pubkey";
}
}
return pubkey;

View File

@ -63,7 +63,7 @@ class Relays {
void getKindEvents(List<int> kind, String relayUrl, int limit, int sinceWhen) {
kind.toString();
String subscriptionId = "kind_" + kind.toString() + "_" + relayUrl.substring(6);
String subscriptionId = "kind_${kind}_${relayUrl.substring(6)}";
String request = getKindRequest(subscriptionId, kind, limit, sinceWhen);
sendRequest(relayUrl, request);
@ -79,20 +79,21 @@ class Relays {
}
}
String subscriptionId = "single_user" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
String subscriptionId = "single_user${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
if( relays.containsKey(relayUrl)) {
Set<String>? 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
bool alreadyRecevied = false;
users.forEach((user) {
for (var user in users) {
if( user == publicKey) {
alreadyRecevied = true;
}
});
}
if( alreadyRecevied)
if( alreadyRecevied) {
return;
}
users.add(publicKey);
}
@ -110,7 +111,7 @@ class Relays {
}
}
String subscriptionId = "mention" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
String subscriptionId = "mention${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
String request = getMentionRequest(subscriptionId, ids, limit, sinceWhen, tagToGet);
sendRequest(relayUrl, request);
@ -118,7 +119,7 @@ class Relays {
void getIdAndMentionEvents(String relayUrl, Set<String> ids, int limit, int idSinceWhen, int mentionSinceWhen, String tagToGet, String idType) {
String subscriptionId = "id_mention_tag" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
String subscriptionId = "id_mention_tag${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
String request = getIdAndMentionRequest(subscriptionId, ids, limit, idSinceWhen, mentionSinceWhen, tagToGet, idType);
sendRequest(relayUrl, request);
}
@ -128,7 +129,7 @@ class Relays {
* @connect Connect to given relay and get all events for multiple users/publicKey and insert the
* received events in the given List<Event>
*/
void getMultiUserEvents(String relayUrl, List<String> publicKeys, int limit, int sinceWhen, [Set<int>? kind = null]) {
void getMultiUserEvents(String relayUrl, List<String> publicKeys, int limit, int sinceWhen, [Set<int>? kind]) {
Set<String> setPublicKeys = publicKeys.toSet();
if( relays.containsKey(relayUrl)) {
@ -139,7 +140,7 @@ class Relays {
}
}
String subscriptionId = "multiple_user" + (relays[relayUrl]?.numRequestsSent??"").toString() + "_" + relayUrl.substring(6);
String subscriptionId = "multiple_user${relays[relayUrl]?.numRequestsSent??""}_${relayUrl.substring(6)}";
String request = getMultiUserRequest( subscriptionId, setPublicKeys, limit, sinceWhen, kind);
sendRequest(relayUrl, request);
}
@ -215,7 +216,7 @@ class Relays {
print('WebSocketChannelException exception for relay $relayUrl');
return; // is presently not used/called
}
on Exception catch(ex) {
on Exception {
printWarning("Invalid event\n");
}
@ -261,9 +262,9 @@ void getContactFeed(Set<String> relayUrls, Set<String> setContacts, int numEvent
groupContacts.add(contacts[i + j]);
}
relayUrls.forEach((relayUrl) {
for (var relayUrl in relayUrls) {
relays.getMultiUserEvents(relayUrl, groupContacts, numEventsToGet, sinceWhen);
});
}
}
@ -272,28 +273,28 @@ void getContactFeed(Set<String> relayUrls, Set<String> setContacts, int numEvent
}
void getUserEvents(Set<String> serverUrls, String publicKey, int numUserEvents, int sinceWhen) {
serverUrls.forEach((serverUrl) {
for (var serverUrl in serverUrls) {
relays.getUserEvents(serverUrl, publicKey, numUserEvents, sinceWhen);
});
}
}
void getMentionEvents(Set<String> serverUrls, Set<String> ids, int numUserEvents, int sinceWhen, String tagToGet) {
serverUrls.forEach((serverUrl) {
for (var serverUrl in serverUrls) {
relays.getMentionEvents(serverUrl, ids, numUserEvents, sinceWhen, tagToGet);
});
}
}
void getIdAndMentionEvents(Set<String> serverUrls, Set<String> ids, int numUserEvents, int idSinceWhen, int mentionSinceWhen, String tagToGet, String idType) {
serverUrls.forEach((serverUrl) {
for (var serverUrl in serverUrls) {
relays.getIdAndMentionEvents(serverUrl, ids, numUserEvents, idSinceWhen, mentionSinceWhen, tagToGet, idType);
});
}
}
getKindEvents(List<int> kind, Set<String> serverUrls, int limit, int sinceWhen) {
serverUrls.forEach((serverUrl) {
for (var serverUrl in serverUrls) {
relays.getKindEvents(kind, serverUrl, limit, sinceWhen);
});
}
}
void getMultiUserEvents(Set<String> serverUrls, Set<String> setPublicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
@ -314,23 +315,24 @@ void getMultiUserEvents(Set<String> serverUrls, Set<String> setPublicKeys, int n
// send request for specific events whose id's are passed as list eventIds
void sendEventsRequest(Set<String> serverUrls, Set<String> eventIds) {
if( eventIds.length == 0)
if( eventIds.isEmpty) {
return;
}
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);;
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);
String getEventRequest = '["REQ","event_${eventIds.length}",{"ids":[$eventIdsStr]}]';
if( gDebug > 0) log.info("sending $getEventRequest");
serverUrls.forEach((url) {
for (var url in serverUrls) {
relays.sendRequest(url, getEventRequest);
});
}
}
void sendRequest(Set<String> serverUrls, request) {
serverUrls.forEach((url) {
for (var url in serverUrls) {
relays.sendRequest(url, request);
});
}
}
Set<Event> getRecievedEvents() {
@ -343,7 +345,7 @@ void clearEvents() {
}
void setRelaysIntialEvents(Set<Event> eventsFromFile) {
eventsFromFile.forEach((element) {relays.uniqueIdsRecieved.add(element.eventData.id);});
for (var element in eventsFromFile) {relays.uniqueIdsRecieved.add(element.eventData.id);}
relays.rEvents = eventsFromFile;
}

View File

@ -241,8 +241,9 @@ Map<String, String> pubkeyColor = { '0': magentaColor, '1': brightMagentaColor,
};
String getNameColor( String pubkey) {
if( pubkey.length == 0)
if( pubkey.isEmpty) {
return brightMagentaColor;
}
String firstChar = pubkey.substring(0, 1).toLowerCase();
return pubkeyColor[firstChar]??brightMagentaColor;
@ -408,10 +409,11 @@ List<String> lines = intro.split("\n");
var terminalColumns = gDefaultTextWidth;
if( stdout.hasTerminal )
if( stdout.hasTerminal ) {
terminalColumns = stdout.terminalColumns;
}
lines.forEach((line) {print(line.length > terminalColumns ? line.substring(0, terminalColumns) : line );});
for (var line in lines) {print(line.length > terminalColumns ? line.substring(0, terminalColumns) : line );}
}
@ -427,6 +429,6 @@ void printUsage() {
print(gUsage);
}
void printVersion() {
print("$version");
print(version);
}

View File

@ -1,4 +1,3 @@
import 'dart:ffi';
import 'dart:io';
import 'dart:convert';
import 'package:nostr_console/event_ds.dart';
@ -6,7 +5,7 @@ import 'package:nostr_console/relays.dart';
import 'package:nostr_console/utils.dart';
import 'package:nostr_console/settings.dart';
import 'package:nostr_console/user.dart';
import 'dart:math'; // for Point
// for Point
typedef fTreeSelector = bool Function(Tree a);
@ -16,7 +15,7 @@ typedef fRoomSelector = bool Function(ScrollableMessages room);
typedef fvisitorMarkNotifications = void Function(Event e);
Store? gStore = null;
Store? gStore;
// only show in which user is involved
bool selectorTrees_selfPosts(Tree t) {
@ -37,7 +36,7 @@ bool userInvolved(String pubkey, Event e) {
}
if( gReactions.containsKey(e.eventData.id)) {
List<List<String>>? reactors = gReactions[e.eventData.id]??null;
List<List<String>>? reactors = gReactions[e.eventData.id];
if( reactors != null) {
for( var reactor in reactors) {
String reactorPubkey = reactor[0];
@ -91,7 +90,7 @@ bool followsInvolved(Event e, Event? contactEvent) {
// check if any of the contact liked it
if( gReactions.containsKey(e.eventData.id)) {
List<List<String>>? reactors = gReactions[e.eventData.id]??null;
List<List<String>>? reactors = gReactions[e.eventData.id];
if( reactors != null) {
for( var reactor in reactors) {
String reactorPubkey = reactor[0];
@ -147,20 +146,20 @@ bool showAllRooms (ScrollableMessages room) => selectorShowAllRooms(room);
int getLatestMessageTime(ScrollableMessages channel) {
List<String> _messageIds = channel.messageIds;
List<String> messageIds = channel.messageIds;
if(gStore == null) {
return 0;
}
if(_messageIds.length == 0) {
if(messageIds.isEmpty) {
int createdAt = channel.createdAt;
return createdAt;
}
int latest = 0;
for(int i = 0; i < _messageIds.length; i++) {
for(int i = 0; i < messageIds.length; i++) {
if( gStore != null) {
Tree? tree = (gStore?.allChildEventsMap[_messageIds[i]] );
Tree? tree = (gStore?.allChildEventsMap[messageIds[i]] );
if( tree != null) {
EventData ed = tree.event.eventData;
if( ed.createdAt > latest) {
@ -193,8 +192,9 @@ DirectMessageRoom? getDirectRoom(List<DirectMessageRoom> rooms, String otherPubk
int scrollableCompareTo(ScrollableMessages a, ScrollableMessages b) {
if( gStore == null)
if( gStore == null) {
return 0;
}
int otherLatest = getLatestMessageTime(b);
int thisLatest = getLatestMessageTime(a);
@ -228,12 +228,12 @@ class ScrollableMessages {
int eventTime = (tempChildEventsMap[messageIds[i]]?.event.eventData.createdAt??0);
if( newEventTime < eventTime) {
// shift current i and rest one to the right, and put event Time here
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in middle to room with name ${topHeader}");
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in middle to room with name $topHeader");
messageIds.insert(i, messageId);
return;
}
}
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in end of room with name ${topHeader}");
if(gSpecificDebug > 0 && roomType == enumRoomType.kind140) print("In addMessageToRoom: inserted enc message in end of room with name $topHeader");
// insert at end
messageIds.add(messageId);
@ -273,15 +273,16 @@ class ScrollableMessages {
if( messageIds.length > gNumChannelMessagesToShow) {
print("\n");
printDepth(0);
stdout.write("${gNotificationColor}Displayed page number ${page} (out of total $numPages pages, where 1st is the latest 'page').\n");
stdout.write("${gNotificationColor}Displayed page number $page (out of total $numPages pages, where 1st is the latest 'page').\n");
printDepth(0);
stdout.write("To see older pages, enter numbers from 1-${numPages}, in format '/N', a slash followed by the required page number.${gColorEndMarker}\n\n");
stdout.write("To see older pages, enter numbers from 1-$numPages, in format '/N', a slash followed by the required page number.$gColorEndMarker\n\n");
}
}
bool selectorNotifications() {
if( gStore == null)
if( gStore == null) {
return false;
}
for(int i = 0; i < messageIds.length; i++) {
Event? e = gStore?.allChildEventsMap[messageIds[i]]?.event;
@ -317,6 +318,7 @@ class Channel extends ScrollableMessages {
Set<String> participants; // pubkey of all participants - only for encrypted channels
String creatorPubkey; // creator of the channel, if event is known
@override
enumRoomType roomType;
Channel(this.channelId, this.internalChatRoomName, this.about, this.picture, List<String> messageIds, this.participants, this.lastUpdated, this.roomType, [this.creatorPubkey=""] ) :
@ -333,7 +335,7 @@ class Channel extends ScrollableMessages {
return internalChatRoomName;
}
void set chatRoomName(String newName){
set chatRoomName(String newName){
internalChatRoomName = newName;
super.topHeader = "Channel Name: $newName (Id: $channelId)";
}
@ -366,11 +368,11 @@ class Channel extends ScrollableMessages {
// represents direct chat of kind 4
class DirectMessageRoom extends ScrollableMessages{
String otherPubkey; // id of user this DM is happening
@override
int createdAt;
DirectMessageRoom(this.otherPubkey, List<String> messageIds, this.createdAt):
super ( "${(otherPubkey)} ($otherPubkey)", messageIds, createdAt, enumRoomType.kind4) {
}
super ( "${(otherPubkey)} ($otherPubkey)", messageIds, createdAt, enumRoomType.kind4);
String getChannelId() {
return otherPubkey;
@ -404,7 +406,7 @@ class Tree {
store = s;
}
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
/* The main print tree function. Calls the reeSelector() for every node and prints it( and its children), only if it returns true.
* returns Point , where first int is total Threads ( or top trees) printed, and second is notifications printed
* returns list< total top threads printed, total events printed, total notifications printed>
@ -412,7 +414,7 @@ class Tree {
List<int> printTree(int depth, DateTime newerThan, bool topPost, [int countPrinted = 0, int maxToPrint = gMaxEventsInThreadPrinted]) {
List<int> ret = [0,0,0];
if(event.eventData.isNotification || event.eventData.newLikes.length > 0) {
if(event.eventData.isNotification || event.eventData.newLikes.isNotEmpty) {
ret[2] = 1;
}
@ -503,7 +505,7 @@ class Tree {
if( pubkeys.contains(event.eventData.pubkey) && gReactions.containsKey(event.eventData.id)) {
List<List<String>>? reactions = gReactions[event.eventData.id];
if( reactions != null) {
if( reactions.length > 0) {
if( reactions.isNotEmpty) {
// set every reaction as a new like so they all get highlighted; these are all later reset after first printing
Set<String> reactorPubkeys = getReactorPubkeys(event.eventData.id);
event.eventData.newLikes = reactorPubkeys;
@ -517,18 +519,20 @@ class Tree {
Set<String> pplTagged = pTags.toSet().intersection(pubkeys);
// 2nd condition: person making the event should not be on this list; they would already be considered in other test
if( pplTagged.length > 0 && !pubkeys.contains(event.eventData.pubkey)) {
if( pplTagged.isNotEmpty && !pubkeys.contains(event.eventData.pubkey)) {
event.eventData.isNotification = isMentioned = true;
}
// check if there are any replies from other people to an event made by someone in list
if( pubkeys.contains(event.eventData.pubkey) && children.length > 0) {
if( pubkeys.contains(event.eventData.pubkey) && children.isNotEmpty) {
for( int i = 0; i < children.length; i++ ) {
children.forEach((child) {
for (var child in children) {
// if child is someone else then set notifications and flag, means there are replies to this event
if(child.event.eventData.pubkey != event.eventData.pubkey ) // tests reply is not from same user
if(child.event.eventData.pubkey != event.eventData.pubkey ) {
// tests reply is not from same user
childMatches = child.event.eventData.isNotification = true;
});
}
}
}
}
@ -597,8 +601,9 @@ class Tree {
if( reactions != null) {
for( int i = 0; i < reactions.length; i++) {
if( pubkeys.contains(reactions[i][0]) ) {
if( enableNotifications)
if( enableNotifications) {
event.eventData.newLikes.add(reactions[i][0]);
}
hasReacted = true;
}
}
@ -617,8 +622,9 @@ class Tree {
// if event is by user(s)
if( pubkeys.contains(event.eventData.pubkey)) {
if( enableNotifications)
if( enableNotifications) {
event.eventData.isNotification = true;
}
return true;
}
if( hasReacted || childMatches) {
@ -636,8 +642,9 @@ class Tree {
// if event is by user(s)
if( pubkeys.contains(event.eventData.pubkey)) {
if( enableNotifications)
if( enableNotifications) {
event.eventData.isNotification = true;
}
return true;
}
@ -721,7 +728,7 @@ class Tree {
bool treeSelector_hasNotifications() {
bool hasNotifications = false;
if( event.eventData.isNotification || event.eventData.newLikes.length > 0) {
if( event.eventData.isNotification || event.eventData.newLikes.isNotEmpty) {
hasNotifications = true;
}
@ -749,7 +756,7 @@ class Tree {
count = 1;
}
if( event.eventData.newLikes.length > 0) {
if( event.eventData.newLikes.isNotEmpty) {
event.eventData.newLikes = {};
count = 1;
}
@ -777,7 +784,7 @@ class Tree {
} // end count()
} // end Tree
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
/*
* The actual tree struture holds only kind 1 events, or only posts. Tree itself can hold any event type( to be fixed, needs renaming etc TODO)
* This Store class holds events too in its map, and in its chatRooms structure
@ -902,7 +909,7 @@ class Store {
static void addTTagEventInChannel(EventData eventData, List<Channel> rooms, Map<String, Tree> tempChildEventsMap) {
List<String>? tTags = eventData.getTTags();
if( tTags != null && tTags.length > 0) {
if( tTags != null && tTags.isNotEmpty) {
for( int i = 0; i < tTags.length; i++) {
String chatRoomId = eventData.getChannelIdForTTagRoom(tTags[i]);
Channel? channel = getChannel(rooms, chatRoomId);
@ -949,11 +956,9 @@ class Store {
return null;
}
/**
* Will create a entry in encryptedChannels ( if one does not already exist)
* Returns id of channel if one is created, null otherwise.
*
*/
/// Will create a entry in encryptedChannels ( if one does not already exist)
/// Returns id of channel if one is created, null otherwise.
///
static String? createEncryptedRoomFromInvite( List<Channel> encryptedChannels, Map<String, Tree> tempChildEventsMap, Event eventSecretMessage) {
String? temp140Id = getEncryptedChannelIdFromSecretMessage( eventSecretMessage);
@ -969,7 +974,7 @@ class Store {
if( event140 != null) {
Set<String> participants = {};
event140.eventData.pTags.forEach((element) { participants.add(element);});
for (var element in event140.eventData.pTags) { participants.add(element);}
String chatRoomId = event140Id;
try {
@ -1018,7 +1023,7 @@ class Store {
// update the participant list if the event already exists ( the room was likely creted with 104 invite, which did not have participant list)
Set<String> participants = {};
event14x.eventData.pTags.forEach((element) { participants.add(element);});
for (var element in event14x.eventData.pTags) { participants.add(element);}
Channel? channel = getChannel(encryptedChannels, event14x.eventData.id);
dynamic json = jsonDecode(event14x.eventData.content);
@ -1042,7 +1047,7 @@ class Store {
case 141:
Set<String> participants = {};
event14x.eventData.pTags.forEach((element) { participants.add(element);});
for (var element in event14x.eventData.pTags) { participants.add(element);}
String chatRoomId = event14x.eventData.getChannelIdForKind4x();
if( chatRoomId.length != 64) {
@ -1093,7 +1098,7 @@ class Store {
}
} else {
// could not get channel id of message.
printWarning("---Could not get encryptd channel for message id ${event14x.eventData.id} got channelId : ${channelId} its len ${channelId.length}");
printWarning("---Could not get encryptd channel for message id ${event14x.eventData.id} got channelId : $channelId its len ${channelId.length}");
}
break;
@ -1158,7 +1163,7 @@ class Store {
directRooms.add( newDirectRoom);
if( ce.eventData.id == gCheckEventId && gDebug >= 0) print("Adding new message ${ce.eventData.id} to NEW direct room $directRoomId. sender pubkey = ${ce.eventData.pubkey}.");
}
if( ce.eventData.evaluatedContent.length > 0) numMessagesDecrypted++;
if( ce.eventData.evaluatedContent.isNotEmpty) numMessagesDecrypted++;
} else {
if( gDebug > 0) print("Could not get chat room id for event ${ce.eventData.id} sender pubkey = ${ce.eventData.pubkey}.");
}
@ -1252,7 +1257,7 @@ class Store {
}
}
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
// @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 Store.fromEvents(Set<Event> events) {
@ -1264,12 +1269,12 @@ class Store {
// create a map tempChildEventsMap from list of events, key is eventId and value is event itself
Map<String, Tree> tempChildEventsMap = {};
events.forEach((event) {
for (var event in events) {
// only add in map those kinds that are supported or supposed to be added ( 0 1 3 7 40)
if( typesInEventMap.contains(event.eventData.kind)) {
tempChildEventsMap[event.eventData.id] = Tree.withoutStore( event, []);
}
});
}
processDeleteEvents(tempChildEventsMap); // handle returned values perhaps later
processReactions(events, tempChildEventsMap);
@ -1322,7 +1327,7 @@ class Store {
}
// if reacted to event is not in store, then add it to dummy list so it can be fetched
if( tree.event.eventData.eTags.length > 0 && tree.event.eventData.eTags.last.length > 0) {
if( tree.event.eventData.eTags.isNotEmpty && tree.event.eventData.eTags.last.isNotEmpty) {
String reactedToId = tree.event.eventData.eTags.last[0];
if( !tempChildEventsMap.containsKey(reactedToId) && tree.event.eventData.createdAt > getSecondsDaysAgo(3)) {
//print("liked event not found in store.");
@ -1353,7 +1358,7 @@ class Store {
// allEncryptedGroupInviteIds has been created above
// now create encrypted rooms from that list which are just for the current user
Set<String> usersEncryptedChannelIds = {};
allEncryptedGroupInviteIds.forEach((secretEventId) {
for (var secretEventId in allEncryptedGroupInviteIds) {
Event? secretEvent = tempChildEventsMap[secretEventId]?.event;
if( secretEvent != null) {
@ -1363,7 +1368,7 @@ class Store {
usersEncryptedChannelIds.add(newEncryptedChannelId); // is later used so a request can be sent to fetch events related to this room
}
}
});
}
tempChildEventsMap.forEach((newEventId, tree) {
int eKind = tree.event.eventData.kind;
@ -1391,7 +1396,7 @@ class Store {
return Store( topLevelTrees, tempChildEventsMap, tempWithoutParent, channels, encryptedChannels, tempDirectRooms, allEncryptedGroupInviteIds);
} // end fromEvents()
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
/* @processIncomingEvent inserts the relevant events into the tree and otherwise processes likes, delete events etc.
* returns the id of the ones actually new so that they can be printed as notifications.
*/
@ -1403,26 +1408,26 @@ class Store {
Set<String> dummyEventIds = {};
// add the event to the main event store thats allChildEventsMap
newEventsToProcess.forEach((newEvent) {
for (var newEvent in newEventsToProcess) {
if( newEvent.eventData.kind == 1 && newEvent.eventData.content.compareTo("Hello Nostr! :)") == 0 && newEvent.eventData.id.substring(0,3).compareTo("000") == 0) {
return; // spam prevention
continue; // spam prevention
}
if( allChildEventsMap.containsKey(newEvent.eventData.id)) {// don't process if the event is already present in the map
return;
continue;
}
//ignore bots
if( [4, 42, 142].contains( newEvent.eventData.kind ) && gBots.contains(newEvent.eventData.pubkey)) {
return;
continue;
}
// handle reaction events and return if we could not find the reacted to. Continue otherwise to add this to notification set newEventIdsSet
if( newEvent.eventData.kind == 7) {
if( processReaction(newEvent, allChildEventsMap) == "") {
if(gDebug > 0) print("In insertEvents: For new reaction ${newEvent.eventData.id} could not find reactedTo or reaction was already present by this reactor");
return;
continue;
}
}
@ -1430,12 +1435,12 @@ class Store {
if( newEvent.eventData.kind == 5) {
processDeleteEvent(allChildEventsMap, newEvent);
if(gDebug > 0) print("In insertEvents: For new deleteion event ${newEvent.eventData.id} could not process it.");
return;
continue;
}
if( newEvent.eventData.kind == 4) {
if( !isValidDirectMessage(newEvent.eventData)) { // direct message not relevant to user are ignored; also otherwise validates the message that it has one p tag
return;
continue;
}
}
@ -1445,12 +1450,13 @@ class Store {
// only kind 0, 1, 3, 4, 5( delete), 7, 40, 42, 140, 142 events are added to map-store, return otherwise
if( !typesInEventMap.contains(newEvent.eventData.kind) ) {
return;
continue;
}
// expand mentions ( and translate if flag is set) and then add event to main event map; 142 events are expanded later
if( newEvent.eventData.kind != 142)
if( newEvent.eventData.kind != 142) {
newEvent.eventData.translateAndExpandMentions( allChildEventsMap); // this also handles dm decryption for kind 4 messages, for kind 1 will do translation/expansion;
}
// add them to the main store of the Tree object, but after checking that its not one of the dummy/missing events.
// In that case, replace the older dummy event, and only then add it to store-map
@ -1462,7 +1468,7 @@ class Store {
if( gDebug >= 0 && newEvent.eventData.id == gCheckEventId) log.info("In processIncoming: Replaced old dummy event of id: ${newEvent.eventData.id}");
tree.event = newEvent;
allChildEventsMap[tree.event.eventData.id] = tree;
return;
continue;
}
}
@ -1471,10 +1477,10 @@ class Store {
// add to new-notification list only if this is a recent event ( because relays may send old events, and we dont want to highlight stale messages)
newEventIdsSet.add(newEvent.eventData.id);
});
}
// now go over the newly inserted event, and add it to the tree for kind 1 events, add 42 events to channels. rest ( such as kind 0, kind 3, kind 7) are ignored.
newEventIdsSet.forEach((newId) {
for (var newId in newEventIdsSet) {
Tree? newTree = allChildEventsMap[newId];
if( newTree != null) { // this should return true because we just inserted this event in the allEvents in block above
@ -1497,21 +1503,22 @@ class Store {
topPosts.add(dummyTopNode);
// add it to list to fetch it from relays
if( parentId.length == 64)
dummyEventIds.add(parentId);
if( parentId.length == 64) {
dummyEventIds.add(parentId);
}
}
}
// now process case where there is a tag which should put this kind 1 message in a channel
String? location = newTree.event.eventData.getSpecificTag("location");
if( location != null && location != "") {
addLocationTagEventInChannel(newTree.event.eventData, this.channels, allChildEventsMap);
addLocationTagEventInChannel(newTree.event.eventData, channels, allChildEventsMap);
}
// now process case where there is a tag which should put this kind 1 message in a channel
List<String>? tTags = newTree.event.eventData.getTTags();
if( tTags != null && tTags != "") {
addTTagEventInChannel(newTree.event.eventData, this.channels, allChildEventsMap);
addTTagEventInChannel(newTree.event.eventData, channels, allChildEventsMap);
}
break;
@ -1562,19 +1569,19 @@ class Store {
break;
}
}
});
}
// get dummy events
sendEventsRequest(gListRelayUrls, dummyEventIds);
int totalTreeSize = 0;
topPosts.forEach((element) {totalTreeSize += element.count();});
for (var element in topPosts) {totalTreeSize += element.count();}
if(gDebug > 0) print("In end of insertEvents: allChildEventsMap size = ${allChildEventsMap.length}; mainTree count = $totalTreeSize");
if(gDebug > 0) print("Returning ${newEventIdsSet.length} new notification-type events, which are ${newEventIdsSet.length < 10 ? newEventIdsSet: " <had more than 10 elements>"} ");
return newEventIdsSet;
} // end insertEvents()
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
/*
* @printNotifications Add the given events to the Tree, and print the events as notifications
* It should be ensured that these are only kind 1 events
@ -1600,13 +1607,13 @@ class Store {
}
List<Tree> topNotificationTree = []; // collect all top tress to display in this list. only unique tress will be displayed
newEventIdsSet.forEach((eventID) {
for (var eventID in newEventIdsSet) {
Tree ?t = allChildEventsMap[eventID];
if( t == null) {
// ignore if not in Tree. Should ideally not happen. TODO write warning otherwise
if( gDebug > 0) print("In printNotifications: Could not find event $eventID in tree");
return;
continue;
} else {
if( isRelevantForNotification(t)) {
switch(t.event.eventData.kind) {
@ -1643,7 +1650,7 @@ class Store {
}
}
}
});
}
// remove duplicate top trees
Set ids = {};
@ -1655,7 +1662,7 @@ class Store {
gFollowList = getFollows(userPublicKey);
List<int> ret = [0,0,0];
topNotificationTree.forEach( (t) {
for (var t in topNotificationTree) {
bool selectorTrees_followActionsWithNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: true);
if( selectorTrees_followActionsWithNotifications(t)) {
List<int> temp = Store.printTopPost(t, 0, DateTime(0));
@ -1664,7 +1671,7 @@ class Store {
ret[2] += temp[2];
//print("\n");
}
});
}
return ret;
}
@ -1691,7 +1698,7 @@ class Store {
return count;
}
/***********************************************************************************************************************************/
/// ********************************************************************************************************************************
/* The main print tree function. Calls the treeSelector() for every node and prints it( and its children), only if it returns true.
*/
List<int> printStoreTrees(int depth, DateTime newerThan, fTreeSelector treeSelector, [int maxToPrint = gMaxEventsInThreadPrinted]) {
@ -1787,11 +1794,9 @@ class Store {
return 0;
}
/**
* @printAllChennelsInfo Print one line information about all channels, which are type 40 events ( class ChatRoom) and for 14x channels both; channelsToPrint is different for both
*
* @param numRoomsOverview This many number of rooms should be printed.
*/
/// @printAllChennelsInfo Print one line information about all channels, which are type 40 events ( class ChatRoom) and for 14x channels both; channelsToPrint is different for both
///
/// @param numRoomsOverview This many number of rooms should be printed.
int printChannelsOverview(List<Channel> channelsToPrint, int numRoomsOverview, fRoomSelector selector, var tempChildEventsMap , Set<String>? secretMessageIds) {
channelsToPrint.sort(scrollableCompareTo);
@ -1818,7 +1823,7 @@ class Store {
//stdout.write("channel type: " + channelsToPrint[j].roomType.toString());
if( channelsToPrint[j].participants.length > 0 && !channelsToPrint[j].participants.contains(userPublicKey)) {
if( channelsToPrint[j].participants.isNotEmpty && !channelsToPrint[j].participants.contains(userPublicKey)) {
continue;
}
@ -1838,11 +1843,11 @@ class Store {
}
if( channelsToPrint[j].chatRoomName != "") {
name = "${channelsToPrint[j].chatRoomName}";
name = channelsToPrint[j].chatRoomName;
}
int numMessages = channelsToPrint[j].getNumValidMessages();
stdout.write("${name} ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(20- numMessages.toString().length)}");
stdout.write("$name ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(20- numMessages.toString().length)}");
numChannelsActuallyPrinted++;
List<String> messageIds = channelsToPrint[j].messageIds;
for( int i = messageIds.length - 1; i >= 0; i--) {
@ -1850,7 +1855,7 @@ class Store {
Event? e = allChildEventsMap[messageIds[i]]?.event;
if( e!= null) {
if( !(e.eventData.kind == 142 && e.eventData.content == e.eventData.evaluatedContent)) {
stdout.write("${e.eventData.getAsLine(tempChildEventsMap, secretMessageIds, channelsToPrint)}");
stdout.write(e.eventData.getAsLine(tempChildEventsMap, secretMessageIds, channelsToPrint));
break; // print only one event, the latest one
}
}
@ -1886,15 +1891,15 @@ class Store {
stdout.write("\nChannel participants : ");
int i = 0;
room.participants.forEach((participant) {
for (var participant in room.participants) {
if( i != 0) {
stdout.write(', ');
}
String pName = getAuthorName(participant);
printInColor("$pName", gCommentColor);
printInColor(pName, gCommentColor);
i++;
});
}
}
@ -1968,7 +1973,7 @@ class Store {
}
return fullChannelId.first;
} else {
if( fullChannelId.length == 0) {
if( fullChannelId.isEmpty) {
printWarning("Could not find the channel.");
}
else {
@ -1982,16 +1987,15 @@ class Store {
return directRooms.length;
}
/**
* @printDirectRoomInfo Print one line information about chat rooms
*/
/// @printDirectRoomInfo Print one line information about chat rooms
int printDirectRoomsOverview(fRoomSelector roomSelector, int numRoomsOverview, var tempChildEventsMap) {
directRooms.sort(scrollableCompareTo);
int numNotificationRooms = 0;
for( int j = 0; j < directRooms.length; j++) {
if( roomSelector(directRooms[j]))
if( roomSelector(directRooms[j])) {
numNotificationRooms++;
}
}
// even if num rooms is zero, we will show the heading when its show all rooms
@ -2026,8 +2030,9 @@ class Store {
int iNotification = 0; // notification counter
for( int j = startRoomIndex; j < endRoomIndex; j++) {
if( !roomSelector(directRooms[j]))
if( !roomSelector(directRooms[j])) {
continue;
}
// print only that we have been asked for
if( iNotification++ > numNotificationRooms) {
@ -2042,7 +2047,7 @@ class Store {
room.visitAllMessages(this, markAllRead);
int numMessages = room.messageIds.length;
stdout.write("${name} ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(18- numMessages.toString().length)}");
stdout.write("$name ${getNumSpaces(32-name.length)} $id $numMessages${getNumSpaces(18- numMessages.toString().length)}");
// print latest event in one line
List<String> messageIds = room.messageIds;
@ -2106,10 +2111,10 @@ class Store {
}
}
} else {
if( lookedUpName.length > 0) {
if( lookedUpName.isNotEmpty) {
printWarning("Got more than one public id for the name given, which are: ");
for(String pubkey in lookedUpName) {
print("${getAuthorName(pubkey)} - ${pubkey}, ");
print("${getAuthorName(pubkey)} - $pubkey, ");
}
}
else { // in case the given id is not present in our global list of usernames, create new room for them
@ -2169,7 +2174,7 @@ class Store {
Future<void> writeEventsToFile(String filename) async {
// this variable will be used later; update it if needed
if( gFollowList.length == 0) {
if( gFollowList.isEmpty) {
gFollowList = getFollows(userPublicKey);
}
@ -2207,7 +2212,7 @@ class Store {
}
String temp = tree.event.originalJson.trim();
String line = "${temp}\n";
String line = "$temp\n";
nLinesStr += line;
eventCounter++;
if( tree.event.eventData.kind == 1) {
@ -2227,8 +2232,8 @@ class Store {
nLinesStr = "";
}
if(gDebug > 0) log.info("finished writing eventCounter = ${eventCounter}.");
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which ${countPosts} are posts.");
if(gDebug > 0) log.info("finished writing eventCounter = $eventCounter.");
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which $countPosts are posts.");
} on Exception catch (e) {
print("Could not open file $filename.");
if( gDebug > 0) print("Could not open file: $e");
@ -2241,7 +2246,7 @@ class Store {
* Also adds 'client' tag with application name.
* @parameter replyToId First few letters of an event id for which reply is being made
*/
String getTagStr(String replyToId, String clientName, [bool addAllP = false, Set<String>? extraTags = null]) {
String getTagStr(String replyToId, String clientName, [bool addAllP = false, Set<String>? extraTags]) {
clientName = (clientName == "")? "nostr_console": clientName; // in case its empty
//print("extraTags = $extraTags");
@ -2249,26 +2254,29 @@ class Store {
if( extraTags != null)
for( String extraTag in extraTags) {
if( otherTags.length > 0)
if( otherTags.isNotEmpty) {
otherTags += ",";
}
otherTags += '["t","$extraTag"]';
}
if( gWhetherToSendClientTag) {
if( otherTags.length > 0)
if( otherTags.isNotEmpty) {
otherTags += ",";
}
otherTags += '["client","$clientName"]';
}
if( gUserLocation != "") {
if( otherTags.length > 0)
if( otherTags.isNotEmpty) {
otherTags += ",";
}
otherTags += '["location","$gUserLocation"]';
}
//print("otherTags = $otherTags");
if( replyToId.isEmpty) {
return otherTags.length >0 ? otherTags: '[]';
return otherTags.isNotEmpty ? otherTags: '[]';
}
String strTags = otherTags ;
@ -2293,7 +2301,7 @@ class Store {
if( latestEventId.isEmpty && replyToId.length == 64) {
latestEventId = replyToId;
}
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.length != 0) {
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.isNotEmpty) {
return "";
}
@ -2301,8 +2309,9 @@ class Store {
if( latestEventId.isNotEmpty) {
String? pTagPubkey = allChildEventsMap[latestEventId]?.event.eventData.pubkey;
if( pTagPubkey != null) {
if( strTags.length > 0)
if( strTags.isNotEmpty) {
strTags += ",";
}
strTags += '["p","$pTagPubkey"]';
}
String relay = getRelayOfUser(userPublicKey, pTagPubkey??"");
@ -2315,14 +2324,16 @@ class Store {
Tree topTree = getTopTree(t);
rootEventId = topTree.event.eventData.id;
if( rootEventId != latestEventId) { // if the reply is to a top/parent event, then only one e tag is sufficient
if( strTags.length > 0)
if( strTags.isNotEmpty) {
strTags += ",";
}
strTags += '["e","$rootEventId","","root"]';
}
}
if( strTags.length > 0)
if( strTags.isNotEmpty) {
strTags += ",";
}
strTags += '["e","$latestEventId","$relay","reply"]';
}
@ -2405,7 +2416,7 @@ class Store {
latestEventId = replyToId;
}
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.length != 0) {
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.isNotEmpty) {
printWarning('Could not find the given id: $replyToId. Sending a regular message.');
}
@ -2422,7 +2433,7 @@ class Store {
// add root for kind 1 in rooms
if( [enumRoomType.RoomLocationTag, enumRoomType.RoomTTag].contains( channel.roomType) ) {
Tree? replyTree = allChildEventsMap[latestEventId]??null;
Tree? replyTree = allChildEventsMap[latestEventId];
if( replyTree != null) {
Tree rootTree = getTopTree(replyTree);
String rootEventId = rootTree.event.eventData.id;
@ -2517,7 +2528,7 @@ class Store {
} else {
stdout.write("* Of the $selfNumContacts people you follow, $numSecond follow you back. Their names are: ");
mutualFollows.sort();
mutualFollows.forEach((name) { stdout.write("$name, ");});
for (var name in mutualFollows) { stdout.write("$name, ");}
}
print("");
} else { // end if contact event was found
@ -2536,9 +2547,9 @@ class Store {
static List<String> processDeleteEvent(Map<String, Tree> tempChildEventsMap, Event deleterEvent) {
List<String> deletedEventIds = [];
if( deleterEvent.eventData.kind == 5) {
deleterEvent.eventData.tags.forEach((tag) {
for (var tag in deleterEvent.eventData.tags) {
if( tag.length < 2) {
return;
continue;
}
if( tag[0] == "e") {
String deletedEventId = tag[1];
@ -2555,7 +2566,7 @@ class Store {
}
}
}
});
}
} // end if
return deletedEventIds;
} // end processDeleteEvent
@ -2566,7 +2577,7 @@ class Store {
Event deleterEvent = tree.event;
if( deleterEvent.eventData.kind == 5) {
List<String> tempIds = processDeleteEvent(tempChildEventsMap, deleterEvent);
tempIds.forEach((tempId) { deletedEventIds.add(tempId); });
for (var tempId in tempIds) { deletedEventIds.add(tempId); }
}
});
return deletedEventIds;
@ -2590,8 +2601,9 @@ class Store {
// the reactedTo event's id, blank if invalid reaction etc
static String processReaction(Event event, Map<String, Tree> tempChildEventsMap) {
if( gDebug > 0 && event.eventData.id == gCheckEventId)
print("in processReaction: 0 got reaction $gCheckEventId");
if( gDebug > 0 && event.eventData.id == gCheckEventId) {
print("in processReaction: 0 got reaction $gCheckEventId");
}
List<String> validReactionList = ["+", "!"]; // TODO support opposite reactions
List<String> opppositeReactions = ['-', "~"];
@ -2785,20 +2797,24 @@ Store getTree(Set<Event> events) {
events.retainWhere((event) => ids.add(event.eventData.id));
// process kind 0 events about metadata
events.forEach( (event) => processKind0Event(event));
for (var event in events) {
processKind0Event(event);
}
// process kind 3 events which is contact list. Update global info about the user (with meta data)
events.forEach( (event) => processKind3Event(event));
for (var event in events) {
processKind3Event(event);
}
// create tree from events
Store node = Store.fromEvents(events);
// translate and expand mentions
events.where((element) => [1, 42].contains(element.eventData.kind)).forEach( (event) => event.eventData.translateAndExpandMentions( node.allChildEventsMap));;
events.where((element) => [1, 42].contains(element.eventData.kind)).forEach( (event) => event.eventData.translateAndExpandMentions( node.allChildEventsMap));
// has been done in fromEvents
//events.where((element) => [gSecretMessageKind].contains(element.eventData.kind)).forEach( (event) => event.eventData.TranslateAndDecryptGroupInvite( ));;
events.where((element) => element.eventData.kind == 142).forEach( (event) => event.eventData.translateAndDecrypt14x(node.encryptedGroupInviteIds, node.encryptedChannels, node.allChildEventsMap));;
events.where((element) => element.eventData.kind == 142).forEach( (event) => event.eventData.translateAndDecrypt14x(node.encryptedGroupInviteIds, node.encryptedChannels, node.allChildEventsMap));
return node;
}
@ -2807,18 +2823,19 @@ Store getTree(Set<Event> events) {
String getDirectRoomId(EventData eventData) {
List<String> participantIds = [];
eventData.tags.forEach((tag) {
if( tag.length < 2)
return;
for (var tag in eventData.tags) {
if( tag.length < 2) {
continue;
}
if( tag[0] == 'p') {
participantIds.add(tag[1]);
}
});
}
participantIds.sort();
String uniqueId = "";
participantIds.forEach((element) {uniqueId += element;}); // TODO ensure its only one thats added s
for (var element in participantIds) {uniqueId += element;} // TODO ensure its only one thats added s
// send the other persons pubkey as identifier
if( eventData.pubkey == userPublicKey) {

View File

@ -10,7 +10,7 @@ Event? getContactEvent(String pubkey) {
// get the latest kind 3 event for the user, which lists his 'follows' list
if( gKindONames.containsKey(pubkey)) {
Event? e = (gKindONames[pubkey]?.latestContactEvent)??null;
Event? e = (gKindONames[pubkey]?.latestContactEvent);
return e;
}
@ -23,7 +23,9 @@ Set<String> getFollows(String pubkey) {
Event? profileContactEvent = getContactEvent(pubkey);
if( profileContactEvent != null) {
profileContactEvent.eventData.contactList.forEach((x) => followPubkeys.add(x.contactPubkey));
for (var x in profileContactEvent.eventData.contactList) {
followPubkeys.add(x.contactPubkey);
}
//followPubkeys = profileContactEvent.eventData.contactList.toSet();
}
@ -33,7 +35,7 @@ Set<String> getFollows(String pubkey) {
Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
Set<String> userChannels = {};
userEvents.forEach((event) {
for (var event in userEvents) {
if( event.eventData.pubkey == userPublicKey) {
if( [42, 142].contains( event.eventData.kind) ) {
String channelId = event.eventData.getChannelIdForKind4x();
@ -44,7 +46,7 @@ Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
userChannels.add(event.eventData.id);
}
}
});
}
return userChannels;
}
@ -88,11 +90,11 @@ Set<String> getpTags(Set<Event> events, int numMostFrequent) {
Set<String> getOnlyUserEvents(Set<Event> initialEvents, String userPubkey) {
Set<String> userEvents = {};
initialEvents.forEach((event) {
for (var event in initialEvents) {
if( event.eventData.pubkey == userPubkey) {
userEvents.add(event.eventData.id);
}
});
}
return userEvents;
}

View File

@ -22,14 +22,13 @@ String getPostKindFrom(enumRoomType eType) {
}
Set<String>? getTagsFromContent(String content) {
Set<String>? tags = null;
Set<String>? tags;
String regexp1 = '(#[a-zA-Z0-9_\-]+ )|(#[a-zA-Z0-9_\-]+)\$';
String regexp1 = '(#[a-zA-Z0-9_-]+ )|(#[a-zA-Z0-9_-]+)\$';
RegExp httpRegExp = RegExp(regexp1);
for( var match in httpRegExp.allMatches(content) ) {
if( tags == null)
tags = {};
tags ??= {};
tags.add( content.substring(match.start + 1, match.end).trim() );
}
@ -84,31 +83,35 @@ extension StringX on String {
int isChannelPageNumber(int max) {
if(this.length < 2 || this[0] != '/') {
if(length < 2 || this[0] != '/') {
return 0;
}
String rest = this.substring(1);
String rest = substring(1);
//print("rest = $rest");
int? n = int.tryParse(rest);
if( n != null) {
if( n < max)
if( n < max) {
return n;
}
}
return 0;
}
isEnglish( ) {
// since smaller words can be smileys they should not be translated
if( length < 10)
if( length < 10) {
return true;
}
if( !isLatinAlphabet())
if( !isLatinAlphabet()) {
return false;
}
if (isRomanceLanguage())
if (isRomanceLanguage()) {
return false;
}
return true;
}
@ -127,7 +130,7 @@ extension StringX on String {
Set<String> romanceWords = frenchWords.union(spanishWords).union(portugeseWords);
for( String word in romanceWords) {
if( this.toLowerCase().contains(" $word ")) {
if( toLowerCase().contains(" $word ")) {
return true;
}
}
@ -208,7 +211,7 @@ String unEscapeChars(String str) {
return temp;
}
void printUnderlined(String x) => { stdout.write("$x\n${getNumDashes(x.length)}\n")};
void printUnderlined(String x) { stdout.write("$x\n${getNumDashes(x.length)}\n");}
String getNumSpaces(int num) {
String s = "";
@ -228,7 +231,7 @@ String getNumDashes(int num, [String dashType = "-"]) {
List<List<int>> getUrlRanges(String s) {
List<List<int>> urlRanges = [];
String regexp1 = "http[s]*:\/\/[a-zA-Z0-9]+([.a-zA-Z0-9/_\\-\\#\\+=\\&\\?]*)";
String regexp1 = "http[s]*://[a-zA-Z0-9]+([.a-zA-Z0-9/_\\-\\#\\+=\\&\\?]*)";
RegExp httpRegExp = RegExp(regexp1);
for( var match in httpRegExp.allMatches(s) ) {
@ -273,11 +276,13 @@ List<int>? getTypeAndModule(String str) {
bool sanityChecked(String lnInvoice) {
if( lnInvoice.length < gMinLnInvoiceLength)
if( lnInvoice.length < gMinLnInvoiceLength) {
return false;
}
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc")
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc") {
return false;
}
return true;
}
@ -306,7 +311,7 @@ String expandLNInvoices(String content) {
}
qrStr = getPubkeyAsQrString(lnInvoice, typeAndModule[0], typeAndModule[1], "");
content = content.substring(0, match.start) + ":-\n\n" + qrStr + "\n\n" + content.substring(match.end);
content = "${content.substring(0, match.start)}:-\n\n$qrStr\n\n${content.substring(match.end)}";
}
return content;
@ -319,7 +324,7 @@ String getPubkeyAsQrString(String str, [int typeNumber = 4, moduleCount = 33, St
String output = "";
final qrCode = QrCode(typeNumber, QrErrorCorrectLevel.L)
..addData('$str');
..addData(str);
final qrImage = QrImage(qrCode);
assert( qrImage.moduleCount == moduleCount);
@ -372,8 +377,9 @@ String getStringFromUser(String prompt, [String defaultValue=""] ) {
stdout.write(prompt);
str = (stdin.readLineSync())??"";
if( str.length == 0)
if( str.isEmpty) {
str = defaultValue;
}
return str;
}
@ -399,21 +405,21 @@ String getCommaSeparatedInts(Set<int>? kind) {
return "";
}
if( kind.length == 0) {
if( kind.isEmpty) {
return "";
}
String strKind = "";
int i = 0;
kind.forEach((k) {
for (var k in kind) {
String comma = ",";
if( i == kind.length-1) {
comma = "";
}
strKind = strKind + k.toString() + comma;
i++;
});
}
return strKind;
}
@ -432,16 +438,14 @@ String getKindRequest(String subscriptionId, List<int> kind, int limit, int sinc
return strRequest;
}
String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen, [Set<int>? _kind = null]) {
String getUserRequest(String subscriptionId, String publicKey, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
Set<int> kind = {};
if( _kind != null) {
kind = _kind;
}
kind = kind;
String strKind = getCommaSeparatedInts(kind);
String strKindSection = "";
if( strKind.length > 0) {
if( strKind.isNotEmpty) {
strKindSection = '"kinds":[$strKind],';
}
@ -477,12 +481,12 @@ String getIdAndMentionRequest(String subscriptionId, Set<String> ids, int numUse
var strSubscription1 = '["REQ","$subscriptionId",{ "$tagToGet": [';
var strSubscription2 ='], "limit": $numUserEvents $idStrTime } ]';
String req = '["REQ","$subscriptionId",{ "$tagToGet": [' + getCommaSeparatedQuotedStrs(ids) + '], "limit": $numUserEvents $mentionStrTime},{"$idString":[' + getCommaSeparatedQuotedStrs(ids) + ']$idStrTime}]';
String req = '["REQ","$subscriptionId",{ "$tagToGet": [${getCommaSeparatedQuotedStrs(ids)}], "limit": $numUserEvents $mentionStrTime},{"$idString":[${getCommaSeparatedQuotedStrs(ids)}]$idStrTime}]';
return req;
}
String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind = null]) {
String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
String strTime = "";
if( sinceWhen != 0) {
strTime = ', "since": ${sinceWhen.toString()}';
@ -491,7 +495,7 @@ String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int nu
String strKind = getCommaSeparatedInts(kind);
String strKindSection = "";
if( strKind.length > 0) {
if( strKind.isNotEmpty) {
strKindSection = '"kinds":[$strKind],';
}
@ -508,14 +512,14 @@ void printSet( Set<String> toPrint, [ String prefix = "", String separator = ""]
stdout.write(prefix);
int i = 0;
toPrint.forEach((element) {
for (var element in toPrint) {
if( i != 0) {
stdout.write(separator);
}
stdout.write(element);
i++;
});
}
stdout.write("\n");
}

View File

@ -91,7 +91,8 @@ homepage: https://github.com/vishalxl/nostr_console
environment:
sdk: '>=2.17.3 <3.0.0'
sdk: '>=2.17.3 <4.0.0'
dev_dependencies:
@ -107,3 +108,5 @@ dependencies:
logging: ^1.0.2
kepler: ^1.0.3
qr: ^3.0.1
pointycastle: any
http: any

View File

@ -221,11 +221,11 @@ String expectedResult =
"11 https://github.com/nostr-protocol/nips/blob/master/16.md#ephemeral-events",
"https://res.cloudinary.com/eskema/image/upload/v1669030722/306072883_413474904244526_502927779121754777_n.jpg_l6je2d.jpg"];
urls.forEach((url) {
for (var url in urls) {
String res = makeParagraphAtDepth(url, 30);
//print(url); print(res);print("");
expect( res, url);
});
}
});
@ -233,27 +233,33 @@ String expectedResult =
Set<Event> initialEvents = {}; // collect all events here and then create tree out of them
String input_filename = 'test_event_file.csv';
initialEvents = await readEventsFromFile(input_filename);
String inputFilename = 'test_event_file.csv';
initialEvents = readEventsFromFile(inputFilename);
int numFilePosts = 0;
// count events
initialEvents.forEach((element) { element.eventData.kind == 1? numFilePosts++: numFilePosts;});
for (var element in initialEvents) { element.eventData.kind == 1? numFilePosts++: numFilePosts;}
//print("read $numFilePosts posts from file $gEventsFilename");
expect(numFilePosts, 3486, reason:'Verify right number of kind 1 posts');
Store node = await getTree(initialEvents);
Store node = getTree(initialEvents);
expect(0, node.getNumDirectRooms(), reason:'verify correct number of direct chat rooms created');
int numKind4xChannels = 0;
node.channels.forEach((channel) => channel.roomType == enumRoomType.kind40? numKind4xChannels++:1);
for (var channel in node.channels) {
channel.roomType == enumRoomType.kind40? numKind4xChannels++:1;
}
int numTTagChannels = 0;
node.channels.forEach((channel) => channel.roomType == enumRoomType.RoomTTag? numTTagChannels++:1);
for (var channel in node.channels) {
channel.roomType == enumRoomType.RoomTTag? numTTagChannels++:1;
}
int numLocationTagChannels = 0;
node.channels.forEach((channel) => channel.roomType == enumRoomType.RoomLocationTag? numLocationTagChannels++:1);
for (var channel in node.channels) {
channel.roomType == enumRoomType.RoomLocationTag? numLocationTagChannels++:1;
}
expect(78, numKind4xChannels, reason: 'verify correct number of public channels created of kind 4x');
expect(41, numTTagChannels, reason: 'verify correct number of public channels created of T tag type');