From adad048873e58ae163560ff3043462e84468e1b4 Mon Sep 17 00:00:00 2001 From: reya Date: Fri, 11 Oct 2024 08:56:43 +0700 Subject: [PATCH] feat: improve negentropy sync --- src-tauri/src/commands/account.rs | 170 ++++++++++++++------------- src-tauri/src/commands/event.rs | 23 ++-- src-tauri/src/commands/metadata.rs | 24 ++-- src-tauri/src/main.rs | 6 +- src/components/note/content.tsx | 6 +- src/routes/bootstrap-relays.lazy.tsx | 9 +- 6 files changed, 129 insertions(+), 109 deletions(-) diff --git a/src-tauri/src/commands/account.rs b/src-tauri/src/commands/account.rs index e4455eae..1de21ad5 100644 --- a/src-tauri/src/commands/account.rs +++ b/src-tauri/src/commands/account.rs @@ -10,12 +10,8 @@ use std::{ time::Duration, }; use tauri::{Emitter, Manager, State}; -use tokio::time::sleep; -use crate::{ - common::{get_latest_event, init_nip65}, - Nostr, NOTIFICATION_SUB_ID, -}; +use crate::{Nostr, NOTIFICATION_SUB_ID}; #[derive(Debug, Clone, Serialize, Deserialize, Type)] struct Account { @@ -284,7 +280,7 @@ pub async fn login( }; // NIP-65: Connect to user's relay list - init_nip65(client, &public_key).await; + // init_nip65(client, &public_key).await; // NIP-03: Get user's contact list let contact_list = { @@ -325,8 +321,8 @@ pub async fn login( .reconcile( Filter::new() .authors(authors.clone()) - .kinds(vec![Kind::Metadata, Kind::ContactList, Kind::EventDeletion]) - .limit(authors.len() * 20), + .kinds(vec![Kind::Metadata, Kind::ContactList]) + .limit(authors.len() * 10), NegentropyOptions::default(), ) .await @@ -339,8 +335,8 @@ pub async fn login( .reconcile( Filter::new() .authors(authors.clone()) - .kinds(vec![Kind::TextNote, Kind::Repost]) - .limit(authors.len() * 50), + .kinds(vec![Kind::TextNote, Kind::Repost, Kind::EventDeletion]) + .limit(authors.len() * 40), NegentropyOptions::default(), ) .await @@ -350,84 +346,94 @@ pub async fn login( // Create the trusted public key list from contact list // TODO: create a cached file - let mut trusted_list: HashSet = HashSet::new(); + if let Ok(events) = client + .database() + .query(vec![Filter::new().kind(Kind::ContactList)]) + .await + { + let keys: Vec<&str> = events + .iter() + .flat_map(|event| event.get_tags_content(TagKind::p())) + .collect(); - for author in authors.into_iter() { - trusted_list.insert(author); - - let filter = Filter::new() - .author(author) - .kind(Kind::ContactList) - .limit(1); - - if let Ok(events) = client.database().query(vec![filter]).await { - if let Some(event) = get_latest_event(&events) { - for tag in event.tags.iter() { - if let Some(TagStandard::PublicKey { - public_key, - uppercase: false, - .. - }) = tag.to_owned().to_standardized() - { - trusted_list.insert(public_key); - }; + let trusted_list: HashSet = keys + .into_iter() + .filter_map(|item| { + if let Ok(pk) = PublicKey::from_str(item) { + Some(pk) + } else { + None } - } + }) + .collect(); + + // Update app's state + state.trusted_list.lock().await.clone_from(&trusted_list); + + let trusted_users: Vec = trusted_list.into_iter().collect(); + println!("Total trusted users: {}", trusted_users.len()); + + if let Ok(report) = client + .reconcile( + Filter::new() + .authors(trusted_users) + .kinds(vec![ + Kind::Metadata, + Kind::TextNote, + Kind::Repost, + Kind::EventDeletion, + ]) + .limit(5000), + NegentropyOptions::default(), + ) + .await + { + println!("Received: {}", report.received.len()) } - } + }; + }; - // Update app's state - state.trusted_list.lock().await.clone_from(&trusted_list); - - // Syncing all user's events - if let Ok(report) = client - .reconcile(Filter::new().author(author), NegentropyOptions::default()) - .await - { - println!("Received: {}", report.received.len()) - } - - // Syncing all tagged events for current user - if let Ok(report) = client - .reconcile( - Filter::new().pubkey(author).kinds(vec![ - Kind::TextNote, - Kind::Repost, - Kind::Reaction, - Kind::ZapReceipt, - ]), - NegentropyOptions::default(), - ) - .await - { - println!("Received: {}", report.received.len()) - } - - // Syncing all events for trusted list - let trusted: Vec = trusted_list.into_iter().collect(); - if let Ok(report) = client - .reconcile( - Filter::new() - .authors(trusted) - .kinds(vec![ - Kind::Metadata, - Kind::TextNote, - Kind::Repost, - Kind::EventDeletion, - ]) - .limit(30000), - NegentropyOptions::default(), - ) - .await - { - println!("Received: {}", report.received.len()) - } - - // Wait a little longer - // TODO: remove? - sleep(Duration::from_secs(5)).await; + // Syncing all user's events + if let Ok(report) = client + .reconcile( + Filter::new().author(author).kinds(vec![ + Kind::TextNote, + Kind::Repost, + Kind::FollowSet, + Kind::InterestSet, + Kind::Interests, + Kind::EventDeletion, + Kind::MuteList, + Kind::BookmarkSet, + Kind::BlockedRelays, + Kind::EmojiSet, + Kind::RelaySet, + Kind::RelayList, + Kind::ApplicationSpecificData, + ]), + NegentropyOptions::default(), + ) + .await + { + println!("Received: {}", report.received.len()) } + // Syncing all tagged events for current user + if let Ok(report) = client + .reconcile( + Filter::new().pubkey(author).kinds(vec![ + Kind::TextNote, + Kind::Repost, + Kind::Reaction, + Kind::ZapReceipt, + ]), + NegentropyOptions::default(), + ) + .await + { + println!("Received: {}", report.received.len()) + }; + handle .emit("neg_synchronized", ()) .expect("Something wrong!"); diff --git a/src-tauri/src/commands/event.rs b/src-tauri/src/commands/event.rs index d73d06cf..9ca08b57 100644 --- a/src-tauri/src/commands/event.rs +++ b/src-tauri/src/commands/event.rs @@ -40,25 +40,26 @@ pub async fn get_event(id: String, state: State<'_, Nostr>) -> Result { - let mut raw: String = String::new(); - let mut parsed: Option = None; - - while let Some(event) = rx.next().await { - raw = event.as_json(); - parsed = if event.kind == Kind::TextNote { + Ok(events) => { + if let Some(event) = get_latest_event(&events) { + let raw = event.as_json(); + let parsed = if event.kind == Kind::TextNote { Some(parse_event(&event.content).await) } else { None }; - } - Ok(RichEvent { raw, parsed }) + Ok(RichEvent { raw, parsed }) + } else { + Err("Not found.".into()) + } } Err(err) => Err(err.to_string()), } diff --git a/src-tauri/src/commands/metadata.rs b/src-tauri/src/commands/metadata.rs index f365da45..62530a71 100644 --- a/src-tauri/src/commands/metadata.rs +++ b/src-tauri/src/commands/metadata.rs @@ -58,23 +58,23 @@ pub async fn get_profile(id: Option, state: State<'_, Nostr>) -> Result< Err("Parse metadata failed".into()) } } else { - println!("Not found, getting event from relays..."); match client - .stream_events_of(vec![filter], Some(Duration::from_secs(10))) + .get_events_of( + vec![filter], + EventSource::relays(Some(Duration::from_secs(10))), + ) .await { - Ok(mut rx) => { - let mut metadata: String = Metadata::new().as_json(); - - while let Some(event) = rx.next().await { - println!("Event: {}", event.as_json()); - if let Ok(m) = Metadata::from_json(&event.content) { - metadata = m.as_json(); - break; + Ok(events) => { + if let Some(event) = get_latest_event(&events) { + if let Ok(metadata) = Metadata::from_json(&event.content) { + Ok(metadata.as_json()) + } else { + Err("Metadata is not valid.".into()) } + } else { + Err("Not found.".into()) } - - Ok(metadata) } Err(e) => Err(e.to_string()), } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 23e2f644..a5f1f71d 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -273,8 +273,12 @@ fn main() { println!("Add discovery relay failed: {}", e) } + if let Err(e) = client.add_discovery_relay("wss://user.kindpag.es/").await { + println!("Add discovery relay failed: {}", e) + } + // Connect - client.connect_with_timeout(Duration::from_secs(20)).await; + client.connect_with_timeout(Duration::from_secs(10)).await; client }); diff --git a/src/components/note/content.tsx b/src/components/note/content.tsx index f5a31ceb..651c5e99 100644 --- a/src/components/note/content.tsx +++ b/src/components/note/content.tsx @@ -113,10 +113,12 @@ const ContentWarning = memo(function ContentWarning({ }: { warning: string }) { const [blurred, setBlurred] = useState(() => warning?.length > 0); - if (!blurred) return null; + if (!blurred) { + return null; + } return ( -
+

The content is hidden because the author diff --git a/src/routes/bootstrap-relays.lazy.tsx b/src/routes/bootstrap-relays.lazy.tsx index 884bc54f..8d56ca31 100644 --- a/src/routes/bootstrap-relays.lazy.tsx +++ b/src/routes/bootstrap-relays.lazy.tsx @@ -80,7 +80,7 @@ function Screen() {

Manage Relays

- This relays will be only use to get user's metadata. + The default relays that Lume will connected.

@@ -127,6 +127,13 @@ function Screen() {
))}
+
+

+ Lume is heavily depend on Negentropy for syncing data. You need + to use at least 1 relay that support Negentropy. If you not + sure, you can keep using the default relay list. +

+