From 40166fd0715e55979a21129f6d6f8127f7fd8287 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Thu, 23 Jul 2026 16:12:36 +0700 Subject: [PATCH] refactor --- crates/chat/src/lib.rs | 130 ++++++++++++++-------------- crates/person/src/person.rs | 4 +- crates/state/src/lib.rs | 61 +++++++++---- crates/workspace/src/lib.rs | 17 +++- crates/workspace/src/sidebar/mod.rs | 2 +- 5 files changed, 129 insertions(+), 85 deletions(-) diff --git a/crates/chat/src/lib.rs b/crates/chat/src/lib.rs index b3f4eee..acd5c7f 100644 --- a/crates/chat/src/lib.rs +++ b/crates/chat/src/lib.rs @@ -47,16 +47,14 @@ pub enum ChatEvent { /// No Inbox Relays found, the app is not ready to subscribe messages InboxRelayNotFound, /// An error occurred - Error(SharedString), + Error(String), } /// Channel signal. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] enum Signal { /// Inbox Relays found, the app is ready to subscribe messages - InboxReady(Box), - /// No Inbox Relays found, the app is not ready to subscribe messages - InboxRelayNotFound, + InboxReady, /// Message received from relay pool Message(NewMessage), /// Eose received from relay pool @@ -70,18 +68,6 @@ impl Signal { Self::Message(NewMessage::new(gift_wrap, rumor)) } - pub fn inbox_ready(event: &Event) -> Self { - Self::InboxReady(Box::new(event.to_owned())) - } - - pub fn inbox_relay_not_found() -> Self { - Self::InboxRelayNotFound - } - - pub fn eose() -> Self { - Self::Eose - } - pub fn error(event: &Event, reason: T) -> Self where T: Into, @@ -108,9 +94,6 @@ pub struct ChatRegistry { /// Tracking the status of unwrapping gift wrap events. tracking: Arc, - /// Whether the messaging relays have been found. - msg_relays_existed: Arc, - /// Channel for sending signals to the UI. signal_tx: flume::Sender, @@ -167,7 +150,6 @@ impl ChatRegistry { seens: Arc::new(RwLock::new(HashMap::default())), event_map: Arc::new(RwLock::new(HashMap::default())), tracking: Arc::new(AtomicBool::new(false)), - msg_relays_existed: Arc::new(AtomicBool::new(false)), signal_rx: rx, signal_tx: tx, tasks: smallvec![], @@ -182,8 +164,6 @@ impl ChatRegistry { let signer = nostr.read(cx).signer(); let tracking = self.tracking.clone(); - let msg_relays_existed = self.msg_relays_existed.clone(); - let seens = self.seens.clone(); let event_map = self.event_map.clone(); let trashes = self.trashes.downgrade(); @@ -208,12 +188,6 @@ impl ChatRegistry { match *message { RelayMessage::Event { event, .. } => { - // Keep track of which relays have seen this event - { - let mut seens = seens.write().await; - seens.entry(event.id).or_default().insert(relay_url); - } - // De-duplicate events by their ID if !processed_events.insert(event.id) { continue; @@ -222,12 +196,9 @@ impl ChatRegistry { // Handle msg relays event to determine when the app is ready to subscribe if event.kind == Kind::InboxRelays { let current_user = signer.get_public_key_async().await?; - + // Emit the inbox ready signal if event.pubkey == current_user { - // Mark that the msg relays have been found - msg_relays_existed.store(true, Ordering::Release); - // Emit the inbox ready signal - tx.send_async(Signal::inbox_ready(&event)).await?; + tx.send_async(Signal::InboxReady).await?; } } @@ -236,6 +207,12 @@ impl ChatRegistry { continue; } + // Keep track of which relays have seen this event + { + let mut seens = seens.write().await; + seens.entry(event.id).or_default().insert(relay_url); + } + // Extract the rumor from the gift wrap event match extract_rumor(&client, &signer, event.as_ref()).await { Ok(rumor) => { @@ -270,7 +247,7 @@ impl ChatRegistry { RelayMessage::EndOfStoredEvents(id) if (id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2) => { - tx.send_async(Signal::eose()).await?; + tx.send_async(Signal::Eose).await?; } _ => {} } @@ -287,14 +264,9 @@ impl ChatRegistry { this.new_message(message, cx); })?; } - Signal::InboxReady(event) => { + Signal::InboxReady => { this.update(cx, |this, cx| { - this.get_messages(&event, cx); - })?; - } - Signal::InboxRelayNotFound => { - this.update(cx, |_this, cx| { - cx.emit(ChatEvent::InboxRelayNotFound); + this.get_messages(cx); })?; } Signal::Eose => { @@ -367,20 +339,34 @@ impl ChatRegistry { Ok(()) })); - let tx = self.signal_tx.clone(); - let msg_relays_existed = self.msg_relays_existed.clone(); + let client = nostr.read(cx).client(); - // Reset the status flag - msg_relays_existed.store(false, Ordering::Release); + // Spawn a task to verify user inbox relays after 5 seconds + self.tasks.push(cx.spawn(async move |this, cx| { + cx.background_executor().timer(Duration::from_secs(5)).await; - // Wait for the msg relays to be found or timeout - self.tasks.push(cx.background_spawn(async move { - // Wait for 5 seconds - smol::Timer::after(Duration::from_secs(5)).await; + if !cx + .background_spawn(async move { + // Construct inbox relays filter + let filter = Filter::new() + .kind(Kind::InboxRelays) + .author(public_key) + .limit(1); - // Then check if the msg relays have been found - if !msg_relays_existed.load(Ordering::Acquire) { - tx.send_async(Signal::inbox_relay_not_found()).await?; + // Check the latest inbox relays event in database + client + .database() + .query(filter) + .await + .unwrap_or_default() + .first_owned() + .is_some() + }) + .await + { + this.update(cx, |_this, cx| { + cx.emit(ChatEvent::InboxRelayNotFound); + })?; } Ok(()) @@ -388,35 +374,47 @@ impl ChatRegistry { } /// Get all messages for the provided signer - fn get_messages(&mut self, msg_relays: &Event, cx: &mut Context) { + fn get_messages(&mut self, cx: &mut Context) { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); let signer = nostr.read(cx).signer(); - let urls: Vec = nip17::extract_relay_list(msg_relays).collect(); - let task: Task> = cx.background_spawn(async move { let public_key = signer.get_public_key_async().await?; - let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); - let id = SubscriptionId::new(format!("{}-msg", public_key.to_hex())); + + // Construct inbox relays filter + let filter = Filter::new() + .kind(Kind::InboxRelays) + .author(public_key) + .limit(1); + + // Get the latest inbox relays event in database + let event = client + .database() + .query(filter) + .await? + .first_owned() + .ok_or(anyhow::anyhow!("No inbox relays found"))?; + + // Extract relay list from event + let relays: Vec = nip17::extract_relay_list(&event).collect(); // Ensure relay connections - for url in urls.iter() { + for url in relays.iter() { client.add_relay(url).and_connect().await?; } + // Construct gift wrap event filter + let filter = Filter::new().kind(Kind::GiftWrap).pubkey(public_key); + let id = SubscriptionId::new(format!("{}-msg", public_key.to_hex())); + // Construct target for subscription - let target: HashMap = urls + let target: HashMap = relays .into_iter() .map(|relay| (relay, filter.clone())) .collect(); - let output = client.subscribe(target).with_id(id).await?; - - log::info!( - "Successfully subscribed to gift-wrap messages on: {:?}", - output.success - ); + client.subscribe(target).with_id(id).await?; Ok(()) }); @@ -424,7 +422,7 @@ impl ChatRegistry { self.tasks.push(cx.spawn(async move |this, cx| { if let Err(e) = task.await { this.update(cx, |_this, cx| { - cx.emit(ChatEvent::Error(SharedString::from(e.to_string()))); + cx.emit(ChatEvent::Error(e.to_string())); })?; } Ok(()) diff --git a/crates/person/src/person.rs b/crates/person/src/person.rs index 53e5a5d..01e89db 100644 --- a/crates/person/src/person.rs +++ b/crates/person/src/person.rs @@ -126,13 +126,13 @@ impl Person { if let Some(display_name) = self.metadata().display_name.as_ref() && !display_name.is_empty() { - return SharedString::from(display_name); + return SharedString::from(display_name.trim()); } if let Some(name) = self.metadata().name.as_ref() && !name.is_empty() { - return SharedString::from(name); + return SharedString::from(name.trim()); } SharedString::from(shorten_pubkey(self.public_key(), 4)) diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index b7bea9c..08a1834 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -3,7 +3,7 @@ use std::time::Duration; use anyhow::{Error, anyhow}; use common::config_dir; -use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Task, Window}; +use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task, Window}; use nostr_gossip_memory::prelude::*; #[cfg(not(target_arch = "wasm32"))] use nostr_lmdb::prelude::*; @@ -53,17 +53,25 @@ pub enum StateEvent { /// Connected to the bootstrapping relay Connected, /// An error occurred - Error(SharedString), + Error(String), } impl StateEvent { pub fn error(error: T) -> Self where - T: Into, + T: Into, { Self::Error(error.into()) } + pub fn is_connecting(&self) -> bool { + matches!(self, StateEvent::Connecting) + } + + pub fn is_connected(&self) -> bool { + matches!(self, StateEvent::Connected) + } + pub fn signer_changed(&self) -> bool { matches!(self, StateEvent::SignerChanged) } @@ -126,9 +134,10 @@ impl NostrRegistry { }) .build(); - // Run at the end of current cycle + // Connect to bootstrap relays after the window is ready cx.defer_in(window, |this, _window, cx| { - this.connect(cx); + this.connect_bootstrap_relays(cx); + this.check_credential(cx); }); Self { @@ -163,20 +172,34 @@ impl NostrRegistry { ::Error: std::error::Error + Send + Sync + 'static, { cx.spawn(async move |this, cx| { - let current_user = new_signer.get_public_key_async().await.ok(); - this.update(cx, |this, cx| { - this.current_user = current_user; - cx.emit(StateEvent::SignerChanged); - }) - .ok(); + match new_signer.get_public_key_async().await { + Ok(public_key) => { + this.update(cx, |this, cx| { + this.signer.swap_inner(new_signer); + this.current_user = Some(public_key); + cx.emit(StateEvent::SignerChanged); + cx.notify(); + }) + .ok(); + } + Err(e) => { + this.update(cx, |_this, cx| { + cx.emit(StateEvent::error(e.to_string())); + }) + .ok(); + } + }; }) .detach(); } /// Connect to the bootstrapping relays - fn connect(&mut self, cx: &mut Context) { + fn connect_bootstrap_relays(&mut self, cx: &mut Context) { let client = self.client(); + // Emit connecting event + cx.emit(StateEvent::Connecting); + let task: Task> = cx.background_spawn(async move { // Add indexer relay to the relay pool for url in INDEXER_RELAYS.into_iter() { @@ -197,9 +220,6 @@ impl NostrRegistry { Ok(()) }); - // Emit connecting event - cx.emit(StateEvent::Connecting); - self.tasks.push(cx.spawn(async move |this, cx| { if let Err(e) = task.await { this.update(cx, |_this, cx| { @@ -215,6 +235,17 @@ impl NostrRegistry { })); } + fn check_credential(&mut self, cx: &mut Context) { + self.tasks.push(cx.spawn(async move |this, cx| { + this.update(cx, |this, cx| { + // TODO: check credential + cx.notify(); + })?; + + Ok(()) + })); + } + /// Get the public key of a NIP-05 address pub fn query_address(&self, addr: Nip05Address, cx: &App) -> Task> { let client = self.client(); diff --git a/crates/workspace/src/lib.rs b/crates/workspace/src/lib.rs index 98f17b8..bf0593e 100644 --- a/crates/workspace/src/lib.rs +++ b/crates/workspace/src/lib.rs @@ -81,6 +81,17 @@ impl Workspace { let mut subscriptions = smallvec![]; + subscriptions.push( + // Observe sign in state changes + cx.observe_in(&nostr, window, move |this, nostr, window, cx| { + if nostr.read(cx).current_user().is_some() { + this.set_center_layout(window, cx); + } else { + this.import_identity(window, cx); + } + }), + ); + subscriptions.push( // Observe system appearance and update theme cx.observe_window_appearance(window, |_this, window, cx| { @@ -90,7 +101,7 @@ impl Workspace { subscriptions.push( // Subscribe to the nostr events - cx.subscribe_in(&nostr, window, move |_this, _state, event, window, cx| { + cx.subscribe_in(&nostr, window, move |this, _state, event, window, cx| { match event { StateEvent::Connecting => { let note = Notification::new() @@ -108,6 +119,10 @@ impl Workspace { window.push_notification(note, cx); } + StateEvent::SignerChanged => { + this.set_center_layout(window, cx); + window.close_all_modals(cx); + } _ => {} }; }), diff --git a/crates/workspace/src/sidebar/mod.rs b/crates/workspace/src/sidebar/mod.rs index 32705ad..0b884ec 100644 --- a/crates/workspace/src/sidebar/mod.rs +++ b/crates/workspace/src/sidebar/mod.rs @@ -462,7 +462,7 @@ impl Sidebar { }); RoomEntry::new(range.start + ix) - .name(profile.name()) + .name(profile.name().trim()) .avatar(profile.avatar()) .on_click(handler) .selected(selected)