From 2c33670ba5343676a3755dcf2515e1d70f5aa853 Mon Sep 17 00:00:00 2001 From: reya Date: Thu, 19 Feb 2026 06:41:23 +0700 Subject: [PATCH] . --- Cargo.lock | 89 ++++++++++++--------- crates/chat/src/lib.rs | 61 +++++++------- crates/coop/Cargo.toml | 2 +- crates/coop/src/main.rs | 4 +- crates/device/src/lib.rs | 2 +- crates/relay_auth/src/lib.rs | 40 +++------- crates/settings/src/lib.rs | 2 +- crates/state/src/constants.rs | 4 +- crates/state/src/lib.rs | 146 ++++++++++++++++++++-------------- 9 files changed, 184 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff12ee6..66118fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,9 +286,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" +checksum = "7d67d43201f4d20c78bcda740c142ca52482d81da80681533d33bf3f0596c8e2" dependencies = [ "compression-codecs", "compression-core", @@ -605,9 +605,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.4" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +checksum = "d9a7b350e3bb1767102698302bc37256cbd48422809984b98d292c40e2579aa9" dependencies = [ "aws-lc-sys", "zeroize", @@ -812,9 +812,9 @@ checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5c6f81257d10a0f602a294ae4182251151ff97dbb504ef9afcdda4a64b24d9b4" [[package]] name = "bytemuck" @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "indexmap", "rustc-hash 2.1.1", @@ -1252,9 +1252,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" dependencies = [ "compression-core", "deflate64", @@ -1497,9 +1497,9 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.17.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c5c9868e64aa6c5410629a83450e142c80e721c727a5bc0fb18107af6c2d66b" +checksum = "5d8c4e3a1d02f5269ed15c2d70b4647167856f66f228dcdf99050ab77bbb5a56" dependencies = [ "bitflags 2.11.0", "fontdb", @@ -1638,7 +1638,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "proc-macro2", "quote", @@ -2588,7 +2588,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "as-raw-xcb-connection", @@ -2688,7 +2688,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2699,7 +2699,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "gpui", @@ -2928,7 +2928,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "async-compression", @@ -2953,7 +2953,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3711,6 +3711,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -3734,7 +3743,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "bindgen", @@ -3899,9 +3908,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5d26952a508f321b4d3d2e80e78fc2603eaefcdf0c30783867f19586518bdc" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -3993,7 +4002,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" [[package]] name = "nostr" version = "0.44.1" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "aes", "base64", @@ -4018,7 +4027,7 @@ dependencies = [ [[package]] name = "nostr-connect" version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "async-utility", "futures-core", @@ -4031,7 +4040,7 @@ dependencies = [ [[package]] name = "nostr-database" version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "btreecap", "flatbuffers", @@ -4043,7 +4052,7 @@ dependencies = [ [[package]] name = "nostr-gossip" version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "nostr", ] @@ -4051,7 +4060,7 @@ dependencies = [ [[package]] name = "nostr-gossip-memory" version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "indexmap", "lru", @@ -4063,7 +4072,7 @@ dependencies = [ [[package]] name = "nostr-lmdb" version = "0.44.0" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "async-utility", "flume", @@ -4077,7 +4086,7 @@ dependencies = [ [[package]] name = "nostr-sdk" version = "0.44.1" -source = "git+https://github.com/rust-nostr/nostr#07de813024f930803a1dd81942edb50eb8a87ba3" +source = "git+https://github.com/rust-nostr/nostr#bd92fd901e8b64856ad4f8373fbb87376314161c" dependencies = [ "async-utility", "async-wsocket", @@ -4551,7 +4560,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "collections", "serde", @@ -5227,7 +5236,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "derive_refineable", ] @@ -5332,7 +5341,7 @@ dependencies = [ [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "bytes", @@ -5387,7 +5396,7 @@ dependencies = [ [[package]] name = "rope" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "arrayvec", "log", @@ -5649,7 +5658,7 @@ dependencies = [ [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "async-task", "backtrace", @@ -6230,7 +6239,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "arrayvec", "log", @@ -6940,10 +6949,14 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex-automata", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -7186,7 +7199,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "async-fs", @@ -7224,7 +7237,7 @@ dependencies = [ [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "perf", "quote", @@ -9032,7 +9045,7 @@ dependencies = [ [[package]] name = "zlog" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "anyhow", "chrono", @@ -9049,7 +9062,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "ztracing" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" dependencies = [ "tracing", "tracing-subscriber", @@ -9060,7 +9073,7 @@ dependencies = [ [[package]] name = "ztracing_macro" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#deb26f8c5f89341206a1c5da7c79f6c3654f5fc5" +source = "git+https://github.com/zed-industries/zed#f07cec59def58dd8199bdced27b1aafbeb5755d8" [[package]] name = "zune-core" diff --git a/crates/chat/src/lib.rs b/crates/chat/src/lib.rs index ad56a13..07807b3 100644 --- a/crates/chat/src/lib.rs +++ b/crates/chat/src/lib.rs @@ -10,11 +10,11 @@ use common::EventUtils; use fuzzy_matcher::skim::SkimMatcherV2; use fuzzy_matcher::FuzzyMatcher; use gpui::{ - App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task, WeakEntity, + App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task, WeakEntity, Window, }; use nostr_sdk::prelude::*; use smallvec::{smallvec, SmallVec}; -use state::{NostrRegistry, RelayState, DEVICE_GIFTWRAP, USER_GIFTWRAP}; +use state::{NostrRegistry, DEVICE_GIFTWRAP, USER_GIFTWRAP}; mod message; mod room; @@ -22,8 +22,8 @@ mod room; pub use message::*; pub use room::*; -pub fn init(cx: &mut App) { - ChatRegistry::set_global(cx.new(ChatRegistry::new), cx); +pub fn init(window: &mut Window, cx: &mut App) { + ChatRegistry::set_global(cx.new(|cx| ChatRegistry::new(window, cx)), cx); } struct GlobalChatRegistry(Entity); @@ -59,11 +59,8 @@ pub struct ChatRegistry { /// Tracking the status of unwrapping gift wrap events. tracking_flag: Arc, - /// Handle tracking asynchronous task - tracking_task: Option>>, - - /// Handle notification asynchronous task - notification_task: Option>, + /// Async tasks + tasks: SmallVec<[Task>; 2]>, /// Subscriptions _subscriptions: SmallVec<[Subscription; 1]>, @@ -83,31 +80,28 @@ impl ChatRegistry { } /// Create a new chat registry instance - fn new(cx: &mut Context) -> Self { + fn new(window: &mut Window, cx: &mut Context) -> Self { let nostr = NostrRegistry::global(cx); let nip17 = nostr.read(cx).nip17_state(); let mut subscriptions = smallvec![]; subscriptions.push( - // Observe the identity - cx.observe(&nip17, |this, state, cx| { - if state.read(cx) == &RelayState::Configured { - // Handle nostr notifications - this.handle_notifications(cx); - // Track unwrapping progress - this.tracking(cx); - } - // Get chat rooms from the database on every state changes + // Observe the nip17 state and load chat rooms on every state change + cx.observe(&nip17, |this, _state, cx| { this.get_rooms(cx); }), ); + cx.defer_in(window, |this, _window, cx| { + this.handle_notifications(cx); + this.tracking(cx); + }); + Self { rooms: vec![], tracking_flag: Arc::new(AtomicBool::new(false)), - tracking_task: None, - notification_task: None, + tasks: smallvec![], _subscriptions: subscriptions, } } @@ -126,7 +120,7 @@ impl ChatRegistry { // Channel for communication between nostr and gpui let (tx, rx) = flume::bounded::(1024); - cx.background_spawn(async move { + self.tasks.push(cx.background_spawn(async move { let device_signer = signer.get_encryption_signer().await; let mut notifications = client.notifications(); let mut processed_events = HashSet::new(); @@ -149,7 +143,7 @@ impl ChatRegistry { continue; } - log::info!("Received gift-wrap event: {event:?}"); + log::info!("Received gift wrap event: {:?}", event); // Extract the rumor from the gift wrap event match Self::extract_rumor(&client, &device_signer, event.as_ref()).await { @@ -158,7 +152,7 @@ impl ChatRegistry { let new_message = NewMessage::new(event.id, rumor); let signal = Signal::Message(new_message); - tx.send_async(signal).await.ok(); + tx.send_async(signal).await?; } false => { status.store(true, Ordering::Release); @@ -171,32 +165,33 @@ impl ChatRegistry { } RelayMessage::EndOfStoredEvents(id) => { if id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2 { - tx.send_async(Signal::Eose).await.ok(); + tx.send_async(Signal::Eose).await?; } } _ => {} } } - }) - .detach(); - self.notification_task = Some(cx.spawn(async move |this, cx| { + Ok(()) + })); + + self.tasks.push(cx.spawn(async move |this, cx| { while let Ok(message) = rx.recv_async().await { match message { Signal::Message(message) => { this.update(cx, |this, cx| { this.new_message(message, cx); - }) - .ok(); + })?; } Signal::Eose => { this.update(cx, |this, cx| { this.get_rooms(cx); - }) - .ok(); + })?; } }; } + + Ok(()) })); } @@ -204,7 +199,7 @@ impl ChatRegistry { fn tracking(&mut self, cx: &mut Context) { let status = self.tracking_flag.clone(); - self.tracking_task = Some(cx.background_spawn(async move { + self.tasks.push(cx.background_spawn(async move { let loop_duration = Duration::from_secs(10); loop { diff --git a/crates/coop/Cargo.toml b/crates/coop/Cargo.toml index 94a62ac..cbff6f1 100644 --- a/crates/coop/Cargo.toml +++ b/crates/coop/Cargo.toml @@ -60,4 +60,4 @@ futures.workspace = true oneshot.workspace = true indexset = "0.12.3" -tracing-subscriber = { version = "0.3.18", features = ["fmt"] } +tracing-subscriber = { version = "0.3.18", features = ["fmt", "env-filter"] } diff --git a/crates/coop/src/main.rs b/crates/coop/src/main.rs index 530928f..14f69fa 100644 --- a/crates/coop/src/main.rs +++ b/crates/coop/src/main.rs @@ -82,7 +82,7 @@ fn main() { settings::init(cx); // Initialize the nostr client - state::init(cx); + state::init(window, cx); // Initialize relay auth registry relay_auth::init(window, cx); @@ -96,7 +96,7 @@ fn main() { device::init(window, cx); // Initialize app registry - chat::init(cx); + chat::init(window, cx); // Initialize auto update auto_update::init(cx); diff --git a/crates/device/src/lib.rs b/crates/device/src/lib.rs index d595d89..f9b21e3 100644 --- a/crates/device/src/lib.rs +++ b/crates/device/src/lib.rs @@ -67,7 +67,7 @@ impl DeviceRegistry { RelayState::Idle => { this.reset(cx); } - RelayState::Configured => { + RelayState::Configured(_) => { this.get_announcement(cx); } _ => {} diff --git a/crates/relay_auth/src/lib.rs b/crates/relay_auth/src/lib.rs index 5f3ff0f..c19c847 100644 --- a/crates/relay_auth/src/lib.rs +++ b/crates/relay_auth/src/lib.rs @@ -1,14 +1,14 @@ use std::borrow::Cow; use std::cell::Cell; use std::collections::HashSet; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::rc::Rc; use std::sync::Arc; use anyhow::{anyhow, Context as AnyhowContext, Error}; use gpui::{ App, AppContext, Context, Entity, Global, IntoElement, ParentElement, SharedString, Styled, - Subscription, Task, Window, + Task, Window, }; use nostr_sdk::prelude::*; use settings::{AppSettings, AuthMode}; @@ -27,18 +27,12 @@ pub fn init(window: &mut Window, cx: &mut App) { } /// Authentication request -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] struct AuthRequest { url: RelayUrl, challenge: String, } -impl Hash for AuthRequest { - fn hash(&self, state: &mut H) { - self.challenge.hash(state); - } -} - impl AuthRequest { pub fn new(challenge: impl Into, url: RelayUrl) -> Self { Self { @@ -74,9 +68,6 @@ pub struct RelayAuth { /// Tasks for asynchronous operations tasks: SmallVec<[Task<()>; 2]>, - - /// Event subscriptions - _subscriptions: SmallVec<[Subscription; 1]>, } impl RelayAuth { @@ -92,22 +83,13 @@ impl RelayAuth { /// Create a new relay auth instance fn new(window: &mut Window, cx: &mut Context) -> Self { - let nostr = NostrRegistry::global(cx); - let mut subscriptions = smallvec![]; - - subscriptions.push( - // Observe the nostr state - cx.observe_in(&nostr, window, move |this, state, window, cx| { - if state.read(cx).connected() { - this.handle_notifications(window, cx) - } - }), - ); + cx.defer_in(window, |this, window, cx| { + this.handle_notifications(window, cx); + }); Self { pending_events: HashSet::default(), tasks: smallvec![], - _subscriptions: subscriptions, } } @@ -119,7 +101,8 @@ impl RelayAuth { // Channel for communication between nostr and gpui let (tx, rx) = flume::bounded::(256); - cx.background_spawn(async move { + self.tasks.push(cx.background_spawn(async move { + log::info!("Started handling nostr notifications"); let mut notifications = client.notifications(); let mut challenges: HashSet> = HashSet::default(); @@ -128,8 +111,8 @@ impl RelayAuth { match message { RelayMessage::Auth { challenge } => { if challenges.insert(challenge.clone()) { - let request = AuthRequest::new(challenge, relay_url); - let signal = Signal::Auth(Arc::new(request)); + let request = Arc::new(AuthRequest::new(challenge, relay_url)); + let signal = Signal::Auth(request); tx.send_async(signal).await.ok(); } @@ -149,8 +132,7 @@ impl RelayAuth { } } } - }) - .detach(); + })); self.tasks.push(cx.spawn_in(window, async move |this, cx| { while let Ok(signal) = rx.recv_async().await { diff --git a/crates/settings/src/lib.rs b/crates/settings/src/lib.rs index 4a43bec..977d97b 100644 --- a/crates/settings/src/lib.rs +++ b/crates/settings/src/lib.rs @@ -52,8 +52,8 @@ pub enum AuthMode { /// Signer kind #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub enum SignerKind { - #[default] Auto, + #[default] User, Encryption, } diff --git a/crates/state/src/constants.rs b/crates/state/src/constants.rs index c0a1a2d..f1bc85d 100644 --- a/crates/state/src/constants.rs +++ b/crates/state/src/constants.rs @@ -37,7 +37,9 @@ pub const USER_GIFTWRAP: &str = "user-gift-wraps"; pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"]; /// Default search relays -pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://search.nos.today"]; +pub const SEARCH_RELAYS: [&str; 1] = ["wss://antiprimal.net"]; + +pub const INDEXER_RELAYS: [&str; 1] = ["wss://indexer.coracle.social"]; /// Default bootstrap relays pub const BOOTSTRAP_RELAYS: [&str; 3] = [ diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index 1881162..70873a3 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -5,7 +5,7 @@ use std::time::Duration; use anyhow::{anyhow, Context as AnyhowContext, Error}; use common::config_dir; -use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task}; +use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task, Window}; use nostr_connect::prelude::*; use nostr_gossip_memory::prelude::*; use nostr_lmdb::NostrLmdb; @@ -19,7 +19,7 @@ pub use constants::*; pub use nip05::*; pub use signer::*; -pub fn init(cx: &mut App) { +pub fn init(window: &mut Window, cx: &mut App) { // rustls uses the `aws_lc_rs` provider by default // This only errors if the default provider has already // been installed. We can ignore this `Result`. @@ -30,7 +30,7 @@ pub fn init(cx: &mut App) { // Initialize the tokio runtime gpui_tokio::init(cx); - NostrRegistry::set_global(cx.new(NostrRegistry::new), cx); + NostrRegistry::set_global(cx.new(|cx| NostrRegistry::new(window, cx)), cx); } struct GlobalNostrRegistry(Entity); @@ -82,7 +82,7 @@ impl NostrRegistry { } /// Create a new nostr instance - fn new(cx: &mut Context) -> Self { + fn new(window: &mut Window, cx: &mut Context) -> Self { // Construct the nostr lmdb instance let lmdb = cx.foreground_executor().block_on(async move { NostrLmdb::open(config_dir().join("nostr")) @@ -122,7 +122,7 @@ impl NostrRegistry { subscriptions.push( // Observe the NIP-65 state cx.observe(&nip65, |this, state, cx| { - if state.read(cx).configured() { + if state.read(cx).configured().is_some() { this.get_profile(cx); this.get_messaging_relays(cx); } @@ -131,20 +131,15 @@ impl NostrRegistry { subscriptions.push( // Observe the NIP-17 state - cx.observe(&nip17, |this, state, cx| { - if state.read(cx) == &RelayState::Configured { - this.get_messages(cx); + cx.observe(&nip17, |this, nip17, cx| { + if let Some(event) = nip17.read(cx).configured().cloned() { + this.subscribe_to_giftwrap_events(&event, cx); }; }), ); - cx.defer(|cx| { - let nostr = NostrRegistry::global(cx); - - // Connect to the bootstrapping relays - nostr.update(cx, |this, cx| { - this.connect(cx); - }); + cx.defer_in(window, |this, _window, cx| { + this.connect(cx); }); Self { @@ -164,36 +159,35 @@ impl NostrRegistry { fn connect(&mut self, cx: &mut Context) { let client = self.client(); - let task: Task> = cx.background_spawn(async move { - // Add search relay to the relay pool - for url in SEARCH_RELAYS.into_iter() { - client.add_relay(url).and_connect().await?; - } - - // Add bootstrap relay to the relay pool - for url in BOOTSTRAP_RELAYS.into_iter() { - client.add_relay(url).and_connect().await?; - } - - Ok(()) - }); - self.tasks.push(cx.spawn(async move |this, cx| { - // Wait for the task to complete - task.await?; - - // Update the state - this.update(cx, |this, cx| { - this.set_connected(cx); - })?; - - // Small delay cx.background_executor() - .timer(Duration::from_millis(200)) + .await_on_background(async move { + // Add search relay to the relay pool + for url in INDEXER_RELAYS.into_iter() { + client + .add_relay(url) + .capabilities(RelayCapabilities::DISCOVERY) + .await + .ok(); + } + + // Add search relay to the relay pool + for url in SEARCH_RELAYS.into_iter() { + client.add_relay(url).await.ok(); + } + + // Add bootstrap relay to the relay pool + for url in BOOTSTRAP_RELAYS.into_iter() { + client.add_relay(url).await.ok(); + } + + client.connect().await; + }) .await; // Update the state this.update(cx, |this, cx| { + this.set_connected(cx); this.get_signer(cx); })?; @@ -284,15 +278,36 @@ impl NostrRegistry { } /// Reset all relay states - pub fn reset_relay_states(&mut self, cx: &mut Context) { + pub fn reset_relays(&mut self, cx: &mut Context) { + let client = self.client(); + self.nip65.update(cx, |this, cx| { *this = RelayState::default(); cx.notify(); }); + self.nip17.update(cx, |this, cx| { *this = RelayState::default(); cx.notify(); }); + + self.tasks.push(cx.background_spawn(async move { + let relays = client.relays().await; + + for (relay_url, relay) in relays.iter() { + let url = relay_url.as_str(); + let default_relay = BOOTSTRAP_RELAYS.contains(&url) + || SEARCH_RELAYS.contains(&url) + || INDEXER_RELAYS.contains(&url); + + if !default_relay { + relay.unsubscribe_all().await?; + relay.disconnect(); + } + } + + Ok(()) + })); } /// Set the signer for the nostr client and verify the public key @@ -308,6 +323,9 @@ impl NostrRegistry { // Update signer signer.switch(new, owned).await; + // Unsubscribe from all subscriptions + client.unsubscribe_all().await?; + // Verify signer let signer = client.signer().context("Signer not found")?; let public_key = signer.get_public_key().await?; @@ -322,7 +340,7 @@ impl NostrRegistry { // Update states this.update(cx, |this, cx| { - this.reset_relay_states(cx); + this.reset_relays(cx); this.get_relay_list(cx); })?; @@ -365,8 +383,6 @@ impl NostrRegistry { while let Some((_url, res)) = stream.next().await { match res { Ok(event) => { - log::info!("Received relay list event: {event:?}"); - // Construct a filter to continuously receive relay list events let filter = Filter::new() .kind(Kind::RelayList) @@ -382,7 +398,7 @@ impl NostrRegistry { // Subscribe to the relay list events client.subscribe(target).await?; - return Ok(RelayState::Configured); + return Ok(RelayState::Configured(Box::new(event))); } Err(e) => { log::error!("Failed to receive relay list event: {e}"); @@ -443,8 +459,6 @@ impl NostrRegistry { while let Some((_url, res)) = stream.next().await { match res { Ok(event) => { - log::info!("Received messaging relays event: {event:?}"); - // Construct a filter to continuously receive relay list events let filter = Filter::new() .kind(Kind::InboxRelays) @@ -454,7 +468,7 @@ impl NostrRegistry { // Subscribe to the relay list events client.subscribe(filter).await?; - return Ok(RelayState::Configured); + return Ok(RelayState::Configured(Box::new(event))); } Err(e) => { log::error!("Failed to get messaging relays: {e}"); @@ -485,24 +499,33 @@ impl NostrRegistry { } /// Continuously get gift wrap events for the current user in their messaging relays - fn get_messages(&mut self, cx: &mut Context) { + fn subscribe_to_giftwrap_events(&mut self, relay_list: &Event, cx: &mut Context) { let client = self.client(); let signer = self.signer(); - let messaging_relays = self.messaging_relays(cx); + let relay_urls: Vec = nip17::extract_relay_list(relay_list).cloned().collect(); let task: Task> = cx.background_spawn(async move { - let urls = messaging_relays.await; let public_key = signer.get_public_key().await?; + for url in relay_urls.iter() { + client.add_relay(url).and_connect().await?; + } + let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); let id = SubscriptionId::new(USER_GIFTWRAP); // Construct target for subscription - let target: HashMap<&RelayUrl, Filter> = - urls.iter().map(|relay| (relay, filter.clone())).collect(); + let target: HashMap<&RelayUrl, Filter> = relay_urls + .iter() + .map(|relay| (relay, filter.clone())) + .collect(); - client.subscribe(target).with_id(id).await?; - log::info!("Subscribed to user gift-wrap messages"); + let output = client.subscribe(target).with_id(id).await?; + + log::info!( + "Successfully subscribed to user gift-wrap messages on: {:?}", + output.success + ); Ok(()) }); @@ -973,7 +996,7 @@ fn default_relay_list() -> Vec<(RelayUrl, Option)> { Some(RelayMetadata::Write), ), ( - RelayUrl::parse("wss://relay.primal.net/").unwrap(), + RelayUrl::parse("wss://relay.damus.io/").unwrap(), Some(RelayMetadata::Read), ), ( @@ -985,18 +1008,18 @@ fn default_relay_list() -> Vec<(RelayUrl, Option)> { fn default_messaging_relays() -> Vec { vec![ - RelayUrl::parse("wss://auth.nostr1.com/").unwrap(), + //RelayUrl::parse("wss://auth.nostr1.com/").unwrap(), RelayUrl::parse("wss://nip17.com/").unwrap(), ] } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub enum RelayState { #[default] Idle, Checking, NotConfigured, - Configured, + Configured(Box), } impl RelayState { @@ -1012,8 +1035,11 @@ impl RelayState { matches!(self, RelayState::NotConfigured) } - pub fn configured(&self) -> bool { - matches!(self, RelayState::Configured) + pub fn configured(&self) -> Option<&Event> { + match self { + RelayState::Configured(event) => Some(event), + _ => None, + } } }