mirror of
https://github.com/vishalxl/nostr_console.git
synced 2025-06-15 03:10:49 +02:00
added analysis_options.yaml and ran lint and applied changes
This commit is contained in:
parent
626a2f66c5
commit
b9ac5538b3
26
analysis_options.yaml
Normal file
26
analysis_options.yaml
Normal 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
|
@ -92,7 +92,7 @@ Future<void> main(List<String> arguments) async {
|
|||||||
userPrivateKey = "";
|
userPrivateKey = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if( gUserLocation.length > 0){
|
if( gUserLocation.isNotEmpty){
|
||||||
print("Going to add $gUserLocation as the location tag with each post.");
|
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
|
// write informative message in case user is not using proper keys
|
||||||
if( userPublicKey == gDefaultPublicKey) {
|
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("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");
|
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) {
|
if( argResults[relayArg] != null) {
|
||||||
Set<String> userRelayList = Set.from(argResults[relayArg].split(","));
|
Set<String> userRelayList = Set.from(argResults[relayArg].split(","));
|
||||||
Set<String> parsedRelays = {};
|
Set<String> parsedRelays = {};
|
||||||
userRelayList.forEach((relay) {
|
for (var relay in userRelayList) {
|
||||||
if(relay.startsWith(RegExp(r'^ws[s]?:\/\/'))) {
|
if(relay.startsWith(RegExp(r'^ws[s]?:\/\/'))) {
|
||||||
parsedRelays.add(relay);
|
parsedRelays.add(relay);
|
||||||
} else {
|
} else {
|
||||||
printWarning("The provided relay entry: \"$relay\" does not start with ws:// or wss://, omitting");
|
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
|
// verify that there is at least one valid relay they provided, otherwise keep defaults
|
||||||
if (parsedRelays.length > 0) {
|
if (parsedRelays.isNotEmpty) {
|
||||||
gListRelayUrls = parsedRelays;
|
gListRelayUrls = parsedRelays;
|
||||||
defaultServerUrl = gListRelayUrls.first;
|
defaultServerUrl = gListRelayUrls.first;
|
||||||
} else {
|
} else {
|
||||||
@ -174,8 +174,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
var terminalColumns = gDefaultTextWidth;
|
var terminalColumns = gDefaultTextWidth;
|
||||||
if( stdout.hasTerminal )
|
if( stdout.hasTerminal ) {
|
||||||
terminalColumns = stdout.terminalColumns;
|
terminalColumns = stdout.terminalColumns;
|
||||||
|
}
|
||||||
|
|
||||||
// can be computed only after textWidth has been found
|
// can be computed only after textWidth has been found
|
||||||
if( gTextWidth > terminalColumns) {
|
if( gTextWidth > terminalColumns) {
|
||||||
@ -184,7 +185,7 @@ Future<void> main(List<String> arguments) async {
|
|||||||
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
||||||
} on StdoutException catch (e) {
|
} on StdoutException catch (e) {
|
||||||
print("Cannot find terminal size. Left aligning by default.");
|
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;
|
gNumLeftMarginSpaces = 0;
|
||||||
}
|
}
|
||||||
// undo above if left option is given
|
// 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.......');
|
stdout.write('Reading events from ${whetherDefault}file.......');
|
||||||
|
|
||||||
// read file events and give the events to relays from where they're picked up later
|
// 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
|
// count events
|
||||||
initialEvents.forEach((element) { numFileEvents++;});
|
for (var element in initialEvents) { numFileEvents++;}
|
||||||
print("read $numFileEvents events from file $gEventsFilename");
|
print("read $numFileEvents events from file $gEventsFilename");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ Future<void> main(List<String> arguments) async {
|
|||||||
clearEvents();
|
clearEvents();
|
||||||
|
|
||||||
|
|
||||||
initialEvents.forEach((element) { element.eventData.kind == 1? numUserPosts++: numUserPosts;});
|
for (var element in initialEvents) { element.eventData.kind == 1? numUserPosts++: numUserPosts;}
|
||||||
numUserPosts -= numFilePosts;
|
numUserPosts -= numFilePosts;
|
||||||
stdout.write("...done\n");//received $numUserPosts new posts made by the user\n");
|
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([40, 41], gListRelayUrls, limitPerSubscription, getSecondsDaysAgo(limitSelfEvents));
|
||||||
getKindEvents([42], gListRelayUrls, 3 * limitPerSubscription, getSecondsDaysAgo(limitOthersEvents));
|
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> contacts = {};
|
||||||
Set<String> pTags = {};
|
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 contact list was found, get user's feed; also get some default contacts
|
||||||
if (contactEvent != null ) {
|
if (contactEvent != null ) {
|
||||||
if(gDebug > 0) print("In main: found contact list: \n ${contactEvent.originalJson}");
|
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);
|
contacts.add(contact.contactPubkey);
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
print("Could not find your contact list.");
|
print("Could not find your contact list.");
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ Future<void> sendReplyPostLike(Store node, String replyToId, String replyKind, S
|
|||||||
|
|
||||||
int numShaDone = 0;
|
int numShaDone = 0;
|
||||||
for( numShaDone = 0; numShaDone < 100000000; numShaDone++) {
|
for( numShaDone = 0; numShaDone < 100000000; numShaDone++) {
|
||||||
vanityTag = strTags + ',["nonce","$numShaDone","$gDifficulty"]';
|
vanityTag = '$strTags,["nonce","$numShaDone","$gDifficulty"]';
|
||||||
id = getShaId(userPublicKey, createdAt.toString(), replyKind, vanityTag, content);
|
id = getShaId(userPublicKey, createdAt.toString(), replyKind, vanityTag, content);
|
||||||
if( id.substring(0, numBytes) == zeroString) {
|
if( id.substring(0, numBytes) == zeroString) {
|
||||||
break;
|
break;
|
||||||
@ -160,7 +160,7 @@ Future<void> sendChannelReply(Store node, Channel channel, String replyTo, Strin
|
|||||||
// send DM
|
// send DM
|
||||||
Future<void> sendDirectMessage(Store node, String otherPubkey, String messageToSend, {String replyKind = "4"}) async {
|
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
|
//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);
|
String encryptedMessageToSend = myEncrypt(userPrivateKey, otherPubkey02, messageToSend);
|
||||||
|
|
||||||
//print("in sendDirectMessage: replyKind = $replyKind");
|
//print("in sendDirectMessage: replyKind = $replyKind");
|
||||||
@ -271,7 +271,7 @@ bool sendDeleteEvent(Store node, String eventIdToDelete) {
|
|||||||
} else {
|
} else {
|
||||||
print("Event not found. Kindly ensure you have entered a valid event id.");
|
print("Event not found. Kindly ensure you have entered a valid event id.");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -282,8 +282,9 @@ void reAdjustAlignment() {
|
|||||||
try {
|
try {
|
||||||
var terminalColumns = gDefaultTextWidth;
|
var terminalColumns = gDefaultTextWidth;
|
||||||
|
|
||||||
if( stdout.hasTerminal )
|
if( stdout.hasTerminal ) {
|
||||||
terminalColumns = stdout.terminalColumns;
|
terminalColumns = stdout.terminalColumns;
|
||||||
|
}
|
||||||
|
|
||||||
if( gTextWidth > terminalColumns) {
|
if( gTextWidth > terminalColumns) {
|
||||||
gTextWidth = terminalColumns - 5;
|
gTextWidth = terminalColumns - 5;
|
||||||
@ -291,7 +292,7 @@ void reAdjustAlignment() {
|
|||||||
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
gNumLeftMarginSpaces = (terminalColumns - gTextWidth )~/2;
|
||||||
} on StdoutException catch (e) {
|
} on StdoutException catch (e) {
|
||||||
print("Terminal information not available");
|
print("Terminal information not available");
|
||||||
if( gDebug>0) print("${e.message}");
|
if( gDebug>0) print(e.message);
|
||||||
gNumLeftMarginSpaces = 0;
|
gNumLeftMarginSpaces = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,7 +318,7 @@ void printProfile(Store node, String profilePubkey) {
|
|||||||
String picture = gKindONames[profilePubkey]?.picture??"";
|
String picture = gKindONames[profilePubkey]?.picture??"";
|
||||||
String lud06 = gKindONames[profilePubkey]?.lud06??"";
|
String lud06 = gKindONames[profilePubkey]?.lud06??"";
|
||||||
String lud16 = gKindONames[profilePubkey]?.lud16??"";
|
String lud16 = gKindONames[profilePubkey]?.lud16??"";
|
||||||
String display_name= gKindONames[profilePubkey]?.display_name??"";
|
String displayName= gKindONames[profilePubkey]?.display_name??"";
|
||||||
String website = gKindONames[profilePubkey]?.website??"";
|
String website = gKindONames[profilePubkey]?.website??"";
|
||||||
int dateLastUpdated = gKindONames[profilePubkey]?.createdAt??0;
|
int dateLastUpdated = gKindONames[profilePubkey]?.createdAt??0;
|
||||||
bool verified = gKindONames[profilePubkey]?.nip05Verified??false;
|
bool verified = gKindONames[profilePubkey]?.nip05Verified??false;
|
||||||
@ -334,7 +335,7 @@ void printProfile(Store node, String profilePubkey) {
|
|||||||
// print LNRUL lud06 if it exists
|
// print LNRUL lud06 if it exists
|
||||||
if( lud06.length > gMinLud06AddressLength) {
|
if( lud06.length > gMinLud06AddressLength) {
|
||||||
try {
|
try {
|
||||||
String lud06LNString = "lightning:" + lud06;
|
String lud06LNString = "lightning:$lud06";
|
||||||
|
|
||||||
List<int>? typesAndModule = getTypeAndModule(lud06LNString);
|
List<int>? typesAndModule = getTypeAndModule(lud06LNString);
|
||||||
if( typesAndModule != null) {
|
if( typesAndModule != null) {
|
||||||
@ -349,7 +350,7 @@ void printProfile(Store node, String profilePubkey) {
|
|||||||
// print LNRUL lud16 if it exists
|
// print LNRUL lud16 if it exists
|
||||||
if( lud16.length > gMinLud16AddressLength) {
|
if( lud16.length > gMinLud16AddressLength) {
|
||||||
try {
|
try {
|
||||||
String lud16LNString = "" + lud16;
|
String lud16LNString = lud16;
|
||||||
List<int>? typesAndModule = getTypeAndModule(lud16LNString);
|
List<int>? typesAndModule = getTypeAndModule(lud16LNString);
|
||||||
if( typesAndModule != null) {
|
if( typesAndModule != null) {
|
||||||
print("Printing lud16 address as QR:\n\n");
|
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("About : $about");
|
||||||
print("Picture : $picture");
|
print("Picture : $picture");
|
||||||
print("display_name: $display_name");
|
print("display_name: $displayName");
|
||||||
print("Website : $website");
|
print("Website : $website");
|
||||||
print("Lud06 : $lud06");
|
print("Lud06 : $lud06");
|
||||||
print("Lud16 : $lud16");
|
print("Lud16 : $lud16");
|
||||||
print("Nip 05 : ${verified?"yes. ${nip05Id}":"no"}");
|
print("Nip 05 : ${verified?"yes. $nip05Id":"no"}");
|
||||||
print("\nLast Updated: ${getPrintableDate(dateLastUpdated)}\n");
|
print("\nLast Updated: ${getPrintableDate(dateLastUpdated)}\n");
|
||||||
|
|
||||||
// get the latest kind 3 event for the user, which lists his 'follows' list
|
// 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
|
// print follow list
|
||||||
stdout.write("$pronoun follow ${profileContactEvent.eventData.contactList.length} accounts: ");
|
stdout.write("$pronoun follow ${profileContactEvent.eventData.contactList.length} accounts: ");
|
||||||
profileContactEvent.eventData.contactList.sort();
|
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");
|
print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +400,9 @@ void printProfile(Store node, String profilePubkey) {
|
|||||||
List<String> followers = node.getFollowers(profilePubkey);
|
List<String> followers = node.getFollowers(profilePubkey);
|
||||||
stdout.write("$pronoun have ${followers.length} followers: ");
|
stdout.write("$pronoun have ${followers.length} followers: ");
|
||||||
followers.sort((a, b) => getAuthorName(a).compareTo(getAuthorName(b)));
|
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("");
|
||||||
print("");
|
print("");
|
||||||
}
|
}
|
||||||
@ -436,11 +441,13 @@ void printMenu(List<String> menuOptions) {
|
|||||||
|
|
||||||
var terminalColumns = gDefaultTextWidth;
|
var terminalColumns = gDefaultTextWidth;
|
||||||
|
|
||||||
if( stdout.hasTerminal )
|
if( stdout.hasTerminal ) {
|
||||||
terminalColumns = stdout.terminalColumns;
|
terminalColumns = stdout.terminalColumns;
|
||||||
|
}
|
||||||
|
|
||||||
if( longestMenuOption + 5> gMenuWidth )
|
if( longestMenuOption + 5> gMenuWidth ) {
|
||||||
gMenuWidth = longestMenuOption + 8;
|
gMenuWidth = longestMenuOption + 8;
|
||||||
|
}
|
||||||
|
|
||||||
if( terminalColumns~/gMenuWidth > 4) {
|
if( terminalColumns~/gMenuWidth > 4) {
|
||||||
terminalColumns = gMenuWidth * 4;
|
terminalColumns = gMenuWidth * 4;
|
||||||
@ -463,7 +470,7 @@ void printMenu(List<String> menuOptions) {
|
|||||||
|
|
||||||
int showMenu(List<String> menuOptions, String menuName, [String menuInfo = ""]) {
|
int showMenu(List<String> menuOptions, String menuName, [String menuInfo = ""]) {
|
||||||
|
|
||||||
if(menuInfo.length > 0) {
|
if(menuInfo.isNotEmpty) {
|
||||||
print("\n$menuInfo\n");
|
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) {
|
void printPubkeys(Set<String> pubkey) {
|
||||||
print("${myPadRight("pubkey",64)} ${myPadRight("name", 20)} ${myPadRight("about", 40)} ${myPadRight("Nip05", 30)}");
|
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("");
|
print("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printPubkeyResult(Set<String> pubkey) {
|
void printPubkeyResult(Set<String> pubkey) {
|
||||||
|
|
||||||
if( pubkey.length == 0) {
|
if( pubkey.isEmpty) {
|
||||||
print("There is no pubkey for that given name.");
|
print("There is no pubkey for that given name.");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -599,18 +608,18 @@ Future<void> otherOptionsMenuUi(Store node) async {
|
|||||||
String userName = getStringFromUser("Enter your new name : ", getAuthorName(userPublicKey));
|
String userName = getStringFromUser("Enter your new name : ", getAuthorName(userPublicKey));
|
||||||
String userAbout = getStringFromUser("Enter new 'about me' for yourself : ", gKindONames[userPublicKey]?.about??"");
|
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 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 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 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 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 lud16 = getStringFromUser("Enter your lud16 address. Leave blank if unknown/none: ", gKindONames[userPublicKey]?.lud16??"");
|
||||||
|
|
||||||
String strLud06 = lud06.length > 0? '"lud06":"$lud06",': '';
|
String strLud06 = lud06.isNotEmpty? '"lud06":"$lud06",': '';
|
||||||
String strLud16 = lud16.length > 0? '"lud16":"$lud16",': '';
|
String strLud16 = lud16.isNotEmpty? '"lud16":"$lud16",': '';
|
||||||
String strDispName = display_name.length > 0? '"display_name":"$display_name",': '';
|
String strDispName = displayName.isNotEmpty? '"display_name":"$displayName",': '';
|
||||||
String strWebsite = website.length > 0? '"website":"$website",': '';
|
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;
|
int createdAt = DateTime.now().millisecondsSinceEpoch ~/1000;
|
||||||
|
|
||||||
EventData eventData = EventData('id', userPublicKey, createdAt, 0, content, [], [], [], [], {}, );
|
EventData eventData = EventData('id', userPublicKey, createdAt, 0, content, [], [], [], [], {}, );
|
||||||
@ -633,11 +642,11 @@ Future<void> otherOptionsMenuUi(Store node) async {
|
|||||||
|
|
||||||
if( eventIdToDelete.length == 1) {
|
if( eventIdToDelete.length == 1) {
|
||||||
String toDeleteId = eventIdToDelete.first;
|
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);
|
sendDeleteEvent(node, eventIdToDelete.first);
|
||||||
await processAnyIncomingEvents(node, false); // get latest event, this takes 300 ms
|
await processAnyIncomingEvents(node, false); // get latest event, this takes 300 ms
|
||||||
} else {
|
} 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.");
|
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 {
|
} else {
|
||||||
printWarning("Invalid Event Id(s). Kindly enter a more unique id.");
|
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);
|
Channel? channel = node.getChannelFromId(node.channels, fullChannelId);
|
||||||
String actualMessage = messageToSend.substring(7);
|
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);
|
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if( channel != null) {
|
if( channel != null) {
|
||||||
await sendChannelReply(node, channel, replyTo, actualMessage, getPostKindFrom( channel.roomType));
|
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];
|
String priKey = keys[0], pubKey = keys[1];
|
||||||
encryptedMessage = myEncrypt(priKey, "02" + pubKey, messageToSend);
|
encryptedMessage = myEncrypt(priKey, "02$pubKey", messageToSend);
|
||||||
|
|
||||||
return encryptedMessage;
|
return encryptedMessage;
|
||||||
}
|
}
|
||||||
@ -983,9 +993,9 @@ Future<void> addUsersToEncryptedChannel(Store node, String fullChannelId, Set<St
|
|||||||
String content = channelEvent.eventData.content;
|
String content = channelEvent.eventData.content;
|
||||||
|
|
||||||
String tags = '["e","$fullChannelId"]';
|
String tags = '["e","$fullChannelId"]';
|
||||||
participants.forEach((participant) {
|
for (var participant in participants) {
|
||||||
tags += ',["p","${participant}"]';
|
tags += ',["p","$participant"]';
|
||||||
});
|
}
|
||||||
|
|
||||||
int numNewUsers = participants.length;
|
int numNewUsers = participants.length;
|
||||||
|
|
||||||
@ -1142,8 +1152,9 @@ Future<void> encryptedChannelMenuUI(Store node) async {
|
|||||||
String replyTo = tokens[1];
|
String replyTo = tokens[1];
|
||||||
String actualMessage = messageToSend.substring(7);
|
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);
|
actualMessage = messageToSend.substring( messageToSend.indexOf(tokens[1]) + tokens[1].length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
String encryptedMessageToSend = encryptChannelMessage(node, fullChannelId, actualMessage);
|
String encryptedMessageToSend = encryptChannelMessage(node, fullChannelId, actualMessage);
|
||||||
if( encryptedMessageToSend != "") {
|
if( encryptedMessageToSend != "") {
|
||||||
@ -1439,7 +1450,9 @@ Future<void> socialMenuUi(Store node) async {
|
|||||||
if( numPrinted[0] == 0) {
|
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");
|
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;
|
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): ");
|
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? $tempUserName = stdin.readLineSync();
|
||||||
String userName = $tempUserName??"";
|
String userName = $tempUserName??"";
|
||||||
stdout.write( "user name: " + userName);
|
stdout.write( "user name: $userName");
|
||||||
if( userName != "") {
|
if( userName != "") {
|
||||||
Set<String> pubkey = getPublicKeyFromName(userName);
|
Set<String> pubkey = getPublicKeyFromName(userName);
|
||||||
|
|
||||||
@ -1578,7 +1591,7 @@ Future<void> socialMenuUi(Store node) async {
|
|||||||
continue;
|
continue;
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
printWarning("Invalid input. Kindly try again.");
|
printWarning("Invalid input. Kindly try again.");
|
||||||
if( gDebug > 0) print(" ${e}");
|
if( gDebug > 0) print(" $e");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1600,8 +1613,9 @@ void directRoomNotifications(Store node, [int x = 0, int y = 0]) {
|
|||||||
bool showNotifications (ScrollableMessages room) => room.selectorNotifications();
|
bool showNotifications (ScrollableMessages room) => room.selectorNotifications();
|
||||||
int numDirectRoomsPrinted = node.printDirectRoomsOverview( showNotifications, 100, node.allChildEventsMap);
|
int numDirectRoomsPrinted = node.printDirectRoomsOverview( showNotifications, 100, node.allChildEventsMap);
|
||||||
|
|
||||||
if( numDirectRoomsPrinted > 0)
|
if( numDirectRoomsPrinted > 0) {
|
||||||
print("\n");
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
int totalNotifications = numPrinted[2] + numDirectRoomsPrinted;
|
int totalNotifications = numPrinted[2] + numDirectRoomsPrinted;
|
||||||
if( totalNotifications > 0) {
|
if( totalNotifications > 0) {
|
||||||
@ -1691,7 +1705,7 @@ Future<void> mainMenuUi(Store node) async {
|
|||||||
mainMenuContinue = false;
|
mainMenuContinue = false;
|
||||||
String authorName = getAuthorName(userPublicKey);
|
String authorName = getAuthorName(userPublicKey);
|
||||||
clearScreen();
|
clearScreen();
|
||||||
print("\nFinished Nostr session for user: ${authorName} ($userPublicKey)");
|
print("\nFinished Nostr session for user: $authorName ($userPublicKey)");
|
||||||
if( gEventsFilename != "") {
|
if( gEventsFilename != "") {
|
||||||
await node.writeEventsToFile(gEventsFilename);
|
await node.writeEventsToFile(gEventsFilename);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class UserNameInfo {
|
|||||||
Event ?latestContactEvent;
|
Event ?latestContactEvent;
|
||||||
bool nip05Verified;
|
bool nip05Verified;
|
||||||
String? nip05Id;
|
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];
|
List<List<String>>? reactions = gReactions[eventId];
|
||||||
|
|
||||||
if( reactions != null) {
|
if( reactions != null) {
|
||||||
reactions.forEach((reaction) { reactorIds.add(reaction[0]);});
|
for (var reaction in reactions) { reactorIds.add(reaction[0]);}
|
||||||
}
|
}
|
||||||
|
|
||||||
return reactorIds;
|
return reactorIds;
|
||||||
@ -157,22 +157,22 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// then depending on the numbers and values ( of root and replyto) return the parent
|
// then depending on the numbers and values ( of root and replyto) return the parent
|
||||||
if( replyId.length > 0) {
|
if( replyId.isNotEmpty) {
|
||||||
if( numReply == 1) {
|
if( numReply == 1) {
|
||||||
return replyId;
|
return replyId;
|
||||||
} else {
|
} else {
|
||||||
// if there are multiply reply's we can't tell which is which, so we return the one at top
|
// 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;
|
return replyId;
|
||||||
} else {
|
} else {
|
||||||
// this is case when there is no reply id . should not actually happen given if conditions
|
// 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;
|
return rootId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( rootId.length > 0) {
|
if( rootId.isNotEmpty) {
|
||||||
//printWarning("returning root id. no reply id found.");
|
//printWarning("returning root id. no reply id found.");
|
||||||
return rootId;
|
return rootId;
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String>? getTTags() {
|
List<String>? getTTags() {
|
||||||
List<String>? tTags = null;
|
List<String>? tTags;
|
||||||
|
|
||||||
for( int i = 0; i < tags.length; i++) {
|
for( int i = 0; i < tags.length; i++) {
|
||||||
List<String> tag = tags[i];
|
List<String> tag = tags[i];
|
||||||
@ -217,9 +217,7 @@ class EventData {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( tag[0] == 't') {
|
if( tag[0] == 't') {
|
||||||
if( tTags == null ) {
|
tTags ??= [];
|
||||||
tTags = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
tTags.add(tag[1]);
|
tTags.add(tag[1]);
|
||||||
}
|
}
|
||||||
@ -268,7 +266,7 @@ class EventData {
|
|||||||
try {
|
try {
|
||||||
verifyEvent(json);
|
verifyEvent(json);
|
||||||
|
|
||||||
} on Exception catch(e) {
|
} on Exception {
|
||||||
//printWarning("verify gave exception $e");
|
//printWarning("verify gave exception $e");
|
||||||
throw Exception("in Event constructor: sig verify gave exception");
|
throw Exception("in Event constructor: sig verify gave exception");
|
||||||
}
|
}
|
||||||
@ -364,7 +362,7 @@ class EventData {
|
|||||||
String author = getAuthorName(mentionedId);
|
String author = getAuthorName(mentionedId);
|
||||||
return "@$author";
|
return "@$author";
|
||||||
} else {
|
} else {
|
||||||
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData??null;
|
EventData? eventData = tempChildEventsMap[mentionedId]?.event.eventData;
|
||||||
if( eventData != null) {
|
if( eventData != null) {
|
||||||
String quotedAuthor = getAuthorName(eventData.pubkey);
|
String quotedAuthor = getAuthorName(eventData.pubkey);
|
||||||
String prefixId = mentionedId.substring(0, 3);
|
String prefixId = mentionedId.substring(0, 3);
|
||||||
@ -401,7 +399,7 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// replace the mentions, if any are found
|
// replace the mentions, if any are found
|
||||||
String mentionStr = "(\#\[[0-9]+\])";
|
String mentionStr = "(#[[0-9]+])";
|
||||||
RegExp mentionRegExp = RegExp(mentionStr);
|
RegExp mentionRegExp = RegExp(mentionStr);
|
||||||
content = content.replaceAllMapped(mentionRegExp, replaceMentions);
|
content = content.replaceAllMapped(mentionRegExp, replaceMentions);
|
||||||
return content;
|
return content;
|
||||||
@ -468,7 +466,7 @@ class EventData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isValidDirectMessage(this, acceptableKind: this.kind)) {
|
if(!isValidDirectMessage(this, acceptableKind: kind)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,19 +575,19 @@ class EventData {
|
|||||||
int ivIndex = content.indexOf("?iv=");
|
int ivIndex = content.indexOf("?iv=");
|
||||||
if( ivIndex > 0) {
|
if( ivIndex > 0) {
|
||||||
var iv = content.substring( ivIndex + 4, content.length);
|
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 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
|
if( pubkey == userPublicKey) { // if user themselve is the sender change public key used to decrypt
|
||||||
userKey = userPrivateKey;
|
userKey = userPrivateKey;
|
||||||
int numPtags = 0;
|
int numPtags = 0;
|
||||||
tags.forEach((tag) {
|
for (var tag in tags) {
|
||||||
if(tag[0] == "p" ) {
|
if(tag[0] == "p" ) {
|
||||||
otherUserPubKey = "02" + tag[1];
|
otherUserPubKey = "02${tag[1]}";
|
||||||
numPtags++;
|
numPtags++;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
// if there are more than one p tags, we don't know who its for
|
// if there are more than one p tags, we don't know who its for
|
||||||
if( numPtags != 1) {
|
if( numPtags != 1) {
|
||||||
if( gDebug >= 0) printInColor(" in translateAndExpand: got event $id with number of p tags != one : $numPtags . not decrypting", redColor);
|
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;
|
return decrypted;
|
||||||
} else {
|
} else {
|
||||||
if(gDebug > 0) print("Invalid content for dm, could not get ivIndex: $content");
|
if(gDebug > 0) print("Invalid content for dm, could not get ivIndex: $content");
|
||||||
@ -629,7 +627,7 @@ class EventData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var iv = content.substring( ivIndex + 4, content.length);
|
var iv = content.substring( ivIndex + 4, content.length);
|
||||||
var enc_str = content.substring(0, ivIndex);
|
var encStr = content.substring(0, ivIndex);
|
||||||
|
|
||||||
String channelId = getChannelIdForKind4x();
|
String channelId = getChannelIdForKind4x();
|
||||||
List<String> keys = [];
|
List<String> keys = [];
|
||||||
@ -642,9 +640,9 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String priKey = keys[0];
|
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;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,7 +655,7 @@ class EventData {
|
|||||||
// get first e tag, which should be the channel of which this is part of
|
// get first e tag, which should be the channel of which this is part of
|
||||||
for( int i = 0; i < eTags.length; i++) {
|
for( int i = 0; i < eTags.length; i++) {
|
||||||
List tag = eTags[i];
|
List tag = eTags[i];
|
||||||
if( tag.length >= 1) {
|
if( tag.isNotEmpty) {
|
||||||
return tag[0];
|
return tag[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -665,7 +663,7 @@ class EventData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getChannelIdForTTagRoom(String tagValue) {
|
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
|
// 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'
|
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||||
if( tempChildEventsMap != null )
|
if( tempChildEventsMap != null )
|
||||||
if(kind == 4)
|
if(kind == 4) {
|
||||||
translateAndDecryptKind4( tempChildEventsMap);
|
translateAndDecryptKind4( tempChildEventsMap);
|
||||||
else if ([1, 42].contains(kind)) {
|
} else if ([1, 42].contains(kind)) {
|
||||||
translateAndExpandMentions(tempChildEventsMap);
|
translateAndExpandMentions(tempChildEventsMap);
|
||||||
} else if ([142].contains(kind)) {
|
} else if ([142].contains(kind)) {
|
||||||
if( secretMessageIds != null && encryptedChannels != null) {
|
if( secretMessageIds != null && encryptedChannels != null) {
|
||||||
@ -752,7 +750,7 @@ class EventData {
|
|||||||
strToPrint += "█";
|
strToPrint += "█";
|
||||||
}
|
}
|
||||||
|
|
||||||
strToPrint += "${name}: ";
|
strToPrint += "$name: ";
|
||||||
const int typicalxLen = "|id: 82b5 , 12:04 AM Sep 19".length + 5; // not sure where 5 comes from
|
const int typicalxLen = "|id: 82b5 , 12:04 AM Sep 19".length + 5; // not sure where 5 comes from
|
||||||
List<dynamic> reactionString = getReactionStr(depth);
|
List<dynamic> reactionString = getReactionStr(depth);
|
||||||
//print("\n|${reactionString[0]}|\n ${ reactionString[1]}\n }");
|
//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
|
// 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;
|
int effectiveLastLineLen = lastLineLen - gSpacesPerDepth * depth - effectiveNameFieldLen - gNumLeftMarginSpaces;
|
||||||
if( contentShifted.length <= maxLineLen )
|
if( contentShifted.length <= maxLineLen ) {
|
||||||
effectiveLastLineLen = contentShifted.length;
|
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
|
// 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];
|
int colorStrLen = reactionString[0].length - reactionString[1];
|
||||||
@ -791,20 +790,20 @@ class EventData {
|
|||||||
if( (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen + idDateLikes.length ) <= gTextWidth) {
|
if( (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen + idDateLikes.length ) <= gTextWidth) {
|
||||||
idDateLikes = idDateLikes.padLeft((gTextWidth ) + colorStrLen - (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen));
|
idDateLikes = idDateLikes.padLeft((gTextWidth ) + colorStrLen - (gSpacesPerDepth * depth + effectiveNameFieldLen + effectiveLastLineLen));
|
||||||
} else {
|
} else {
|
||||||
idDateLikes = "\n" + idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen);
|
idDateLikes = "\n${idDateLikes.padLeft(gNumLeftMarginSpaces + gTextWidth + colorStrLen)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// print content and the dateslikes string
|
// print content and the dateslikes string
|
||||||
strToPrint += getStrInColor(contentShifted + idDateLikes + "\n", commentColor);
|
strToPrint += getStrInColor("$contentShifted$idDateLikes\n", commentColor);
|
||||||
stdout.write(strToPrint);
|
stdout.write(strToPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getAsLine(var tempChildEventsMap, Set<String>? secretMessageIds, List<Channel>? encryptedChannels, {int len = 20}) {
|
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'
|
// will only do decryption if its not been decrypted yet by looking at 'evaluatedContent'
|
||||||
if(kind == 4)
|
if(kind == 4) {
|
||||||
translateAndDecryptKind4( tempChildEventsMap);
|
translateAndDecryptKind4( tempChildEventsMap);
|
||||||
else if ([1, 42].contains(kind)) {
|
} else if ([1, 42].contains(kind)) {
|
||||||
translateAndExpandMentions(tempChildEventsMap);
|
translateAndExpandMentions(tempChildEventsMap);
|
||||||
} else if ([142].contains(kind)) {
|
} else if ([142].contains(kind)) {
|
||||||
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
|
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'
|
||||||
// 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);
|
translateAndDecryptKind4( tempChildEventsMap);
|
||||||
else if ([1, 42].contains(kind)) {
|
} else if ([1, 42].contains(kind)) {
|
||||||
translateAndExpandMentions(tempChildEventsMap);
|
translateAndExpandMentions(tempChildEventsMap);
|
||||||
} else if ([142].contains(kind)) {
|
} else if ([142].contains(kind)) {
|
||||||
if( tempChildEventsMap != null && secretMessageIds != null && encryptedChannels != null) {
|
if( secretMessageIds != null && encryptedChannels != null) {
|
||||||
//print('decrypting 14x in getStrForChannel');
|
//print('decrypting 14x in getStrForChannel');
|
||||||
translateAndDecrypt14x(secretMessageIds, encryptedChannels, tempChildEventsMap);
|
translateAndDecrypt14x(secretMessageIds, encryptedChannels, tempChildEventsMap);
|
||||||
}
|
}
|
||||||
@ -867,8 +866,9 @@ class EventData {
|
|||||||
tempEvaluatedContent = tempContent = content; // content would be changed so show that
|
tempEvaluatedContent = tempContent = content; // content would be changed so show that
|
||||||
}
|
}
|
||||||
|
|
||||||
if( tempEvaluatedContent=="")
|
if( tempEvaluatedContent=="") {
|
||||||
tempEvaluatedContent = tempContent;
|
tempEvaluatedContent = tempContent;
|
||||||
|
}
|
||||||
|
|
||||||
const int nameWidthDepth = 16~/gSpacesPerDepth; // how wide name will be in depth spaces
|
const int nameWidthDepth = 16~/gSpacesPerDepth; // how wide name will be in depth spaces
|
||||||
const int timeWidthDepth = 18~/gSpacesPerDepth;
|
const int timeWidthDepth = 18~/gSpacesPerDepth;
|
||||||
@ -900,13 +900,13 @@ class EventData {
|
|||||||
if( replyToEvent.eventData.evaluatedContent.length <= gReplyLengthPrinted){
|
if( replyToEvent.eventData.evaluatedContent.length <= gReplyLengthPrinted){
|
||||||
replyToPrint = replyToEvent.eventData.evaluatedContent;
|
replyToPrint = replyToEvent.eventData.evaluatedContent;
|
||||||
} else {
|
} 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 = 'In reply to:"${getAuthorName(replyToEvent.eventData.pubkey)}: $replyToPrint"';
|
||||||
strReplyTo = makeParagraphAtDepth(strReplyTo, finalContentDepthInSpaces + 6); // one extra for content
|
strReplyTo = makeParagraphAtDepth(strReplyTo, finalContentDepthInSpaces + 6); // one extra for content
|
||||||
|
|
||||||
// add reply to string to end of the content. How it will show:
|
// 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 {
|
} else {
|
||||||
@ -916,10 +916,10 @@ class EventData {
|
|||||||
String msgId = id.substring(0, 3).padLeft(gSpacesPerDepth~/2).padRight(gSpacesPerDepth) ;
|
String msgId = id.substring(0, 3).padLeft(gSpacesPerDepth~/2).padRight(gSpacesPerDepth) ;
|
||||||
|
|
||||||
if( isNotification) {
|
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;
|
isNotification = false;
|
||||||
} else {
|
} else {
|
||||||
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: " + contentShifted;
|
strToPrint = "${getDepthSpaces(depth-1)}$msgId $dateToPrint $nameToPrint: $contentShifted";
|
||||||
}
|
}
|
||||||
return strToPrint;
|
return strToPrint;
|
||||||
}
|
}
|
||||||
@ -956,8 +956,9 @@ class EventData {
|
|||||||
firstEntry = false;
|
firstEntry = false;
|
||||||
} else {
|
} else {
|
||||||
// this is normal printing of the reaction. only print for + for now
|
// this is normal printing of the reaction. only print for + for now
|
||||||
if( reactors[i][1] == "+")
|
if( reactors[i][1] == "+") {
|
||||||
authorName = getAuthorName(reactorId);
|
authorName = getAuthorName(reactorId);
|
||||||
|
}
|
||||||
reactorNames += comma + authorName;
|
reactorNames += comma + authorName;
|
||||||
len += (2 + authorName.length);
|
len += (2 + authorName.length);
|
||||||
firstEntry = false;
|
firstEntry = false;
|
||||||
@ -979,14 +980,14 @@ class EventData {
|
|||||||
|
|
||||||
// returns the last e tag as reply to event for kind 42 and 142 events
|
// returns the last e tag as reply to event for kind 42 and 142 events
|
||||||
Event? getReplyToChannelEvent(Map<String, Tree> tempChildEventsMap) {
|
Event? getReplyToChannelEvent(Map<String, Tree> tempChildEventsMap) {
|
||||||
switch (this.kind) {
|
switch (kind) {
|
||||||
case 42:
|
case 42:
|
||||||
case 142:
|
case 142:
|
||||||
for(int i = tags.length - 1; i >= 0; i--) {
|
for(int i = tags.length - 1; i >= 0; i--) {
|
||||||
List tag = tags[i];
|
List tag = tags[i];
|
||||||
if( tag[0] == 'e') {
|
if( tag[0] == 'e') {
|
||||||
String replyToEventId = tag[1];
|
String replyToEventId = tag[1];
|
||||||
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event)??null;
|
Event? eventInReplyTo = (gStore?.allChildEventsMap[replyToEventId]?.event);
|
||||||
if( eventInReplyTo != null) {
|
if( eventInReplyTo != null) {
|
||||||
// add 1 cause 42 can reply to or tag kind 1, and we'll show that kind 1
|
// 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)) {
|
if ( [1,42,142].contains( eventInReplyTo.eventData.kind)) {
|
||||||
@ -1039,14 +1040,15 @@ class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventData newEventData = EventData.fromJson(json[2]);
|
EventData newEventData = EventData.fromJson(json[2]);
|
||||||
if( !fromFile)
|
if( !fromFile) {
|
||||||
newEventData.isNotification = true;
|
newEventData.isNotification = true;
|
||||||
|
}
|
||||||
return Event(json[0] as String, json[1] as String, newEventData, [relay], d, fromFile );
|
return Event(json[0] as String, json[1] as String, newEventData, [relay], d, fromFile );
|
||||||
} on Exception catch(e) {
|
} on Exception catch(e) {
|
||||||
if( gDebug > 0) {
|
if( gDebug > 0) {
|
||||||
print("Could not create event. $e\nproblem str: $d\n");
|
print("Could not create event. $e\nproblem str: $d\n");
|
||||||
}
|
}
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,7 +1117,7 @@ bool processKind0Event(Event e) {
|
|||||||
String picture = "";
|
String picture = "";
|
||||||
String lud06 = "";
|
String lud06 = "";
|
||||||
String lud16 = "";
|
String lud16 = "";
|
||||||
String display_name = "";
|
String displayName = "";
|
||||||
String website = "";
|
String website = "";
|
||||||
String nip05 = "";
|
String nip05 = "";
|
||||||
|
|
||||||
@ -1126,7 +1128,7 @@ bool processKind0Event(Event e) {
|
|||||||
picture = json["picture"]??"";
|
picture = json["picture"]??"";
|
||||||
lud06 = json["lud06"]??"";
|
lud06 = json["lud06"]??"";
|
||||||
lud16 = json["lud16"]??"";
|
lud16 = json["lud16"]??"";
|
||||||
display_name = json["display_name"]??"";
|
displayName = json["display_name"]??"";
|
||||||
website = json["website"]??"";
|
website = json["website"]??"";
|
||||||
nip05 = json['nip05']??"";
|
nip05 = json['nip05']??"";
|
||||||
//String twitterId = json['twitter']??"";
|
//String twitterId = json['twitter']??"";
|
||||||
@ -1137,12 +1139,12 @@ bool processKind0Event(Event e) {
|
|||||||
|
|
||||||
bool newEntry = false, entryModified = false;
|
bool newEntry = false, entryModified = false;
|
||||||
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
||||||
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);
|
||||||
newEntry = true;;
|
newEntry = true;
|
||||||
} else {
|
} else {
|
||||||
int oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
|
int oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
|
||||||
if( oldTime < e.eventData.createdAt) {
|
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;
|
entryModified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1154,13 +1156,13 @@ bool processKind0Event(Event e) {
|
|||||||
bool localDebug = false; //e.eventData.pubkey == "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"? true: false;
|
bool localDebug = false; //e.eventData.pubkey == "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"? true: false;
|
||||||
|
|
||||||
if( newEntry || entryModified) {
|
if( newEntry || entryModified) {
|
||||||
if(nip05.length > 0) {
|
if(nip05.isNotEmpty) {
|
||||||
List<String> urlSplit = nip05.split("@");
|
List<String> urlSplit = nip05.split("@");
|
||||||
if( urlSplit.length == 2) {
|
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")) {
|
if( !urlNip05.startsWith("http")) {
|
||||||
urlNip05 = "http://"+ urlNip05;
|
urlNip05 = "http://$urlNip05";
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNip05Info(urlNip05)
|
fetchNip05Info(urlNip05)
|
||||||
@ -1178,7 +1180,7 @@ bool processKind0Event(Event e) {
|
|||||||
int oldTime = 0;
|
int oldTime = 0;
|
||||||
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
if( !gKindONames.containsKey(e.eventData.pubkey)) {
|
||||||
//printWarning("in response handing. creating user info");
|
//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 {
|
} else {
|
||||||
oldTime = gKindONames[e.eventData.pubkey]?.createdAt??0;
|
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}");
|
//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;
|
bool newEntry = false, entryModified = false;
|
||||||
if( !gKindONames.containsKey(newContactEvent.eventData.pubkey)) {
|
if( !gKindONames.containsKey(newContactEvent.eventData.pubkey)) {
|
||||||
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(null, null, null, null, null, null, null, null, null, newContactEvent, newContactEvent.eventData.createdAt);
|
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(null, null, null, null, null, null, null, null, null, newContactEvent, newContactEvent.eventData.createdAt);
|
||||||
newEntry = true;;
|
newEntry = true;
|
||||||
} else {
|
} else {
|
||||||
// if entry already exists, then check its old time and update only if we have a newer entry now
|
// 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;
|
int oldTime = gKindONames[newContactEvent.eventData.pubkey]?.createdAtKind3??0;
|
||||||
if( oldTime < newContactEvent.eventData.createdAt) {
|
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,
|
String? name = gKindONames[newContactEvent.eventData.pubkey]?.name,
|
||||||
about = gKindONames[newContactEvent.eventData.pubkey]?.about,
|
about = gKindONames[newContactEvent.eventData.pubkey]?.about,
|
||||||
picture = gKindONames[newContactEvent.eventData.pubkey]?.picture,
|
picture = gKindONames[newContactEvent.eventData.pubkey]?.picture,
|
||||||
lud06 = gKindONames[newContactEvent.eventData.pubkey]?.lud06,
|
lud06 = gKindONames[newContactEvent.eventData.pubkey]?.lud06,
|
||||||
lud16 = gKindONames[newContactEvent.eventData.pubkey]?.lud16,
|
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,
|
website = gKindONames[newContactEvent.eventData.pubkey]?.website,
|
||||||
nip05id = gKindONames[newContactEvent.eventData.pubkey]?.nip05Id??"";
|
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 );
|
gKindONames[newContactEvent.eventData.pubkey] = UserNameInfo(createdAt, name, about, picture, lud06, lud16, displayName, website, nip05id, newContactEvent, newContactEvent.eventData.createdAt );
|
||||||
entryModified = true;;
|
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
|
// 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}) {
|
String getAuthorName(String pubkey, {int maxDisplayLen = gMaxInteger, int pubkeyLenShown = 5}) {
|
||||||
|
|
||||||
if( gFollowList.length == 0) {
|
if( gFollowList.isEmpty) {
|
||||||
gFollowList = getFollows(userPublicKey);
|
gFollowList = getFollows(userPublicKey);
|
||||||
}
|
}
|
||||||
bool isFollow = gFollowList.contains(pubkey) && (pubkey != 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 maxLen(String pubkey) => pubkey.length > pubkeyLenShown? pubkey.substring(0,pubkeyLenShown) : pubkey.substring(0, pubkey.length);
|
||||||
String name = "";
|
String name = "";
|
||||||
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0)
|
if( gKindONames[pubkey]?.name == null || gKindONames[pubkey]?.name?.length == 0) {
|
||||||
name = maxLen(pubkey);
|
name = maxLen(pubkey);
|
||||||
else {
|
} else {
|
||||||
name = (gKindONames[pubkey]?.name)??maxLen(pubkey);
|
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)
|
// 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) {
|
Set<String> getPublicKeyFromName(String inquiredName) {
|
||||||
if( inquiredName.length < 1) {
|
if( inquiredName.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
Set<String> pubkeys = {};
|
Set<String> pubkeys = {};
|
||||||
@ -1337,8 +1339,9 @@ void printDepth(int d) {
|
|||||||
void printCenteredHeadline(displayName) {
|
void printCenteredHeadline(displayName) {
|
||||||
int numDashes = 10; // num of dashes on each side
|
int numDashes = 10; // num of dashes on each side
|
||||||
int startText = gNumLeftMarginSpaces + ( gTextWidth - (displayName.length + 2 * numDashes)) ~/ 2;
|
int startText = gNumLeftMarginSpaces + ( gTextWidth - (displayName.length + 2 * numDashes)) ~/ 2;
|
||||||
if( startText < 0)
|
if( startText < 0) {
|
||||||
startText = 0;
|
startText = 0;
|
||||||
|
}
|
||||||
|
|
||||||
String str = getNumSpaces(startText) + getNumDashes(numDashes) + displayName + getNumDashes(numDashes);
|
String str = getNumSpaces(startText) + getNumDashes(numDashes) + displayName + getNumDashes(numDashes);
|
||||||
print(str);
|
print(str);
|
||||||
@ -1369,7 +1372,7 @@ String makeParagraphAtDepth(String s, int depthInSpaces) {
|
|||||||
String line = listCulledLine[0];
|
String line = listCulledLine[0];
|
||||||
int lenReturned = listCulledLine[1] as int;
|
int lenReturned = listCulledLine[1] as int;
|
||||||
|
|
||||||
if( line.length == 0 || lenReturned == 0) break;
|
if( line.isEmpty || lenReturned == 0) break;
|
||||||
|
|
||||||
newString += line;
|
newString += line;
|
||||||
startIndex += lenReturned;
|
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.
|
// 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) {
|
List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesString, List<List<int>> urlRanges) {
|
||||||
|
|
||||||
if( startIndex >= s.length)
|
if( startIndex >= s.length) {
|
||||||
return ["", 0];
|
return ["", 0];
|
||||||
|
}
|
||||||
|
|
||||||
String line = ""; // is returned
|
String line = ""; // is returned
|
||||||
|
|
||||||
@ -1420,7 +1424,9 @@ List getLineWithMaxLen(String s, int startIndex, int lenPerLine, String spacesSt
|
|||||||
int i = line.length - 1;
|
int i = line.length - 1;
|
||||||
|
|
||||||
// find a whitespace character
|
// find a whitespace character
|
||||||
for( ; i > 0 && !isWordSeparater(line[i]); i--);
|
for( ; i > 0 && !isWordSeparater(line[i]); i--) {
|
||||||
|
{}
|
||||||
|
}
|
||||||
// for ended
|
// for ended
|
||||||
|
|
||||||
if( line.length - i < gMaxLenUnbrokenWord) {
|
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
|
// break the line here if its a word separator
|
||||||
if( isWordSeparater(line[i])) {
|
if( isWordSeparater(line[i])) {
|
||||||
int newLineStart = i + 1;
|
int newLineStart = i + 1;
|
||||||
if( line[i] != ' ')
|
if( line[i] != ' ') {
|
||||||
newLineStart = 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;
|
lineBroken = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1494,16 +1501,16 @@ bool isValidDirectMessage(EventData directMessageData, {int acceptableKind = 4})
|
|||||||
bool validUserMessage = false;
|
bool validUserMessage = false;
|
||||||
List<String> allPtags = [];
|
List<String> allPtags = [];
|
||||||
|
|
||||||
directMessageData.tags.forEach((tag) {
|
for (var tag in directMessageData.tags) {
|
||||||
if( tag.length < 2 ) {
|
if( tag.length < 2 ) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
if( tag[0] == "p" && tag[1].length == 64) { // basic length sanity test
|
if( tag[0] == "p" && tag[1].length == 64) { // basic length sanity test
|
||||||
allPtags.add(tag[1]);
|
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( 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
|
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() {
|
String getRandomPrivKey() {
|
||||||
FortunaRandom fr = FortunaRandom();
|
FortunaRandom fr = FortunaRandom();
|
||||||
final _sGen = Random.secure();;
|
final sGen = Random.secure();
|
||||||
fr.seed(KeyParameter(
|
fr.seed(KeyParameter(
|
||||||
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
|
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
|
||||||
|
|
||||||
BigInt randomNumber = fr.nextBigInteger(256);
|
BigInt randomNumber = fr.nextBigInteger(256);
|
||||||
String strKey = randomNumber.toRadixString(16);
|
String strKey = randomNumber.toRadixString(16);
|
||||||
if( strKey.length < 64) {
|
if( strKey.length < 64) {
|
||||||
int numZeros = 64 - strKey.length;
|
int numZeros = 64 - strKey.length;
|
||||||
for(int i = 0; i < numZeros; i++) {
|
for(int i = 0; i < numZeros; i++) {
|
||||||
strKey = "0" + strKey;
|
strKey = "0$strKey";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strKey;
|
return strKey;
|
||||||
@ -1568,7 +1575,7 @@ Uint8List myPrivateDecryptRaw( String privateString,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( byteSecret.isEmpty) {
|
if( byteSecret.isEmpty) {
|
||||||
byteSecret = Kepler.byteSecret(privateString, publicString);;
|
byteSecret = Kepler.byteSecret(privateString, publicString);
|
||||||
gMapByteSecret[publicString] = byteSecret;
|
gMapByteSecret[publicString] = byteSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1578,11 +1585,11 @@ Uint8List myPrivateDecryptRaw( String privateString,
|
|||||||
? convert.base64.decode(b64IV)
|
? convert.base64.decode(b64IV)
|
||||||
: Uint8List.fromList(secretIV[1]);
|
: Uint8List.fromList(secretIV[1]);
|
||||||
|
|
||||||
CipherParameters params = new PaddedBlockCipherParameters(
|
CipherParameters params = PaddedBlockCipherParameters(
|
||||||
new ParametersWithIV(new KeyParameter(key), iv), null);
|
ParametersWithIV(KeyParameter(key), iv), null);
|
||||||
|
|
||||||
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
|
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
|
||||||
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
|
PKCS7Padding(), CBCBlockCipher(AESEngine()));
|
||||||
|
|
||||||
cipherImpl.init(false,
|
cipherImpl.init(false,
|
||||||
params as PaddedBlockCipherParameters<CipherParameters?,
|
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
|
// generate iv https://stackoverflow.com/questions/63630661/aes-engine-not-initialised-with-pointycastle-securerandom
|
||||||
FortunaRandom fr = FortunaRandom();
|
FortunaRandom fr = FortunaRandom();
|
||||||
final _sGen = Random.secure();;
|
final sGen = Random.secure();
|
||||||
fr.seed(KeyParameter(
|
fr.seed(KeyParameter(
|
||||||
Uint8List.fromList(List.generate(32, (_) => _sGen.nextInt(255)))));
|
Uint8List.fromList(List.generate(32, (_) => sGen.nextInt(255)))));
|
||||||
final iv = fr.nextBytes(16);
|
final iv = fr.nextBytes(16);
|
||||||
|
|
||||||
CipherParameters params = new PaddedBlockCipherParameters(
|
CipherParameters params = PaddedBlockCipherParameters(
|
||||||
new ParametersWithIV(new KeyParameter(key), iv), null);
|
ParametersWithIV(KeyParameter(key), iv), null);
|
||||||
|
|
||||||
PaddedBlockCipherImpl cipherImpl = new PaddedBlockCipherImpl(
|
PaddedBlockCipherImpl cipherImpl = PaddedBlockCipherImpl(
|
||||||
new PKCS7Padding(), new CBCBlockCipher(new AESEngine()));
|
PKCS7Padding(), CBCBlockCipher(AESEngine()));
|
||||||
|
|
||||||
cipherImpl.init(true, // means to encrypt
|
cipherImpl.init(true, // means to encrypt
|
||||||
params as PaddedBlockCipherParameters<CipherParameters?,
|
params as PaddedBlockCipherParameters<CipherParameters?,
|
||||||
@ -1647,16 +1654,14 @@ String myEncryptRaw( String privateString,
|
|||||||
offset += cipherImpl.doFinal(uintInputText, offset, outputEncodedText, offset);
|
offset += cipherImpl.doFinal(uintInputText, offset, outputEncodedText, offset);
|
||||||
final Uint8List finalEncodedText = outputEncodedText.sublist(0, 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);
|
String outputPlainText = convert.base64.encode(finalEncodedText);
|
||||||
outputPlainText = outputPlainText + "?iv=" + stringIv;
|
outputPlainText = "$outputPlainText?iv=$stringIv";
|
||||||
return outputPlainText;
|
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
|
||||||
* 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.
|
||||||
* new events from relays are written to file.
|
|
||||||
*/
|
|
||||||
Set<Event> readEventsFromFile(String filename) {
|
Set<Event> readEventsFromFile(String filename) {
|
||||||
Set<Event> events = {};
|
Set<Event> events = {};
|
||||||
final File file = File(filename);
|
final File file = File(filename);
|
||||||
@ -1709,7 +1714,7 @@ String myGetPublicKey(String prikey) {
|
|||||||
if( pubkey.length < 64) {
|
if( pubkey.length < 64) {
|
||||||
int numZeros = 64 - pubkey.length;
|
int numZeros = 64 - pubkey.length;
|
||||||
for(int i = 0; i < numZeros; i++) {
|
for(int i = 0; i < numZeros; i++) {
|
||||||
pubkey = "0" + pubkey;
|
pubkey = "0$pubkey";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pubkey;
|
return pubkey;
|
||||||
|
@ -63,7 +63,7 @@ class Relays {
|
|||||||
|
|
||||||
void getKindEvents(List<int> kind, String relayUrl, int limit, int sinceWhen) {
|
void getKindEvents(List<int> kind, String relayUrl, int limit, int sinceWhen) {
|
||||||
kind.toString();
|
kind.toString();
|
||||||
String subscriptionId = "kind_" + kind.toString() + "_" + relayUrl.substring(6);
|
String subscriptionId = "kind_${kind}_${relayUrl.substring(6)}";
|
||||||
String request = getKindRequest(subscriptionId, kind, limit, sinceWhen);
|
String request = getKindRequest(subscriptionId, kind, limit, sinceWhen);
|
||||||
|
|
||||||
sendRequest(relayUrl, request);
|
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)) {
|
if( relays.containsKey(relayUrl)) {
|
||||||
Set<String>? users = relays[relayUrl]?.users;
|
Set<String>? users = relays[relayUrl]?.users;
|
||||||
if( users != null) { // get a user only if it has not already been requested
|
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
|
// following is too restrictive casuse changed sinceWhen is not considered. TODO improve it
|
||||||
bool alreadyRecevied = false;
|
bool alreadyRecevied = false;
|
||||||
users.forEach((user) {
|
for (var user in users) {
|
||||||
if( user == publicKey) {
|
if( user == publicKey) {
|
||||||
alreadyRecevied = true;
|
alreadyRecevied = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if( alreadyRecevied)
|
if( alreadyRecevied) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
users.add(publicKey);
|
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);
|
String request = getMentionRequest(subscriptionId, ids, limit, sinceWhen, tagToGet);
|
||||||
sendRequest(relayUrl, request);
|
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) {
|
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);
|
String request = getIdAndMentionRequest(subscriptionId, ids, limit, idSinceWhen, mentionSinceWhen, tagToGet, idType);
|
||||||
sendRequest(relayUrl, request);
|
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
|
* @connect Connect to given relay and get all events for multiple users/publicKey and insert the
|
||||||
* received events in the given List<Event>
|
* 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();
|
Set<String> setPublicKeys = publicKeys.toSet();
|
||||||
|
|
||||||
if( relays.containsKey(relayUrl)) {
|
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);
|
String request = getMultiUserRequest( subscriptionId, setPublicKeys, limit, sinceWhen, kind);
|
||||||
sendRequest(relayUrl, request);
|
sendRequest(relayUrl, request);
|
||||||
}
|
}
|
||||||
@ -215,7 +216,7 @@ class Relays {
|
|||||||
print('WebSocketChannelException exception for relay $relayUrl');
|
print('WebSocketChannelException exception for relay $relayUrl');
|
||||||
return; // is presently not used/called
|
return; // is presently not used/called
|
||||||
}
|
}
|
||||||
on Exception catch(ex) {
|
on Exception {
|
||||||
printWarning("Invalid event\n");
|
printWarning("Invalid event\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,9 +262,9 @@ void getContactFeed(Set<String> relayUrls, Set<String> setContacts, int numEvent
|
|||||||
groupContacts.add(contacts[i + j]);
|
groupContacts.add(contacts[i + j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
relayUrls.forEach((relayUrl) {
|
for (var relayUrl in relayUrls) {
|
||||||
relays.getMultiUserEvents(relayUrl, groupContacts, numEventsToGet, sinceWhen);
|
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) {
|
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);
|
relays.getUserEvents(serverUrl, publicKey, numUserEvents, sinceWhen);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getMentionEvents(Set<String> serverUrls, Set<String> ids, int numUserEvents, int sinceWhen, String tagToGet) {
|
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);
|
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) {
|
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);
|
relays.getIdAndMentionEvents(serverUrl, ids, numUserEvents, idSinceWhen, mentionSinceWhen, tagToGet, idType);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getKindEvents(List<int> kind, Set<String> serverUrls, int limit, int sinceWhen) {
|
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);
|
relays.getKindEvents(kind, serverUrl, limit, sinceWhen);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getMultiUserEvents(Set<String> serverUrls, Set<String> setPublicKeys, int numUserEvents, int sinceWhen, [Set<int>? kind]) {
|
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
|
// send request for specific events whose id's are passed as list eventIds
|
||||||
void sendEventsRequest(Set<String> serverUrls, Set<String> eventIds) {
|
void sendEventsRequest(Set<String> serverUrls, Set<String> eventIds) {
|
||||||
if( eventIds.length == 0)
|
if( eventIds.isEmpty) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);;
|
String eventIdsStr = getCommaSeparatedQuotedStrs(eventIds);
|
||||||
|
|
||||||
String getEventRequest = '["REQ","event_${eventIds.length}",{"ids":[$eventIdsStr]}]';
|
String getEventRequest = '["REQ","event_${eventIds.length}",{"ids":[$eventIdsStr]}]';
|
||||||
if( gDebug > 0) log.info("sending $getEventRequest");
|
if( gDebug > 0) log.info("sending $getEventRequest");
|
||||||
|
|
||||||
serverUrls.forEach((url) {
|
for (var url in serverUrls) {
|
||||||
relays.sendRequest(url, getEventRequest);
|
relays.sendRequest(url, getEventRequest);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRequest(Set<String> serverUrls, request) {
|
void sendRequest(Set<String> serverUrls, request) {
|
||||||
serverUrls.forEach((url) {
|
for (var url in serverUrls) {
|
||||||
relays.sendRequest(url, request);
|
relays.sendRequest(url, request);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Event> getRecievedEvents() {
|
Set<Event> getRecievedEvents() {
|
||||||
@ -343,7 +345,7 @@ void clearEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setRelaysIntialEvents(Set<Event> eventsFromFile) {
|
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;
|
relays.rEvents = eventsFromFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +241,9 @@ Map<String, String> pubkeyColor = { '0': magentaColor, '1': brightMagentaColor,
|
|||||||
};
|
};
|
||||||
|
|
||||||
String getNameColor( String pubkey) {
|
String getNameColor( String pubkey) {
|
||||||
if( pubkey.length == 0)
|
if( pubkey.isEmpty) {
|
||||||
return brightMagentaColor;
|
return brightMagentaColor;
|
||||||
|
}
|
||||||
|
|
||||||
String firstChar = pubkey.substring(0, 1).toLowerCase();
|
String firstChar = pubkey.substring(0, 1).toLowerCase();
|
||||||
return pubkeyColor[firstChar]??brightMagentaColor;
|
return pubkeyColor[firstChar]??brightMagentaColor;
|
||||||
@ -408,10 +409,11 @@ List<String> lines = intro.split("\n");
|
|||||||
|
|
||||||
var terminalColumns = gDefaultTextWidth;
|
var terminalColumns = gDefaultTextWidth;
|
||||||
|
|
||||||
if( stdout.hasTerminal )
|
if( stdout.hasTerminal ) {
|
||||||
terminalColumns = stdout.terminalColumns;
|
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);
|
print(gUsage);
|
||||||
}
|
}
|
||||||
void printVersion() {
|
void printVersion() {
|
||||||
print("$version");
|
print(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
269
lib/tree_ds.dart
269
lib/tree_ds.dart
@ -1,4 +1,3 @@
|
|||||||
import 'dart:ffi';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:nostr_console/event_ds.dart';
|
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/utils.dart';
|
||||||
import 'package:nostr_console/settings.dart';
|
import 'package:nostr_console/settings.dart';
|
||||||
import 'package:nostr_console/user.dart';
|
import 'package:nostr_console/user.dart';
|
||||||
import 'dart:math'; // for Point
|
// for Point
|
||||||
|
|
||||||
|
|
||||||
typedef fTreeSelector = bool Function(Tree a);
|
typedef fTreeSelector = bool Function(Tree a);
|
||||||
@ -16,7 +15,7 @@ typedef fRoomSelector = bool Function(ScrollableMessages room);
|
|||||||
|
|
||||||
typedef fvisitorMarkNotifications = void Function(Event e);
|
typedef fvisitorMarkNotifications = void Function(Event e);
|
||||||
|
|
||||||
Store? gStore = null;
|
Store? gStore;
|
||||||
|
|
||||||
// only show in which user is involved
|
// only show in which user is involved
|
||||||
bool selectorTrees_selfPosts(Tree t) {
|
bool selectorTrees_selfPosts(Tree t) {
|
||||||
@ -37,7 +36,7 @@ bool userInvolved(String pubkey, Event e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( gReactions.containsKey(e.eventData.id)) {
|
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) {
|
if( reactors != null) {
|
||||||
for( var reactor in reactors) {
|
for( var reactor in reactors) {
|
||||||
String reactorPubkey = reactor[0];
|
String reactorPubkey = reactor[0];
|
||||||
@ -91,7 +90,7 @@ bool followsInvolved(Event e, Event? contactEvent) {
|
|||||||
|
|
||||||
// check if any of the contact liked it
|
// check if any of the contact liked it
|
||||||
if( gReactions.containsKey(e.eventData.id)) {
|
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) {
|
if( reactors != null) {
|
||||||
for( var reactor in reactors) {
|
for( var reactor in reactors) {
|
||||||
String reactorPubkey = reactor[0];
|
String reactorPubkey = reactor[0];
|
||||||
@ -147,20 +146,20 @@ bool showAllRooms (ScrollableMessages room) => selectorShowAllRooms(room);
|
|||||||
|
|
||||||
int getLatestMessageTime(ScrollableMessages channel) {
|
int getLatestMessageTime(ScrollableMessages channel) {
|
||||||
|
|
||||||
List<String> _messageIds = channel.messageIds;
|
List<String> messageIds = channel.messageIds;
|
||||||
if(gStore == null) {
|
if(gStore == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_messageIds.length == 0) {
|
if(messageIds.isEmpty) {
|
||||||
int createdAt = channel.createdAt;
|
int createdAt = channel.createdAt;
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int latest = 0;
|
int latest = 0;
|
||||||
for(int i = 0; i < _messageIds.length; i++) {
|
for(int i = 0; i < messageIds.length; i++) {
|
||||||
if( gStore != null) {
|
if( gStore != null) {
|
||||||
Tree? tree = (gStore?.allChildEventsMap[_messageIds[i]] );
|
Tree? tree = (gStore?.allChildEventsMap[messageIds[i]] );
|
||||||
if( tree != null) {
|
if( tree != null) {
|
||||||
EventData ed = tree.event.eventData;
|
EventData ed = tree.event.eventData;
|
||||||
if( ed.createdAt > latest) {
|
if( ed.createdAt > latest) {
|
||||||
@ -193,8 +192,9 @@ DirectMessageRoom? getDirectRoom(List<DirectMessageRoom> rooms, String otherPubk
|
|||||||
|
|
||||||
int scrollableCompareTo(ScrollableMessages a, ScrollableMessages b) {
|
int scrollableCompareTo(ScrollableMessages a, ScrollableMessages b) {
|
||||||
|
|
||||||
if( gStore == null)
|
if( gStore == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int otherLatest = getLatestMessageTime(b);
|
int otherLatest = getLatestMessageTime(b);
|
||||||
int thisLatest = getLatestMessageTime(a);
|
int thisLatest = getLatestMessageTime(a);
|
||||||
@ -228,12 +228,12 @@ class ScrollableMessages {
|
|||||||
int eventTime = (tempChildEventsMap[messageIds[i]]?.event.eventData.createdAt??0);
|
int eventTime = (tempChildEventsMap[messageIds[i]]?.event.eventData.createdAt??0);
|
||||||
if( newEventTime < eventTime) {
|
if( newEventTime < eventTime) {
|
||||||
// shift current i and rest one to the right, and put event Time here
|
// 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);
|
messageIds.insert(i, messageId);
|
||||||
return;
|
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
|
// insert at end
|
||||||
messageIds.add(messageId);
|
messageIds.add(messageId);
|
||||||
@ -273,15 +273,16 @@ class ScrollableMessages {
|
|||||||
if( messageIds.length > gNumChannelMessagesToShow) {
|
if( messageIds.length > gNumChannelMessagesToShow) {
|
||||||
print("\n");
|
print("\n");
|
||||||
printDepth(0);
|
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);
|
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() {
|
bool selectorNotifications() {
|
||||||
if( gStore == null)
|
if( gStore == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < messageIds.length; i++) {
|
for(int i = 0; i < messageIds.length; i++) {
|
||||||
Event? e = gStore?.allChildEventsMap[messageIds[i]]?.event;
|
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
|
Set<String> participants; // pubkey of all participants - only for encrypted channels
|
||||||
String creatorPubkey; // creator of the channel, if event is known
|
String creatorPubkey; // creator of the channel, if event is known
|
||||||
|
|
||||||
|
@override
|
||||||
enumRoomType roomType;
|
enumRoomType roomType;
|
||||||
|
|
||||||
Channel(this.channelId, this.internalChatRoomName, this.about, this.picture, List<String> messageIds, this.participants, this.lastUpdated, this.roomType, [this.creatorPubkey=""] ) :
|
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;
|
return internalChatRoomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set chatRoomName(String newName){
|
set chatRoomName(String newName){
|
||||||
internalChatRoomName = newName;
|
internalChatRoomName = newName;
|
||||||
super.topHeader = "Channel Name: $newName (Id: $channelId)";
|
super.topHeader = "Channel Name: $newName (Id: $channelId)";
|
||||||
}
|
}
|
||||||
@ -366,11 +368,11 @@ class Channel extends ScrollableMessages {
|
|||||||
// represents direct chat of kind 4
|
// represents direct chat of kind 4
|
||||||
class DirectMessageRoom extends ScrollableMessages{
|
class DirectMessageRoom extends ScrollableMessages{
|
||||||
String otherPubkey; // id of user this DM is happening
|
String otherPubkey; // id of user this DM is happening
|
||||||
|
@override
|
||||||
int createdAt;
|
int createdAt;
|
||||||
|
|
||||||
DirectMessageRoom(this.otherPubkey, List<String> messageIds, this.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() {
|
String getChannelId() {
|
||||||
return otherPubkey;
|
return otherPubkey;
|
||||||
@ -404,7 +406,7 @@ class Tree {
|
|||||||
store = s;
|
store = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************/
|
/// ********************************************************************************************************************************
|
||||||
/* The main print tree function. Calls the reeSelector() for every node and prints it( and its children), only if it returns true.
|
/* 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 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>
|
* 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> printTree(int depth, DateTime newerThan, bool topPost, [int countPrinted = 0, int maxToPrint = gMaxEventsInThreadPrinted]) {
|
||||||
List<int> ret = [0,0,0];
|
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;
|
ret[2] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +505,7 @@ class Tree {
|
|||||||
if( pubkeys.contains(event.eventData.pubkey) && gReactions.containsKey(event.eventData.id)) {
|
if( pubkeys.contains(event.eventData.pubkey) && gReactions.containsKey(event.eventData.id)) {
|
||||||
List<List<String>>? reactions = gReactions[event.eventData.id];
|
List<List<String>>? reactions = gReactions[event.eventData.id];
|
||||||
if( reactions != null) {
|
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 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);
|
Set<String> reactorPubkeys = getReactorPubkeys(event.eventData.id);
|
||||||
event.eventData.newLikes = reactorPubkeys;
|
event.eventData.newLikes = reactorPubkeys;
|
||||||
@ -517,18 +519,20 @@ class Tree {
|
|||||||
Set<String> pplTagged = pTags.toSet().intersection(pubkeys);
|
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
|
// 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;
|
event.eventData.isNotification = isMentioned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there are any replies from other people to an event made by someone in list
|
// 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++ ) {
|
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 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;
|
childMatches = child.event.eventData.isNotification = true;
|
||||||
});
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,8 +601,9 @@ class Tree {
|
|||||||
if( reactions != null) {
|
if( reactions != null) {
|
||||||
for( int i = 0; i < reactions.length; i++) {
|
for( int i = 0; i < reactions.length; i++) {
|
||||||
if( pubkeys.contains(reactions[i][0]) ) {
|
if( pubkeys.contains(reactions[i][0]) ) {
|
||||||
if( enableNotifications)
|
if( enableNotifications) {
|
||||||
event.eventData.newLikes.add(reactions[i][0]);
|
event.eventData.newLikes.add(reactions[i][0]);
|
||||||
|
}
|
||||||
hasReacted = true;
|
hasReacted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -617,8 +622,9 @@ class Tree {
|
|||||||
|
|
||||||
// if event is by user(s)
|
// if event is by user(s)
|
||||||
if( pubkeys.contains(event.eventData.pubkey)) {
|
if( pubkeys.contains(event.eventData.pubkey)) {
|
||||||
if( enableNotifications)
|
if( enableNotifications) {
|
||||||
event.eventData.isNotification = true;
|
event.eventData.isNotification = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if( hasReacted || childMatches) {
|
if( hasReacted || childMatches) {
|
||||||
@ -636,8 +642,9 @@ class Tree {
|
|||||||
|
|
||||||
// if event is by user(s)
|
// if event is by user(s)
|
||||||
if( pubkeys.contains(event.eventData.pubkey)) {
|
if( pubkeys.contains(event.eventData.pubkey)) {
|
||||||
if( enableNotifications)
|
if( enableNotifications) {
|
||||||
event.eventData.isNotification = true;
|
event.eventData.isNotification = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,7 +728,7 @@ class Tree {
|
|||||||
bool treeSelector_hasNotifications() {
|
bool treeSelector_hasNotifications() {
|
||||||
|
|
||||||
bool hasNotifications = false;
|
bool hasNotifications = false;
|
||||||
if( event.eventData.isNotification || event.eventData.newLikes.length > 0) {
|
if( event.eventData.isNotification || event.eventData.newLikes.isNotEmpty) {
|
||||||
hasNotifications = true;
|
hasNotifications = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,7 +756,7 @@ class Tree {
|
|||||||
count = 1;
|
count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( event.eventData.newLikes.length > 0) {
|
if( event.eventData.newLikes.isNotEmpty) {
|
||||||
event.eventData.newLikes = {};
|
event.eventData.newLikes = {};
|
||||||
count = 1;
|
count = 1;
|
||||||
}
|
}
|
||||||
@ -777,7 +784,7 @@ class Tree {
|
|||||||
} // end count()
|
} // end count()
|
||||||
} // end Tree
|
} // 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)
|
* 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
|
* 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) {
|
static void addTTagEventInChannel(EventData eventData, List<Channel> rooms, Map<String, Tree> tempChildEventsMap) {
|
||||||
|
|
||||||
List<String>? tTags = eventData.getTTags();
|
List<String>? tTags = eventData.getTTags();
|
||||||
if( tTags != null && tTags.length > 0) {
|
if( tTags != null && tTags.isNotEmpty) {
|
||||||
for( int i = 0; i < tTags.length; i++) {
|
for( int i = 0; i < tTags.length; i++) {
|
||||||
String chatRoomId = eventData.getChannelIdForTTagRoom(tTags[i]);
|
String chatRoomId = eventData.getChannelIdForTTagRoom(tTags[i]);
|
||||||
Channel? channel = getChannel(rooms, chatRoomId);
|
Channel? channel = getChannel(rooms, chatRoomId);
|
||||||
@ -949,11 +956,9 @@ class Store {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Will create a entry in encryptedChannels ( if one does not already exist)
|
||||||
* Will create a entry in encryptedChannels ( if one does not already exist)
|
/// Returns id of channel if one is created, null otherwise.
|
||||||
* Returns id of channel if one is created, null otherwise.
|
///
|
||||||
*
|
|
||||||
*/
|
|
||||||
static String? createEncryptedRoomFromInvite( List<Channel> encryptedChannels, Map<String, Tree> tempChildEventsMap, Event eventSecretMessage) {
|
static String? createEncryptedRoomFromInvite( List<Channel> encryptedChannels, Map<String, Tree> tempChildEventsMap, Event eventSecretMessage) {
|
||||||
|
|
||||||
String? temp140Id = getEncryptedChannelIdFromSecretMessage( eventSecretMessage);
|
String? temp140Id = getEncryptedChannelIdFromSecretMessage( eventSecretMessage);
|
||||||
@ -969,7 +974,7 @@ class Store {
|
|||||||
if( event140 != null) {
|
if( event140 != null) {
|
||||||
|
|
||||||
Set<String> participants = {};
|
Set<String> participants = {};
|
||||||
event140.eventData.pTags.forEach((element) { participants.add(element);});
|
for (var element in event140.eventData.pTags) { participants.add(element);}
|
||||||
|
|
||||||
String chatRoomId = event140Id;
|
String chatRoomId = event140Id;
|
||||||
try {
|
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)
|
// 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 = {};
|
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);
|
Channel? channel = getChannel(encryptedChannels, event14x.eventData.id);
|
||||||
|
|
||||||
dynamic json = jsonDecode(event14x.eventData.content);
|
dynamic json = jsonDecode(event14x.eventData.content);
|
||||||
@ -1042,7 +1047,7 @@ class Store {
|
|||||||
|
|
||||||
case 141:
|
case 141:
|
||||||
Set<String> participants = {};
|
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();
|
String chatRoomId = event14x.eventData.getChannelIdForKind4x();
|
||||||
if( chatRoomId.length != 64) {
|
if( chatRoomId.length != 64) {
|
||||||
@ -1093,7 +1098,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// could not get channel id of message.
|
// 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;
|
break;
|
||||||
|
|
||||||
@ -1158,7 +1163,7 @@ class Store {
|
|||||||
directRooms.add( newDirectRoom);
|
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.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 {
|
} else {
|
||||||
if( gDebug > 0) print("Could not get chat room id for event ${ce.eventData.id} sender pubkey = ${ce.eventData.pubkey}.");
|
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.
|
// @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)
|
// 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) {
|
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
|
// create a map tempChildEventsMap from list of events, key is eventId and value is event itself
|
||||||
Map<String, Tree> tempChildEventsMap = {};
|
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)
|
// 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)) {
|
if( typesInEventMap.contains(event.eventData.kind)) {
|
||||||
tempChildEventsMap[event.eventData.id] = Tree.withoutStore( event, []);
|
tempChildEventsMap[event.eventData.id] = Tree.withoutStore( event, []);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
processDeleteEvents(tempChildEventsMap); // handle returned values perhaps later
|
processDeleteEvents(tempChildEventsMap); // handle returned values perhaps later
|
||||||
processReactions(events, tempChildEventsMap);
|
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 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];
|
String reactedToId = tree.event.eventData.eTags.last[0];
|
||||||
if( !tempChildEventsMap.containsKey(reactedToId) && tree.event.eventData.createdAt > getSecondsDaysAgo(3)) {
|
if( !tempChildEventsMap.containsKey(reactedToId) && tree.event.eventData.createdAt > getSecondsDaysAgo(3)) {
|
||||||
//print("liked event not found in store.");
|
//print("liked event not found in store.");
|
||||||
@ -1353,7 +1358,7 @@ class Store {
|
|||||||
// allEncryptedGroupInviteIds has been created above
|
// allEncryptedGroupInviteIds has been created above
|
||||||
// now create encrypted rooms from that list which are just for the current user
|
// now create encrypted rooms from that list which are just for the current user
|
||||||
Set<String> usersEncryptedChannelIds = {};
|
Set<String> usersEncryptedChannelIds = {};
|
||||||
allEncryptedGroupInviteIds.forEach((secretEventId) {
|
for (var secretEventId in allEncryptedGroupInviteIds) {
|
||||||
Event? secretEvent = tempChildEventsMap[secretEventId]?.event;
|
Event? secretEvent = tempChildEventsMap[secretEventId]?.event;
|
||||||
|
|
||||||
if( secretEvent != null) {
|
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
|
usersEncryptedChannelIds.add(newEncryptedChannelId); // is later used so a request can be sent to fetch events related to this room
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
tempChildEventsMap.forEach((newEventId, tree) {
|
tempChildEventsMap.forEach((newEventId, tree) {
|
||||||
int eKind = tree.event.eventData.kind;
|
int eKind = tree.event.eventData.kind;
|
||||||
@ -1391,7 +1396,7 @@ class Store {
|
|||||||
return Store( topLevelTrees, tempChildEventsMap, tempWithoutParent, channels, encryptedChannels, tempDirectRooms, allEncryptedGroupInviteIds);
|
return Store( topLevelTrees, tempChildEventsMap, tempWithoutParent, channels, encryptedChannels, tempDirectRooms, allEncryptedGroupInviteIds);
|
||||||
} // end fromEvents()
|
} // end fromEvents()
|
||||||
|
|
||||||
/***********************************************************************************************************************************/
|
/// ********************************************************************************************************************************
|
||||||
/* @processIncomingEvent inserts the relevant events into the tree and otherwise processes likes, delete events etc.
|
/* @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.
|
* 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 = {};
|
Set<String> dummyEventIds = {};
|
||||||
|
|
||||||
// add the event to the main event store thats allChildEventsMap
|
// 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) {
|
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
|
if( allChildEventsMap.containsKey(newEvent.eventData.id)) {// don't process if the event is already present in the map
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ignore bots
|
//ignore bots
|
||||||
if( [4, 42, 142].contains( newEvent.eventData.kind ) && gBots.contains(newEvent.eventData.pubkey)) {
|
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
|
// 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( newEvent.eventData.kind == 7) {
|
||||||
if( processReaction(newEvent, allChildEventsMap) == "") {
|
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");
|
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) {
|
if( newEvent.eventData.kind == 5) {
|
||||||
processDeleteEvent(allChildEventsMap, newEvent);
|
processDeleteEvent(allChildEventsMap, newEvent);
|
||||||
if(gDebug > 0) print("In insertEvents: For new deleteion event ${newEvent.eventData.id} could not process it.");
|
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( 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
|
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
|
// 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) ) {
|
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
|
// 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;
|
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.
|
// 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
|
// 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}");
|
if( gDebug >= 0 && newEvent.eventData.id == gCheckEventId) log.info("In processIncoming: Replaced old dummy event of id: ${newEvent.eventData.id}");
|
||||||
tree.event = newEvent;
|
tree.event = newEvent;
|
||||||
allChildEventsMap[tree.event.eventData.id] = tree;
|
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)
|
// 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);
|
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.
|
// 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];
|
Tree? newTree = allChildEventsMap[newId];
|
||||||
if( newTree != null) { // this should return true because we just inserted this event in the allEvents in block above
|
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);
|
topPosts.add(dummyTopNode);
|
||||||
|
|
||||||
// add it to list to fetch it from relays
|
// add it to list to fetch it from relays
|
||||||
if( parentId.length == 64)
|
if( parentId.length == 64) {
|
||||||
dummyEventIds.add(parentId);
|
dummyEventIds.add(parentId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now process case where there is a tag which should put this kind 1 message in a channel
|
// 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");
|
String? location = newTree.event.eventData.getSpecificTag("location");
|
||||||
if( location != null && 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
|
// 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();
|
List<String>? tTags = newTree.event.eventData.getTTags();
|
||||||
if( tTags != null && tTags != "") {
|
if( tTags != null && tTags != "") {
|
||||||
addTTagEventInChannel(newTree.event.eventData, this.channels, allChildEventsMap);
|
addTTagEventInChannel(newTree.event.eventData, channels, allChildEventsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1562,19 +1569,19 @@ class Store {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// get dummy events
|
// get dummy events
|
||||||
sendEventsRequest(gListRelayUrls, dummyEventIds);
|
sendEventsRequest(gListRelayUrls, dummyEventIds);
|
||||||
|
|
||||||
int totalTreeSize = 0;
|
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("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>"} ");
|
if(gDebug > 0) print("Returning ${newEventIdsSet.length} new notification-type events, which are ${newEventIdsSet.length < 10 ? newEventIdsSet: " <had more than 10 elements>"} ");
|
||||||
return newEventIdsSet;
|
return newEventIdsSet;
|
||||||
} // end insertEvents()
|
} // end insertEvents()
|
||||||
|
|
||||||
/***********************************************************************************************************************************/
|
/// ********************************************************************************************************************************
|
||||||
/*
|
/*
|
||||||
* @printNotifications Add the given events to the Tree, and print the events as notifications
|
* @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
|
* 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
|
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];
|
Tree ?t = allChildEventsMap[eventID];
|
||||||
if( t == null) {
|
if( t == null) {
|
||||||
// ignore if not in Tree. Should ideally not happen. TODO write warning otherwise
|
// 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");
|
if( gDebug > 0) print("In printNotifications: Could not find event $eventID in tree");
|
||||||
return;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if( isRelevantForNotification(t)) {
|
if( isRelevantForNotification(t)) {
|
||||||
switch(t.event.eventData.kind) {
|
switch(t.event.eventData.kind) {
|
||||||
@ -1643,7 +1650,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// remove duplicate top trees
|
// remove duplicate top trees
|
||||||
Set ids = {};
|
Set ids = {};
|
||||||
@ -1655,7 +1662,7 @@ class Store {
|
|||||||
gFollowList = getFollows(userPublicKey);
|
gFollowList = getFollows(userPublicKey);
|
||||||
|
|
||||||
List<int> ret = [0,0,0];
|
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);
|
bool selectorTrees_followActionsWithNotifications (Tree t) => t.treeSelectorUserPostAndLike(getFollows( userPublicKey), enableNotifications: true);
|
||||||
if( selectorTrees_followActionsWithNotifications(t)) {
|
if( selectorTrees_followActionsWithNotifications(t)) {
|
||||||
List<int> temp = Store.printTopPost(t, 0, DateTime(0));
|
List<int> temp = Store.printTopPost(t, 0, DateTime(0));
|
||||||
@ -1664,7 +1671,7 @@ class Store {
|
|||||||
ret[2] += temp[2];
|
ret[2] += temp[2];
|
||||||
//print("\n");
|
//print("\n");
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1691,7 +1698,7 @@ class Store {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************/
|
/// ********************************************************************************************************************************
|
||||||
/* The main print tree function. Calls the treeSelector() for every node and prints it( and its children), only if it returns true.
|
/* 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]) {
|
List<int> printStoreTrees(int depth, DateTime newerThan, fTreeSelector treeSelector, [int maxToPrint = gMaxEventsInThreadPrinted]) {
|
||||||
@ -1787,11 +1794,9 @@ class Store {
|
|||||||
return 0;
|
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
|
||||||
* @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.
|
||||||
* @param numRoomsOverview This many number of rooms should be printed.
|
|
||||||
*/
|
|
||||||
int printChannelsOverview(List<Channel> channelsToPrint, int numRoomsOverview, fRoomSelector selector, var tempChildEventsMap , Set<String>? secretMessageIds) {
|
int printChannelsOverview(List<Channel> channelsToPrint, int numRoomsOverview, fRoomSelector selector, var tempChildEventsMap , Set<String>? secretMessageIds) {
|
||||||
|
|
||||||
channelsToPrint.sort(scrollableCompareTo);
|
channelsToPrint.sort(scrollableCompareTo);
|
||||||
@ -1818,7 +1823,7 @@ class Store {
|
|||||||
|
|
||||||
//stdout.write("channel type: " + channelsToPrint[j].roomType.toString());
|
//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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1838,11 +1843,11 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( channelsToPrint[j].chatRoomName != "") {
|
if( channelsToPrint[j].chatRoomName != "") {
|
||||||
name = "${channelsToPrint[j].chatRoomName}";
|
name = channelsToPrint[j].chatRoomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numMessages = channelsToPrint[j].getNumValidMessages();
|
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++;
|
numChannelsActuallyPrinted++;
|
||||||
List<String> messageIds = channelsToPrint[j].messageIds;
|
List<String> messageIds = channelsToPrint[j].messageIds;
|
||||||
for( int i = messageIds.length - 1; i >= 0; i--) {
|
for( int i = messageIds.length - 1; i >= 0; i--) {
|
||||||
@ -1850,7 +1855,7 @@ class Store {
|
|||||||
Event? e = allChildEventsMap[messageIds[i]]?.event;
|
Event? e = allChildEventsMap[messageIds[i]]?.event;
|
||||||
if( e!= null) {
|
if( e!= null) {
|
||||||
if( !(e.eventData.kind == 142 && e.eventData.content == e.eventData.evaluatedContent)) {
|
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
|
break; // print only one event, the latest one
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1886,15 +1891,15 @@ class Store {
|
|||||||
stdout.write("\nChannel participants : ");
|
stdout.write("\nChannel participants : ");
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
room.participants.forEach((participant) {
|
for (var participant in room.participants) {
|
||||||
|
|
||||||
if( i != 0) {
|
if( i != 0) {
|
||||||
stdout.write(', ');
|
stdout.write(', ');
|
||||||
}
|
}
|
||||||
String pName = getAuthorName(participant);
|
String pName = getAuthorName(participant);
|
||||||
printInColor("$pName", gCommentColor);
|
printInColor(pName, gCommentColor);
|
||||||
i++;
|
i++;
|
||||||
});
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1968,7 +1973,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
return fullChannelId.first;
|
return fullChannelId.first;
|
||||||
} else {
|
} else {
|
||||||
if( fullChannelId.length == 0) {
|
if( fullChannelId.isEmpty) {
|
||||||
printWarning("Could not find the channel.");
|
printWarning("Could not find the channel.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1982,16 +1987,15 @@ class Store {
|
|||||||
return directRooms.length;
|
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) {
|
int printDirectRoomsOverview(fRoomSelector roomSelector, int numRoomsOverview, var tempChildEventsMap) {
|
||||||
directRooms.sort(scrollableCompareTo);
|
directRooms.sort(scrollableCompareTo);
|
||||||
|
|
||||||
int numNotificationRooms = 0;
|
int numNotificationRooms = 0;
|
||||||
for( int j = 0; j < directRooms.length; j++) {
|
for( int j = 0; j < directRooms.length; j++) {
|
||||||
if( roomSelector(directRooms[j]))
|
if( roomSelector(directRooms[j])) {
|
||||||
numNotificationRooms++;
|
numNotificationRooms++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// even if num rooms is zero, we will show the heading when its show all rooms
|
// 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
|
int iNotification = 0; // notification counter
|
||||||
for( int j = startRoomIndex; j < endRoomIndex; j++) {
|
for( int j = startRoomIndex; j < endRoomIndex; j++) {
|
||||||
if( !roomSelector(directRooms[j]))
|
if( !roomSelector(directRooms[j])) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// print only that we have been asked for
|
// print only that we have been asked for
|
||||||
if( iNotification++ > numNotificationRooms) {
|
if( iNotification++ > numNotificationRooms) {
|
||||||
@ -2042,7 +2047,7 @@ class Store {
|
|||||||
room.visitAllMessages(this, markAllRead);
|
room.visitAllMessages(this, markAllRead);
|
||||||
|
|
||||||
int numMessages = room.messageIds.length;
|
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
|
// print latest event in one line
|
||||||
List<String> messageIds = room.messageIds;
|
List<String> messageIds = room.messageIds;
|
||||||
@ -2106,10 +2111,10 @@ class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( lookedUpName.length > 0) {
|
if( lookedUpName.isNotEmpty) {
|
||||||
printWarning("Got more than one public id for the name given, which are: ");
|
printWarning("Got more than one public id for the name given, which are: ");
|
||||||
for(String pubkey in lookedUpName) {
|
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
|
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 {
|
Future<void> writeEventsToFile(String filename) async {
|
||||||
|
|
||||||
// this variable will be used later; update it if needed
|
// this variable will be used later; update it if needed
|
||||||
if( gFollowList.length == 0) {
|
if( gFollowList.isEmpty) {
|
||||||
gFollowList = getFollows(userPublicKey);
|
gFollowList = getFollows(userPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2207,7 +2212,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String temp = tree.event.originalJson.trim();
|
String temp = tree.event.originalJson.trim();
|
||||||
String line = "${temp}\n";
|
String line = "$temp\n";
|
||||||
nLinesStr += line;
|
nLinesStr += line;
|
||||||
eventCounter++;
|
eventCounter++;
|
||||||
if( tree.event.eventData.kind == 1) {
|
if( tree.event.eventData.kind == 1) {
|
||||||
@ -2227,8 +2232,8 @@ class Store {
|
|||||||
nLinesStr = "";
|
nLinesStr = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gDebug > 0) log.info("finished writing eventCounter = ${eventCounter}.");
|
if(gDebug > 0) log.info("finished writing eventCounter = $eventCounter.");
|
||||||
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which ${countPosts} are posts.");
|
print("Appended $eventCounter new events to file \"$gEventsFilename\" of which $countPosts are posts.");
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
print("Could not open file $filename.");
|
print("Could not open file $filename.");
|
||||||
if( gDebug > 0) print("Could not open file: $e");
|
if( gDebug > 0) print("Could not open file: $e");
|
||||||
@ -2241,7 +2246,7 @@ class Store {
|
|||||||
* Also adds 'client' tag with application name.
|
* Also adds 'client' tag with application name.
|
||||||
* @parameter replyToId First few letters of an event id for which reply is being made
|
* @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
|
clientName = (clientName == "")? "nostr_console": clientName; // in case its empty
|
||||||
|
|
||||||
//print("extraTags = $extraTags");
|
//print("extraTags = $extraTags");
|
||||||
@ -2249,26 +2254,29 @@ class Store {
|
|||||||
|
|
||||||
if( extraTags != null)
|
if( extraTags != null)
|
||||||
for( String extraTag in extraTags) {
|
for( String extraTag in extraTags) {
|
||||||
if( otherTags.length > 0)
|
if( otherTags.isNotEmpty) {
|
||||||
otherTags += ",";
|
otherTags += ",";
|
||||||
|
}
|
||||||
otherTags += '["t","$extraTag"]';
|
otherTags += '["t","$extraTag"]';
|
||||||
}
|
}
|
||||||
|
|
||||||
if( gWhetherToSendClientTag) {
|
if( gWhetherToSendClientTag) {
|
||||||
if( otherTags.length > 0)
|
if( otherTags.isNotEmpty) {
|
||||||
otherTags += ",";
|
otherTags += ",";
|
||||||
|
}
|
||||||
otherTags += '["client","$clientName"]';
|
otherTags += '["client","$clientName"]';
|
||||||
}
|
}
|
||||||
|
|
||||||
if( gUserLocation != "") {
|
if( gUserLocation != "") {
|
||||||
if( otherTags.length > 0)
|
if( otherTags.isNotEmpty) {
|
||||||
otherTags += ",";
|
otherTags += ",";
|
||||||
|
}
|
||||||
otherTags += '["location","$gUserLocation"]';
|
otherTags += '["location","$gUserLocation"]';
|
||||||
}
|
}
|
||||||
|
|
||||||
//print("otherTags = $otherTags");
|
//print("otherTags = $otherTags");
|
||||||
if( replyToId.isEmpty) {
|
if( replyToId.isEmpty) {
|
||||||
return otherTags.length >0 ? otherTags: '[]';
|
return otherTags.isNotEmpty ? otherTags: '[]';
|
||||||
}
|
}
|
||||||
|
|
||||||
String strTags = otherTags ;
|
String strTags = otherTags ;
|
||||||
@ -2293,7 +2301,7 @@ class Store {
|
|||||||
if( latestEventId.isEmpty && replyToId.length == 64) {
|
if( latestEventId.isEmpty && replyToId.length == 64) {
|
||||||
latestEventId = replyToId;
|
latestEventId = replyToId;
|
||||||
}
|
}
|
||||||
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.length != 0) {
|
if( latestEventId.isEmpty && replyToId.length != 64 && replyToId.isNotEmpty) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2301,8 +2309,9 @@ class Store {
|
|||||||
if( latestEventId.isNotEmpty) {
|
if( latestEventId.isNotEmpty) {
|
||||||
String? pTagPubkey = allChildEventsMap[latestEventId]?.event.eventData.pubkey;
|
String? pTagPubkey = allChildEventsMap[latestEventId]?.event.eventData.pubkey;
|
||||||
if( pTagPubkey != null) {
|
if( pTagPubkey != null) {
|
||||||
if( strTags.length > 0)
|
if( strTags.isNotEmpty) {
|
||||||
strTags += ",";
|
strTags += ",";
|
||||||
|
}
|
||||||
strTags += '["p","$pTagPubkey"]';
|
strTags += '["p","$pTagPubkey"]';
|
||||||
}
|
}
|
||||||
String relay = getRelayOfUser(userPublicKey, pTagPubkey??"");
|
String relay = getRelayOfUser(userPublicKey, pTagPubkey??"");
|
||||||
@ -2315,14 +2324,16 @@ class Store {
|
|||||||
Tree topTree = getTopTree(t);
|
Tree topTree = getTopTree(t);
|
||||||
rootEventId = topTree.event.eventData.id;
|
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( 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 += ",";
|
||||||
|
}
|
||||||
strTags += '["e","$rootEventId","","root"]';
|
strTags += '["e","$rootEventId","","root"]';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( strTags.length > 0)
|
if( strTags.isNotEmpty) {
|
||||||
strTags += ",";
|
strTags += ",";
|
||||||
|
}
|
||||||
strTags += '["e","$latestEventId","$relay","reply"]';
|
strTags += '["e","$latestEventId","$relay","reply"]';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2405,7 +2416,7 @@ class Store {
|
|||||||
latestEventId = replyToId;
|
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.');
|
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
|
// add root for kind 1 in rooms
|
||||||
if( [enumRoomType.RoomLocationTag, enumRoomType.RoomTTag].contains( channel.roomType) ) {
|
if( [enumRoomType.RoomLocationTag, enumRoomType.RoomTTag].contains( channel.roomType) ) {
|
||||||
Tree? replyTree = allChildEventsMap[latestEventId]??null;
|
Tree? replyTree = allChildEventsMap[latestEventId];
|
||||||
if( replyTree != null) {
|
if( replyTree != null) {
|
||||||
Tree rootTree = getTopTree(replyTree);
|
Tree rootTree = getTopTree(replyTree);
|
||||||
String rootEventId = rootTree.event.eventData.id;
|
String rootEventId = rootTree.event.eventData.id;
|
||||||
@ -2517,7 +2528,7 @@ class Store {
|
|||||||
} else {
|
} else {
|
||||||
stdout.write("* Of the $selfNumContacts people you follow, $numSecond follow you back. Their names are: ");
|
stdout.write("* Of the $selfNumContacts people you follow, $numSecond follow you back. Their names are: ");
|
||||||
mutualFollows.sort();
|
mutualFollows.sort();
|
||||||
mutualFollows.forEach((name) { stdout.write("$name, ");});
|
for (var name in mutualFollows) { stdout.write("$name, ");}
|
||||||
}
|
}
|
||||||
print("");
|
print("");
|
||||||
} else { // end if contact event was found
|
} else { // end if contact event was found
|
||||||
@ -2536,9 +2547,9 @@ class Store {
|
|||||||
static List<String> processDeleteEvent(Map<String, Tree> tempChildEventsMap, Event deleterEvent) {
|
static List<String> processDeleteEvent(Map<String, Tree> tempChildEventsMap, Event deleterEvent) {
|
||||||
List<String> deletedEventIds = [];
|
List<String> deletedEventIds = [];
|
||||||
if( deleterEvent.eventData.kind == 5) {
|
if( deleterEvent.eventData.kind == 5) {
|
||||||
deleterEvent.eventData.tags.forEach((tag) {
|
for (var tag in deleterEvent.eventData.tags) {
|
||||||
if( tag.length < 2) {
|
if( tag.length < 2) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
if( tag[0] == "e") {
|
if( tag[0] == "e") {
|
||||||
String deletedEventId = tag[1];
|
String deletedEventId = tag[1];
|
||||||
@ -2555,7 +2566,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} // end if
|
} // end if
|
||||||
return deletedEventIds;
|
return deletedEventIds;
|
||||||
} // end processDeleteEvent
|
} // end processDeleteEvent
|
||||||
@ -2566,7 +2577,7 @@ class Store {
|
|||||||
Event deleterEvent = tree.event;
|
Event deleterEvent = tree.event;
|
||||||
if( deleterEvent.eventData.kind == 5) {
|
if( deleterEvent.eventData.kind == 5) {
|
||||||
List<String> tempIds = processDeleteEvent(tempChildEventsMap, deleterEvent);
|
List<String> tempIds = processDeleteEvent(tempChildEventsMap, deleterEvent);
|
||||||
tempIds.forEach((tempId) { deletedEventIds.add(tempId); });
|
for (var tempId in tempIds) { deletedEventIds.add(tempId); }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return deletedEventIds;
|
return deletedEventIds;
|
||||||
@ -2590,8 +2601,9 @@ class Store {
|
|||||||
// the reactedTo event's id, blank if invalid reaction etc
|
// the reactedTo event's id, blank if invalid reaction etc
|
||||||
static String processReaction(Event event, Map<String, Tree> tempChildEventsMap) {
|
static String processReaction(Event event, Map<String, Tree> tempChildEventsMap) {
|
||||||
|
|
||||||
if( gDebug > 0 && event.eventData.id == gCheckEventId)
|
if( gDebug > 0 && event.eventData.id == gCheckEventId) {
|
||||||
print("in processReaction: 0 got reaction $gCheckEventId");
|
print("in processReaction: 0 got reaction $gCheckEventId");
|
||||||
|
}
|
||||||
|
|
||||||
List<String> validReactionList = ["+", "!"]; // TODO support opposite reactions
|
List<String> validReactionList = ["+", "!"]; // TODO support opposite reactions
|
||||||
List<String> opppositeReactions = ['-', "~"];
|
List<String> opppositeReactions = ['-', "~"];
|
||||||
@ -2785,20 +2797,24 @@ Store getTree(Set<Event> events) {
|
|||||||
events.retainWhere((event) => ids.add(event.eventData.id));
|
events.retainWhere((event) => ids.add(event.eventData.id));
|
||||||
|
|
||||||
// process kind 0 events about metadata
|
// 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)
|
// 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
|
// create tree from events
|
||||||
Store node = Store.fromEvents(events);
|
Store node = Store.fromEvents(events);
|
||||||
|
|
||||||
// translate and expand mentions
|
// 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
|
// has been done in fromEvents
|
||||||
//events.where((element) => [gSecretMessageKind].contains(element.eventData.kind)).forEach( (event) => event.eventData.TranslateAndDecryptGroupInvite( ));;
|
//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;
|
return node;
|
||||||
}
|
}
|
||||||
@ -2807,18 +2823,19 @@ Store getTree(Set<Event> events) {
|
|||||||
String getDirectRoomId(EventData eventData) {
|
String getDirectRoomId(EventData eventData) {
|
||||||
|
|
||||||
List<String> participantIds = [];
|
List<String> participantIds = [];
|
||||||
eventData.tags.forEach((tag) {
|
for (var tag in eventData.tags) {
|
||||||
if( tag.length < 2)
|
if( tag.length < 2) {
|
||||||
return;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if( tag[0] == 'p') {
|
if( tag[0] == 'p') {
|
||||||
participantIds.add(tag[1]);
|
participantIds.add(tag[1]);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
participantIds.sort();
|
participantIds.sort();
|
||||||
String uniqueId = "";
|
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
|
// send the other persons pubkey as identifier
|
||||||
if( eventData.pubkey == userPublicKey) {
|
if( eventData.pubkey == userPublicKey) {
|
||||||
|
@ -10,7 +10,7 @@ Event? getContactEvent(String pubkey) {
|
|||||||
|
|
||||||
// get the latest kind 3 event for the user, which lists his 'follows' list
|
// get the latest kind 3 event for the user, which lists his 'follows' list
|
||||||
if( gKindONames.containsKey(pubkey)) {
|
if( gKindONames.containsKey(pubkey)) {
|
||||||
Event? e = (gKindONames[pubkey]?.latestContactEvent)??null;
|
Event? e = (gKindONames[pubkey]?.latestContactEvent);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,9 @@ Set<String> getFollows(String pubkey) {
|
|||||||
|
|
||||||
Event? profileContactEvent = getContactEvent(pubkey);
|
Event? profileContactEvent = getContactEvent(pubkey);
|
||||||
if( profileContactEvent != null) {
|
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();
|
//followPubkeys = profileContactEvent.eventData.contactList.toSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ Set<String> getFollows(String pubkey) {
|
|||||||
Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
|
Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
|
||||||
Set<String> userChannels = {};
|
Set<String> userChannels = {};
|
||||||
|
|
||||||
userEvents.forEach((event) {
|
for (var event in userEvents) {
|
||||||
if( event.eventData.pubkey == userPublicKey) {
|
if( event.eventData.pubkey == userPublicKey) {
|
||||||
if( [42, 142].contains( event.eventData.kind) ) {
|
if( [42, 142].contains( event.eventData.kind) ) {
|
||||||
String channelId = event.eventData.getChannelIdForKind4x();
|
String channelId = event.eventData.getChannelIdForKind4x();
|
||||||
@ -44,7 +46,7 @@ Set<String> getUserChannels(Set<Event> userEvents, String userPublicKey) {
|
|||||||
userChannels.add(event.eventData.id);
|
userChannels.add(event.eventData.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return userChannels;
|
return userChannels;
|
||||||
}
|
}
|
||||||
@ -88,11 +90,11 @@ Set<String> getpTags(Set<Event> events, int numMostFrequent) {
|
|||||||
|
|
||||||
Set<String> getOnlyUserEvents(Set<Event> initialEvents, String userPubkey) {
|
Set<String> getOnlyUserEvents(Set<Event> initialEvents, String userPubkey) {
|
||||||
Set<String> userEvents = {};
|
Set<String> userEvents = {};
|
||||||
initialEvents.forEach((event) {
|
for (var event in initialEvents) {
|
||||||
if( event.eventData.pubkey == userPubkey) {
|
if( event.eventData.pubkey == userPubkey) {
|
||||||
userEvents.add(event.eventData.id);
|
userEvents.add(event.eventData.id);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return userEvents;
|
return userEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,13 @@ String getPostKindFrom(enumRoomType eType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Set<String>? getTagsFromContent(String content) {
|
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);
|
RegExp httpRegExp = RegExp(regexp1);
|
||||||
|
|
||||||
for( var match in httpRegExp.allMatches(content) ) {
|
for( var match in httpRegExp.allMatches(content) ) {
|
||||||
if( tags == null)
|
tags ??= {};
|
||||||
tags = {};
|
|
||||||
|
|
||||||
tags.add( content.substring(match.start + 1, match.end).trim() );
|
tags.add( content.substring(match.start + 1, match.end).trim() );
|
||||||
}
|
}
|
||||||
@ -84,31 +83,35 @@ extension StringX on String {
|
|||||||
|
|
||||||
int isChannelPageNumber(int max) {
|
int isChannelPageNumber(int max) {
|
||||||
|
|
||||||
if(this.length < 2 || this[0] != '/') {
|
if(length < 2 || this[0] != '/') {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String rest = this.substring(1);
|
String rest = substring(1);
|
||||||
|
|
||||||
//print("rest = $rest");
|
//print("rest = $rest");
|
||||||
int? n = int.tryParse(rest);
|
int? n = int.tryParse(rest);
|
||||||
if( n != null) {
|
if( n != null) {
|
||||||
if( n < max)
|
if( n < max) {
|
||||||
return n;
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnglish( ) {
|
isEnglish( ) {
|
||||||
// since smaller words can be smileys they should not be translated
|
// since smaller words can be smileys they should not be translated
|
||||||
if( length < 10)
|
if( length < 10) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if( !isLatinAlphabet())
|
if( !isLatinAlphabet()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isRomanceLanguage())
|
if (isRomanceLanguage()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -127,7 +130,7 @@ extension StringX on String {
|
|||||||
|
|
||||||
Set<String> romanceWords = frenchWords.union(spanishWords).union(portugeseWords);
|
Set<String> romanceWords = frenchWords.union(spanishWords).union(portugeseWords);
|
||||||
for( String word in romanceWords) {
|
for( String word in romanceWords) {
|
||||||
if( this.toLowerCase().contains(" $word ")) {
|
if( toLowerCase().contains(" $word ")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +211,7 @@ String unEscapeChars(String str) {
|
|||||||
return temp;
|
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 getNumSpaces(int num) {
|
||||||
String s = "";
|
String s = "";
|
||||||
@ -228,7 +231,7 @@ String getNumDashes(int num, [String dashType = "-"]) {
|
|||||||
|
|
||||||
List<List<int>> getUrlRanges(String s) {
|
List<List<int>> getUrlRanges(String s) {
|
||||||
List<List<int>> urlRanges = [];
|
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);
|
RegExp httpRegExp = RegExp(regexp1);
|
||||||
for( var match in httpRegExp.allMatches(s) ) {
|
for( var match in httpRegExp.allMatches(s) ) {
|
||||||
@ -273,11 +276,13 @@ List<int>? getTypeAndModule(String str) {
|
|||||||
|
|
||||||
bool sanityChecked(String lnInvoice) {
|
bool sanityChecked(String lnInvoice) {
|
||||||
|
|
||||||
if( lnInvoice.length < gMinLnInvoiceLength)
|
if( lnInvoice.length < gMinLnInvoiceLength) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc")
|
if( lnInvoice.substring(0, 4).toLowerCase() != "lnbc") {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -306,7 +311,7 @@ String expandLNInvoices(String content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qrStr = getPubkeyAsQrString(lnInvoice, typeAndModule[0], typeAndModule[1], "");
|
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;
|
return content;
|
||||||
@ -319,7 +324,7 @@ String getPubkeyAsQrString(String str, [int typeNumber = 4, moduleCount = 33, St
|
|||||||
String output = "";
|
String output = "";
|
||||||
|
|
||||||
final qrCode = QrCode(typeNumber, QrErrorCorrectLevel.L)
|
final qrCode = QrCode(typeNumber, QrErrorCorrectLevel.L)
|
||||||
..addData('$str');
|
..addData(str);
|
||||||
final qrImage = QrImage(qrCode);
|
final qrImage = QrImage(qrCode);
|
||||||
|
|
||||||
assert( qrImage.moduleCount == moduleCount);
|
assert( qrImage.moduleCount == moduleCount);
|
||||||
@ -372,8 +377,9 @@ String getStringFromUser(String prompt, [String defaultValue=""] ) {
|
|||||||
stdout.write(prompt);
|
stdout.write(prompt);
|
||||||
str = (stdin.readLineSync())??"";
|
str = (stdin.readLineSync())??"";
|
||||||
|
|
||||||
if( str.length == 0)
|
if( str.isEmpty) {
|
||||||
str = defaultValue;
|
str = defaultValue;
|
||||||
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,21 +405,21 @@ String getCommaSeparatedInts(Set<int>? kind) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if( kind.length == 0) {
|
if( kind.isEmpty) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String strKind = "";
|
String strKind = "";
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
kind.forEach((k) {
|
for (var k in kind) {
|
||||||
String comma = ",";
|
String comma = ",";
|
||||||
if( i == kind.length-1) {
|
if( i == kind.length-1) {
|
||||||
comma = "";
|
comma = "";
|
||||||
}
|
}
|
||||||
strKind = strKind + k.toString() + comma;
|
strKind = strKind + k.toString() + comma;
|
||||||
i++;
|
i++;
|
||||||
});
|
}
|
||||||
|
|
||||||
return strKind;
|
return strKind;
|
||||||
}
|
}
|
||||||
@ -432,16 +438,14 @@ String getKindRequest(String subscriptionId, List<int> kind, int limit, int sinc
|
|||||||
return strRequest;
|
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 = {};
|
Set<int> kind = {};
|
||||||
if( _kind != null) {
|
kind = kind;
|
||||||
kind = _kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
String strKind = getCommaSeparatedInts(kind);
|
String strKind = getCommaSeparatedInts(kind);
|
||||||
|
|
||||||
String strKindSection = "";
|
String strKindSection = "";
|
||||||
if( strKind.length > 0) {
|
if( strKind.isNotEmpty) {
|
||||||
strKindSection = '"kinds":[$strKind],';
|
strKindSection = '"kinds":[$strKind],';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,12 +481,12 @@ String getIdAndMentionRequest(String subscriptionId, Set<String> ids, int numUse
|
|||||||
|
|
||||||
var strSubscription1 = '["REQ","$subscriptionId",{ "$tagToGet": [';
|
var strSubscription1 = '["REQ","$subscriptionId",{ "$tagToGet": [';
|
||||||
var strSubscription2 ='], "limit": $numUserEvents $idStrTime } ]';
|
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;
|
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 = "";
|
String strTime = "";
|
||||||
if( sinceWhen != 0) {
|
if( sinceWhen != 0) {
|
||||||
strTime = ', "since": ${sinceWhen.toString()}';
|
strTime = ', "since": ${sinceWhen.toString()}';
|
||||||
@ -491,7 +495,7 @@ String getMultiUserRequest(String subscriptionId, Set<String> publicKeys, int nu
|
|||||||
String strKind = getCommaSeparatedInts(kind);
|
String strKind = getCommaSeparatedInts(kind);
|
||||||
|
|
||||||
String strKindSection = "";
|
String strKindSection = "";
|
||||||
if( strKind.length > 0) {
|
if( strKind.isNotEmpty) {
|
||||||
strKindSection = '"kinds":[$strKind],';
|
strKindSection = '"kinds":[$strKind],';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,14 +512,14 @@ void printSet( Set<String> toPrint, [ String prefix = "", String separator = ""]
|
|||||||
stdout.write(prefix);
|
stdout.write(prefix);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
toPrint.forEach((element) {
|
for (var element in toPrint) {
|
||||||
if( i != 0) {
|
if( i != 0) {
|
||||||
stdout.write(separator);
|
stdout.write(separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.write(element);
|
stdout.write(element);
|
||||||
i++;
|
i++;
|
||||||
});
|
}
|
||||||
stdout.write("\n");
|
stdout.write("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,8 @@ homepage: https://github.com/vishalxl/nostr_console
|
|||||||
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.17.3 <3.0.0'
|
sdk: '>=2.17.3 <4.0.0'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
@ -107,3 +108,5 @@ dependencies:
|
|||||||
logging: ^1.0.2
|
logging: ^1.0.2
|
||||||
kepler: ^1.0.3
|
kepler: ^1.0.3
|
||||||
qr: ^3.0.1
|
qr: ^3.0.1
|
||||||
|
pointycastle: any
|
||||||
|
http: any
|
||||||
|
@ -221,11 +221,11 @@ String expectedResult =
|
|||||||
"11 https://github.com/nostr-protocol/nips/blob/master/16.md#ephemeral-events",
|
"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"];
|
"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);
|
String res = makeParagraphAtDepth(url, 30);
|
||||||
//print(url); print(res);print("");
|
//print(url); print(res);print("");
|
||||||
expect( res, url);
|
expect( res, url);
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -233,27 +233,33 @@ String expectedResult =
|
|||||||
Set<Event> initialEvents = {}; // collect all events here and then create tree out of them
|
Set<Event> initialEvents = {}; // collect all events here and then create tree out of them
|
||||||
|
|
||||||
|
|
||||||
String input_filename = 'test_event_file.csv';
|
String inputFilename = 'test_event_file.csv';
|
||||||
initialEvents = await readEventsFromFile(input_filename);
|
initialEvents = readEventsFromFile(inputFilename);
|
||||||
|
|
||||||
int numFilePosts = 0;
|
int numFilePosts = 0;
|
||||||
// count events
|
// 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");
|
//print("read $numFilePosts posts from file $gEventsFilename");
|
||||||
expect(numFilePosts, 3486, reason:'Verify right number of kind 1 posts');
|
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');
|
expect(0, node.getNumDirectRooms(), reason:'verify correct number of direct chat rooms created');
|
||||||
|
|
||||||
int numKind4xChannels = 0;
|
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;
|
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;
|
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(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');
|
expect(41, numTTagChannels, reason: 'verify correct number of public channels created of T tag type');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user