diff --git a/crates/chat/src/lib.rs b/crates/chat/src/lib.rs index 3991887..2736d30 100644 --- a/crates/chat/src/lib.rs +++ b/crates/chat/src/lib.rs @@ -41,8 +41,6 @@ pub enum ChatEvent { CloseRoom(u64), /// An event to notify UI about a new chat request Ping, - /// An event to notify UI that the chat registry has subscribed to messaging relays - Subscribed, /// An error occurred Error(SharedString), } @@ -78,6 +76,9 @@ impl Signal { /// Chat Registry #[derive(Debug)] pub struct ChatRegistry { + /// Whether the chat registry is currently initializing. + pub initializing: bool, + /// Chat rooms rooms: Vec>, @@ -130,9 +131,9 @@ impl ChatRegistry { cx.subscribe(&nostr, |this, _state, event, cx| { if event == &StateEvent::SignerSet { this.reset(cx); - this.get_rooms(cx); this.get_contact_list(cx); this.get_messages(cx); + this.get_rooms(cx); }; }), ); @@ -145,6 +146,7 @@ impl ChatRegistry { }); Self { + initializing: true, rooms: vec![], trashes: cx.new(|_| BTreeSet::default()), seens: Arc::new(RwLock::new(HashMap::default())), @@ -327,13 +329,13 @@ impl ChatRegistry { /// Get all messages for current user pub fn get_messages(&mut self, cx: &mut Context) { - let task = self.subscribe(cx); + let task = self.subscribe_gift_wrap_events(cx); self.tasks.push(cx.spawn(async move |this, cx| { match task.await { Ok(_) => { - this.update(cx, |_this, cx| { - cx.emit(ChatEvent::Subscribed); + this.update(cx, |this, cx| { + this.set_initializing(false, cx); })?; } Err(e) => { @@ -354,6 +356,7 @@ impl ChatRegistry { cx.background_spawn(async move { let public_key = signer.get_public_key().await?; + let id = SubscriptionId::new("inbox-relay"); // Construct filter for inbox relays let filter = Filter::new() @@ -364,12 +367,12 @@ impl ChatRegistry { // Stream events from user's write relays let mut stream = client .stream_events(filter) + .with_id(id) .timeout(Duration::from_secs(TIMEOUT)) .await?; while let Some((_url, res)) = stream.next().await { if let Ok(event) = res { - log::debug!("Got event: {:?}", event); let urls: Vec = nip17::extract_owned_relay_list(event).collect(); return Ok(urls); } @@ -380,7 +383,7 @@ impl ChatRegistry { } /// Continuously get gift wrap events for the current user in their messaging relays - fn subscribe(&self, cx: &App) -> Task> { + fn subscribe_gift_wrap_events(&self, cx: &App) -> Task> { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); let signer = nostr.read(cx).signer(); @@ -414,6 +417,12 @@ impl ChatRegistry { }) } + /// Set the initializing status of the chat registry + fn set_initializing(&mut self, initializing: bool, cx: &mut Context) { + self.initializing = initializing; + cx.notify(); + } + /// Get the loading status of the chat registry pub fn loading(&self) -> bool { self.tracking_flag.load(Ordering::Acquire) @@ -557,7 +566,12 @@ impl ChatRegistry { /// Reset the registry. pub fn reset(&mut self, cx: &mut Context) { + self.initializing = true; self.rooms.clear(); + self.trashes.update(cx, |this, cx| { + this.clear(); + cx.notify(); + }); cx.notify(); } diff --git a/crates/coop/src/workspace.rs b/crates/coop/src/workspace.rs index 3049172..0867b49 100644 --- a/crates/coop/src/workspace.rs +++ b/crates/coop/src/workspace.rs @@ -177,16 +177,6 @@ impl Workspace { window.push_notification(note, cx); } - DeviceEvent::NotSubscribe { reason } => { - let note = Notification::new() - .id::() - .title("Cannot getting messages") - .message(reason) - .autohide(false) - .with_kind(NotificationKind::Error); - - window.push_notification(note, cx); - } DeviceEvent::Error(error) => { window.push_notification(Notification::error(error).autohide(false), cx); } @@ -650,6 +640,12 @@ impl Workspace { } fn titlebar_right(&mut self, cx: &mut Context) -> impl IntoElement { + let chat = ChatRegistry::global(cx); + let initializing = chat.read(cx).initializing; + + let device = DeviceRegistry::global(cx); + let device_initializing = device.read(cx).initializing; + let nostr = NostrRegistry::global(cx); let signer = nostr.read(cx).signer(); @@ -701,9 +697,13 @@ impl Workspace { .tooltip("Decoupled encryption key") .small() .ghost() + .loading(device_initializing) + .when(device_initializing, |this| { + this.label("Dekey") + .xsmall() + .tooltip("Loading decoupled encryption key...") + }) .dropdown_menu(move |this, _window, cx| { - let device = DeviceRegistry::global(cx); - let subscribing = device.read(cx).subscribing; let requesting = device.read(cx).requesting; this.min_w(px(260.)) @@ -724,30 +724,6 @@ impl Workspace { .child(SharedString::from("Waiting for approval...")) })) }) - .item(PopupMenuItem::element(move |_window, cx| { - h_flex() - .px_1() - .w_full() - .gap_2() - .text_sm() - .when(!subscribing, |this| { - this.text_color(cx.theme().text_muted) - }) - .child(div().size_1p5().rounded_full().map(|this| { - if subscribing { - this.bg(cx.theme().icon_accent) - } else { - this.bg(cx.theme().icon_muted) - } - })) - .map(|this| { - if subscribing { - this.child("Listening for messages") - } else { - this.child("Idle") - } - }) - })) .separator() .menu_with_icon( "Backup", @@ -777,8 +753,13 @@ impl Workspace { .icon(IconName::Inbox) .small() .ghost() + .loading(initializing) + .when(initializing, |this| { + this.label("Inbox") + .xsmall() + .tooltip("Getting inbox messages...") + }) .dropdown_menu(move |this, _window, cx| { - let chat = ChatRegistry::global(cx); let persons = PersonRegistry::global(cx); let profile = persons.read(cx).get(&public_key, cx); @@ -832,12 +813,12 @@ impl Workspace { Box::new(Command::RefreshMessagingRelays), ) .menu_with_icon( - "Update gossip relays", + "Manage gossip relays", IconName::Relay, Box::new(Command::ShowRelayList), ) .menu_with_icon( - "Update messaging relays", + "Manage messaging relays", IconName::Settings, Box::new(Command::ShowMessaging), ) diff --git a/crates/device/src/lib.rs b/crates/device/src/lib.rs index f0fdbc3..cc9386d 100644 --- a/crates/device/src/lib.rs +++ b/crates/device/src/lib.rs @@ -41,8 +41,6 @@ pub enum DeviceEvent { Creating, /// Encryption key is not set NotSet { reason: SharedString }, - /// An event to notify that Coop isn't subscribed to gift wrap events - NotSubscribe { reason: SharedString }, /// An error occurred Error(SharedString), } @@ -55,15 +53,6 @@ impl DeviceEvent { Self::Error(error.into()) } - pub fn not_subscribe(reason: T) -> Self - where - T: Into, - { - Self::NotSubscribe { - reason: reason.into(), - } - } - pub fn not_set(reason: T) -> Self where T: Into, @@ -79,14 +68,14 @@ impl DeviceEvent { /// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md #[derive(Debug)] pub struct DeviceRegistry { - /// Whether the registry is currently subscribing to gift wrap events - pub subscribing: bool, + /// Whether the registry is currently initializing + pub initializing: bool, /// Whether the registry is waiting for encryption key approval from other devices pub requesting: bool, /// Whether there is a pending request for encryption key approval - pub has_pending_request: bool, + pub pending_request: bool, /// Async tasks tasks: Vec>>, @@ -111,10 +100,13 @@ impl DeviceRegistry { /// Create a new device registry instance fn new(window: &mut Window, cx: &mut Context) -> Self { let nostr = NostrRegistry::global(cx); + + // Subscribe to nostr state events let subscription = cx.subscribe_in(&nostr, window, |this, _e, event, _window, cx| { if event == &StateEvent::SignerSet { - this.set_subscribing(false, cx); + this.set_initializing(true, cx); this.set_requesting(false, cx); + this.get_announcement(cx); }; }); @@ -123,9 +115,9 @@ impl DeviceRegistry { }); Self { - subscribing: false, + initializing: true, requesting: false, - has_pending_request: false, + pending_request: false, tasks: vec![], _subscription: Some(subscription), } @@ -139,7 +131,6 @@ impl DeviceRegistry { self.tasks.push(cx.background_spawn(async move { let mut notifications = client.notifications(); let mut processed_events = HashSet::new(); - let mut found_relay_list = false; while let Some(notification) = notifications.next().await { if let ClientNotification::Message { message, .. } = notification @@ -151,17 +142,6 @@ impl DeviceRegistry { } match event.kind { - Kind::RelayList => { - // Skip if the relay list has already been found - if found_relay_list { - continue; - } - // Verify the relay list event is signed by the user's signer - if verify_author(&client, event.as_ref()).await { - tx.send_async(event.into_owned()).await?; - found_relay_list = true; - } - } Kind::Custom(4454) => { if verify_author(&client, event.as_ref()).await { tx.send_async(event.into_owned()).await?; @@ -202,9 +182,9 @@ impl DeviceRegistry { })); } - /// Set whether the registry is currently subscribing to gift wrap events - fn set_subscribing(&mut self, subscribing: bool, cx: &mut Context) { - self.subscribing = subscribing; + /// Set whether the registry is currently initializing + fn set_initializing(&mut self, initializing: bool, cx: &mut Context) { + self.initializing = initializing; cx.notify(); } @@ -215,8 +195,8 @@ impl DeviceRegistry { } /// Set whether there is a pending request for encryption key approval - fn set_has_pending_request(&mut self, pending: bool, cx: &mut Context) { - self.has_pending_request = pending; + fn set_pending_request(&mut self, pending: bool, cx: &mut Context) { + self.pending_request = pending; cx.notify(); } @@ -243,16 +223,16 @@ impl DeviceRegistry { /// Get all messages for encryption keys fn get_messages(&mut self, cx: &mut Context) { - let task = self.subscribe_to_giftwrap_events(cx); + let task = self.subscribe_gift_wrap_events(cx); self.tasks.push(cx.spawn(async move |this, cx| { if let Err(e) = task.await { this.update(cx, |_this, cx| { - cx.emit(DeviceEvent::not_subscribe(e.to_string())); + cx.emit(DeviceEvent::error(e.to_string())); })?; } else { this.update(cx, |this, cx| { - this.set_subscribing(true, cx); + this.set_initializing(false, cx); })?; } Ok(()) @@ -260,7 +240,7 @@ impl DeviceRegistry { } /// Continuously get gift wrap events for the current user in their messaging relays - fn subscribe_to_giftwrap_events(&self, cx: &App) -> Task> { + fn subscribe_gift_wrap_events(&self, cx: &App) -> Task> { let persons = PersonRegistry::global(cx); let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); @@ -471,21 +451,16 @@ impl DeviceRegistry { self.tasks.push(cx.background_spawn(async move { let public_key = signer.get_public_key().await?; + let id = SubscriptionId::new("dekey-requests"); // Construct a filter for encryption key requests - let now = Filter::new() + let filter = Filter::new() .kind(Kind::Custom(4454)) .author(public_key) .since(Timestamp::now()); - // Construct a filter for the last encryption key request - let last = Filter::new() - .kind(Kind::Custom(4454)) - .author(public_key) - .limit(1); - // Subscribe to the device key requests on user's write relays - client.subscribe(vec![now, last]).await?; + client.subscribe(vec![filter]).with_id(id).await?; Ok(()) })); @@ -687,10 +662,10 @@ impl DeviceRegistry { /// Handle encryption request fn ask_for_approval(&mut self, event: Event, window: &mut Window, cx: &mut Context) { // Ignore if there is already a pending request - if self.has_pending_request { + if self.pending_request { return; } - self.set_has_pending_request(true, cx); + self.set_pending_request(true, cx); // Show notification let notification = self.notification(event, cx); diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index 9760ffa..9f177eb 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -133,14 +133,7 @@ impl NostrRegistry { .signer(signer.clone()) .database(lmdb) .gossip(NostrGossipMemory::unbounded()) - .gossip_config( - GossipConfig::default() - .no_background_refresh() - .sync_idle_timeout(Duration::from_secs(TIMEOUT)) - .sync_initial_timeout(Duration::from_millis(600)), - ) .automatic_authentication(false) - .verify_subscriptions(true) .connect_timeout(Duration::from_secs(10)) .sleep_when_idle(SleepWhenIdle::Enabled { timeout: Duration::from_secs(600), @@ -280,7 +273,7 @@ impl NostrRegistry { let app_keys = self.app_keys.clone(); if let Ok(payload) = std::fs::read_to_string(key_path) { - if payload.starts_with("nsec1") || payload.starts_with("bunker://") { + if !payload.is_empty() { cx.background_spawn(async move { let decrypted = app_keys.nip44_decrypt(&public_key, &payload).await?; let secret = SecretKey::parse(&decrypted)?; @@ -435,11 +428,7 @@ impl NostrRegistry { let event = EventBuilder::nip17_relay_list(relays).sign(&signer).await?; // Publish messaging relay list event - client - .send_event(&event) - .to_nip65() - .ack_policy(AckPolicy::none()) - .await?; + client.send_event(&event).to_nip65().await?; // Write user's credentials to the system keyring write_secret.await?;