From b142982ab1493a9dc291dda53c5a9afc9ea3d4bf Mon Sep 17 00:00:00 2001 From: reya <123083837+reyamir@users.noreply.github.com> Date: Sat, 13 Sep 2025 07:42:17 +0700 Subject: [PATCH] chore: refactor event fetching (#148) * use stream for nip65 and nip17 relays fetching * . --- Cargo.lock | 50 +++++----- crates/coop/src/chatspace.rs | 188 ++++++++++++++++------------------- 2 files changed, 112 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ed0ef3..0d66355 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -894,9 +894,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" dependencies = [ "find-msvc-tools", "jobserver", @@ -1113,7 +1113,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "indexmap", "rustc-hash 2.1.1", @@ -1554,7 +1554,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "proc-macro2", "quote", @@ -2480,7 +2480,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "as-raw-xcb-connection", @@ -2574,7 +2574,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2586,7 +2586,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "gpui", @@ -2800,7 +2800,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "bytes", @@ -2820,7 +2820,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3611,7 +3611,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "bindgen 0.71.1", @@ -3859,7 +3859,7 @@ dependencies = [ [[package]] name = "nostr" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "aes", "base64", @@ -3883,7 +3883,7 @@ dependencies = [ [[package]] name = "nostr-connect" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "async-utility", "nostr", @@ -3895,7 +3895,7 @@ dependencies = [ [[package]] name = "nostr-database" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "flatbuffers", "lru", @@ -3906,7 +3906,7 @@ dependencies = [ [[package]] name = "nostr-lmdb" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "async-utility", "flume", @@ -3920,7 +3920,7 @@ dependencies = [ [[package]] name = "nostr-relay-pool" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "async-utility", "async-wsocket", @@ -3937,7 +3937,7 @@ dependencies = [ [[package]] name = "nostr-sdk" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#04ca01082044dd4192fee995b9ba101c78af3a02" +source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389" dependencies = [ "async-utility", "nostr", @@ -5051,7 +5051,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "derive_refineable", "workspace-hack", @@ -5205,7 +5205,7 @@ dependencies = [ [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "bytes", @@ -5491,9 +5491,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "b5a37813727b78798e53c2bec3f5e8fe12a6d6f8389bf9ca7802add4c9905ad8" dependencies = [ "aws-lc-rs", "ring", @@ -5740,7 +5740,7 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semantic_version" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "serde", @@ -6181,7 +6181,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "arrayvec", "log", @@ -7080,9 +7080,9 @@ checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" @@ -7211,7 +7211,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#9c548a0ec6d8b84e2b3b1ee2a78add5fae7a8ba7" +source = "git+https://github.com/zed-industries/zed#592b013013e74d5ad44f2c04ef5afeb3be21249e" dependencies = [ "anyhow", "async-fs", diff --git a/crates/coop/src/chatspace.rs b/crates/coop/src/chatspace.rs index ae8ed9b..a839d2d 100644 --- a/crates/coop/src/chatspace.rs +++ b/crates/coop/src/chatspace.rs @@ -216,67 +216,60 @@ impl ChatSpace { async fn observe_signer() { let client = nostr_client(); let ingester = ingester(); + let stream_timeout = Duration::from_secs(5); let loop_duration = Duration::from_secs(1); - let mut is_sent_signal = false; - let mut identity: Option = None; loop { - if let Some(public_key) = identity { - let nip65 = Filter::new().kind(Kind::RelayList).author(public_key); + let Ok(signer) = client.signer().await else { + smol::Timer::after(loop_duration).await; + continue; + }; - if client.database().count(nip65).await.unwrap_or(0) > 0 { - let dm_relays = Filter::new().kind(Kind::InboxRelays).author(public_key); + let Ok(public_key) = signer.get_public_key().await else { + smol::Timer::after(loop_duration).await; + continue; + }; - match client.database().query(dm_relays).await { - Ok(events) => { - if let Some(event) = events.first_owned() { - let relay_urls = nip17::extract_relay_list(&event).collect_vec(); + // Notify the app that the signer has been set. + ingester.send(Signal::SignerSet(public_key)).await; - if relay_urls.is_empty() { - if !is_sent_signal { - ingester.send(Signal::DmRelayNotFound).await; - is_sent_signal = true; - } - } else { - break; - } - } else if !is_sent_signal { - ingester.send(Signal::DmRelayNotFound).await; - is_sent_signal = true; - } else { - break; - } - } - Err(e) => { - log::error!("Database query error: {e}"); - if !is_sent_signal { - ingester.send(Signal::DmRelayNotFound).await; - is_sent_signal = true; - } - } - } - } else { - log::error!("Database error."); - break; - } - } else { - // Wait for signer set - if let Ok(signer) = client.signer().await { - if let Ok(public_key) = signer.get_public_key().await { - identity = Some(public_key); - - // Notify the app that the signer has been set. - ingester.send(Signal::SignerSet(public_key)).await; - - // Subscribe to the NIP-65 relays for the public key. - if let Err(e) = Self::fetch_nip65_relays(public_key).await { - log::error!("Failed to fetch NIP-65 relays: {e}"); + // Subscribe to the NIP-65 relays for the public key. + let filter = Filter::new() + .kind(Kind::RelayList) + .author(public_key) + .limit(1); + + match client + .stream_events_from(BOOTSTRAP_RELAYS, filter, stream_timeout) + .await + { + Ok(mut stream) => { + let mut processed_ids = HashSet::new(); + + if let Some(event) = stream.next().await { + if processed_ids.insert(event.id) { + // Fetch user's metadata event + Self::fetch_single_event(Kind::Metadata, event.pubkey).await; + + // Fetch user's contact list event + Self::fetch_single_event(Kind::ContactList, event.pubkey).await; + + // Fetch user's inbox relays event + Self::fetch_nip17_relays(event.pubkey).await; + + break; } + } else { + ingester.send(Signal::DmRelayNotFound).await; } } - } + Err(e) => { + log::error!("Error fetching NIP-17 Relay: {e:?}"); + ingester.send(Signal::DmRelayNotFound).await; + } + }; - smol::Timer::after(loop_duration).await; + break; } } @@ -395,39 +388,6 @@ impl ChatSpace { } match event.kind { - Kind::RelayList => { - if let Ok(true) = Self::is_self_event(&event).await { - // Fetch user's metadata event - Self::fetch_single_event(Kind::Metadata, event.pubkey).await; - - // Fetch user's contact list event - Self::fetch_single_event(Kind::ContactList, event.pubkey).await; - - // Fetch user's inbox relays event - Self::fetch_single_event(Kind::InboxRelays, event.pubkey).await; - } - } - Kind::InboxRelays => { - if let Ok(true) = Self::is_self_event(&event).await { - let relays = nip17::extract_relay_list(&event).collect_vec(); - - if !relays.is_empty() { - for relay in relays.clone().into_iter() { - if client.add_relay(relay).await.is_err() { - let notice = Notice::RelayFailed(relay.clone()); - ingester.send(Signal::Notice(notice)).await; - } - if client.connect_relay(relay).await.is_err() { - let notice = Notice::RelayFailed(relay.clone()); - ingester.send(Signal::Notice(notice)).await; - } - } - - // Subscribe to gift wrap events only in the current user's NIP-17 relays - Self::fetch_gift_wrap(relays, event.pubkey).await; - } - } - } Kind::ContactList => { if let Ok(true) = Self::is_self_event(&event).await { let public_keys = event.tags.public_keys().copied().collect_vec(); @@ -610,6 +570,49 @@ impl ChatSpace { } } + pub async fn fetch_nip17_relays(public_key: PublicKey) { + let client = nostr_client(); + let ingester = ingester(); + let filter = Filter::new() + .kind(Kind::InboxRelays) + .author(public_key) + .limit(1); + + match client.stream_events(filter, Duration::from_secs(5)).await { + Ok(mut stream) => { + let mut processed_ids = HashSet::new(); + + if let Some(event) = stream.next().await { + if processed_ids.insert(event.id) { + let relays = nip17::extract_relay_list(&event).collect_vec(); + + if !relays.is_empty() { + for relay in relays.clone().into_iter() { + if client.add_relay(relay).await.is_err() { + let notice = Notice::RelayFailed(relay.clone()); + ingester.send(Signal::Notice(notice)).await; + } + if client.connect_relay(relay).await.is_err() { + let notice = Notice::RelayFailed(relay.clone()); + ingester.send(Signal::Notice(notice)).await; + } + } + + // Subscribe to gift wrap events only in the current user's NIP-17 relays + Self::fetch_gift_wrap(relays, event.pubkey).await; + } + } + } else { + ingester.send(Signal::DmRelayNotFound).await; + } + } + Err(e) => { + log::error!("Error fetching NIP-17 Relay: {e:?}"); + ingester.send(Signal::DmRelayNotFound).await; + } + }; + } + pub async fn fetch_gift_wrap(relays: Vec<&RelayUrl>, public_key: PublicKey) { let client = nostr_client(); let sub_id = css().gift_wrap_sub_id.clone(); @@ -624,23 +627,6 @@ impl ChatSpace { } } - /// Fetches NIP-65 relay list for a given public key - pub async fn fetch_nip65_relays(public_key: PublicKey) -> Result<(), Error> { - let client = nostr_client(); - let css = css(); - - let filter = Filter::new() - .kind(Kind::RelayList) - .author(public_key) - .limit(1); - - client - .subscribe_to(BOOTSTRAP_RELAYS, filter, css.auto_close_opts) - .await?; - - Ok(()) - } - /// Fetches metadata for a list of public keys async fn fetch_metadata_for_pubkeys(public_keys: HashSet) { if public_keys.is_empty() {