diff --git a/crates/chat/src/room.rs b/crates/chat/src/room.rs index af0fdf4..713a32a 100644 --- a/crates/chat/src/room.rs +++ b/crates/chat/src/room.rs @@ -1,5 +1,4 @@ use std::cmp::Ordering; -use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::time::Duration; @@ -10,7 +9,7 @@ use itertools::Itertools; use nostr_sdk::prelude::*; use person::{Person, PersonRegistry}; use settings::{RoomConfig, SignerKind}; -use state::{NostrRegistry, BOOTSTRAP_RELAYS, TIMEOUT}; +use state::{NostrRegistry, TIMEOUT}; use crate::NewMessage; @@ -333,9 +332,6 @@ impl Room { let signer = nostr.read(cx).signer(); let sender = signer.public_key(); - // Get room's id - let id = self.id; - // Get all members, excluding the sender let members: Vec = self .members @@ -345,30 +341,27 @@ impl Room { .collect(); cx.background_spawn(async move { - let id = SubscriptionId::new(format!("room-{id}")); let opts = SubscribeAutoCloseOptions::default() .exit_policy(ReqExitPolicy::ExitOnEOSE) .timeout(Some(Duration::from_secs(TIMEOUT))); - // Construct filters for each member - let filters: Vec = members - .into_iter() - .map(|public_key| { - Filter::new() - .author(public_key) - .kind(Kind::RelayList) - .limit(1) - }) - .collect(); + for public_key in members.into_iter() { + let inbox = Filter::new() + .author(public_key) + .kind(Kind::InboxRelays) + .limit(1); - // Construct target for subscription - let target: HashMap<&str, Vec> = BOOTSTRAP_RELAYS - .into_iter() - .map(|relay| (relay, filters.clone())) - .collect(); + let announcement = Filter::new() + .author(public_key) + .kind(Kind::Custom(10044)) + .limit(1); - // Subscribe to the target - client.subscribe(target).close_on(opts).with_id(id).await?; + // Subscribe to the target + client + .subscribe(vec![inbox, announcement]) + .close_on(opts) + .await?; + } Ok(()) }) @@ -491,15 +484,9 @@ impl Room { // Process each member for member in members { - let relays = member.messaging_relays(); let announcement = member.announcement(); let public_key = member.public_key(); - if relays.is_empty() { - reports.push(SendReport::new(public_key).error("No messaging relays")); - continue; - } - // Handle encryption signer requirements if signer_kind.encryption() { if announcement.is_none() { @@ -535,8 +522,7 @@ impl Room { SignerKind::User => (member.public_key(), user_signer.clone()), }; - match send_gift_wrap(&client, &signer, &receiver, &rumor, relays, public_key).await - { + match send_gift_wrap(&client, &signer, &receiver, &rumor, public_key).await { Ok((report, _)) => { reports.push(report); sents += 1; @@ -549,12 +535,10 @@ impl Room { // Send backup to current user if needed if backup && sents >= 1 { - let relays = sender.messaging_relays(); let public_key = sender.public_key(); let signer = encryption_signer.as_ref().unwrap_or(&user_signer); - match send_gift_wrap(&client, signer, &public_key, &rumor, relays, public_key).await - { + match send_gift_wrap(&client, signer, &public_key, &rumor, public_key).await { Ok((report, _)) => reports.push(report), Err(report) => reports.push(report), } @@ -571,22 +555,16 @@ async fn send_gift_wrap( signer: &T, receiver: &PublicKey, rumor: &UnsignedEvent, - relays: &[RelayUrl], public_key: PublicKey, ) -> Result<(SendReport, bool), SendReport> where T: NostrSigner + 'static, { - // Ensure relay connections - for url in relays { - client.add_relay(url).and_connect().await.ok(); - } - match EventBuilder::gift_wrap(signer, receiver, rumor.clone(), []).await { Ok(event) => { match client .send_event(&event) - .to(relays) + .to_nip17() .ack_policy(AckPolicy::none()) .await { diff --git a/crates/coop/src/main.rs b/crates/coop/src/main.rs index eb8ca3d..3dd7b0b 100644 --- a/crates/coop/src/main.rs +++ b/crates/coop/src/main.rs @@ -2,9 +2,9 @@ use std::sync::{Arc, Mutex}; use assets::Assets; use gpui::{ - actions, point, px, size, App, AppContext, Bounds, KeyBinding, Menu, MenuItem, SharedString, - TitlebarOptions, WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, - WindowOptions, + App, AppContext, Bounds, KeyBinding, Menu, MenuItem, SharedString, TitlebarOptions, + WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions, + actions, point, px, size, }; use gpui_platform::application; use state::{APP_ID, CLIENT_NAME}; @@ -86,7 +86,7 @@ fn main() { state::init(window, cx); // Initialize person registry - person::init(cx); + person::init(window, cx); // Initialize relay auth registry relay_auth::init(window, cx); diff --git a/crates/person/src/lib.rs b/crates/person/src/lib.rs index 3e58064..338bdfa 100644 --- a/crates/person/src/lib.rs +++ b/crates/person/src/lib.rs @@ -5,7 +5,7 @@ use std::time::Duration; use anyhow::{Error, anyhow}; use common::EventUtils; -use gpui::{App, AppContext, Context, Entity, Global, Task}; +use gpui::{App, AppContext, Context, Entity, Global, Task, Window}; use nostr_sdk::prelude::*; use smallvec::{SmallVec, smallvec}; use state::{Announcement, BOOTSTRAP_RELAYS, NostrRegistry, TIMEOUT}; @@ -14,8 +14,8 @@ mod person; pub use person::*; -pub fn init(cx: &mut App) { - PersonRegistry::set_global(cx.new(PersonRegistry::new), cx); +pub fn init(window: &mut Window, cx: &mut App) { + PersonRegistry::set_global(cx.new(|cx| PersonRegistry::new(window, cx)), cx); } struct GlobalPersonRegistry(Entity); @@ -42,7 +42,7 @@ pub struct PersonRegistry { sender: flume::Sender, /// Tasks for asynchronous operations - _tasks: SmallVec<[Task<()>; 4]>, + tasks: SmallVec<[Task<()>; 4]>, } impl PersonRegistry { @@ -57,7 +57,7 @@ impl PersonRegistry { } /// Create a new person registry instance - fn new(cx: &mut Context) -> Self { + fn new(window: &mut Window, cx: &mut Context) -> Self { let nostr = NostrRegistry::global(cx); let client = nostr.read(cx).client(); @@ -111,33 +111,16 @@ impl PersonRegistry { }), ); - tasks.push( - // Load all user profiles from the database - cx.spawn(async move |this, cx| { - let result = cx - .background_executor() - .await_on_background(async move { load_persons(&client).await }) - .await; - - match result { - Ok(persons) => { - this.update(cx, |this, cx| { - this.bulk_inserts(persons, cx); - }) - .ok(); - } - Err(e) => { - log::error!("Failed to load all persons from the database: {e}"); - } - }; - }), - ); + // Load all user profiles from the database + cx.defer_in(window, |this, _window, cx| { + this.load(cx); + }); Self { persons: HashMap::new(), seens: Rc::new(RefCell::new(HashSet::new())), sender: mta_tx, - _tasks: tasks, + tasks, } } @@ -163,25 +146,21 @@ impl PersonRegistry { let metadata = Metadata::from_json(&event.content).unwrap_or_default(); let person = Person::new(event.pubkey, metadata); let val = Box::new(person); - // Send tx.send_async(Dispatch::Person(val)).await.ok(); } Kind::ContactList => { let public_keys = event.extract_public_keys(); - // Get metadata for all public keys get_metadata(client, public_keys).await.ok(); } Kind::InboxRelays => { let val = Box::new(event.into_owned()); - // Send tx.send_async(Dispatch::Relays(val)).await.ok(); } Kind::Custom(10044) => { let val = Box::new(event.into_owned()); - // Send tx.send_async(Dispatch::Announcement(val)).await.ok(); } @@ -198,7 +177,7 @@ impl PersonRegistry { loop { match flume::Selector::new() .recv(rx, |result| result.ok()) - .wait_timeout(Duration::from_secs(2)) + .wait_timeout(Duration::from_secs(TIMEOUT)) { Ok(Some(public_key)) => { batch.insert(public_key); @@ -216,6 +195,35 @@ impl PersonRegistry { } } + /// Load all user profiles from the database + fn load(&mut self, cx: &mut Context) { + let nostr = NostrRegistry::global(cx); + let client = nostr.read(cx).client(); + + let task: Task, Error>> = cx.background_spawn(async move { + let filter = Filter::new().kind(Kind::Metadata).limit(200); + let events = client.database().query(filter).await?; + let persons = events + .into_iter() + .map(|event| { + let metadata = Metadata::from_json(event.content).unwrap_or_default(); + Person::new(event.pubkey, metadata) + }) + .collect(); + + Ok(persons) + }); + + self.tasks.push(cx.spawn(async move |this, cx| { + if let Ok(persons) = task.await { + this.update(cx, |this, cx| { + this.bulk_inserts(persons, cx); + }) + .ok(); + } + })); + } + /// Set profile encryption keys announcement fn set_announcement(&mut self, event: &Event, cx: &mut App) { let announcement = Announcement::from(event); @@ -334,19 +342,3 @@ where Ok(()) } - -/// Load all user profiles from the database -async fn load_persons(client: &Client) -> Result, Error> { - let filter = Filter::new().kind(Kind::Metadata).limit(200); - let events = client.database().query(filter).await?; - - let mut persons = vec![]; - - for event in events.into_iter() { - let metadata = Metadata::from_json(event.content).unwrap_or_default(); - let person = Person::new(event.pubkey, metadata); - persons.push(person); - } - - Ok(persons) -} diff --git a/crates/relay_auth/src/lib.rs b/crates/relay_auth/src/lib.rs index a422565..a6249ef 100644 --- a/crates/relay_auth/src/lib.rs +++ b/crates/relay_auth/src/lib.rs @@ -283,7 +283,10 @@ impl RelayAuth { }); window.push_notification( - Notification::success(format!("{} has been authenticated", url)), + Notification::success(format!( + "{} has been authenticated", + url.domain().unwrap_or_default() + )), cx, ); } diff --git a/crates/state/src/constants.rs b/crates/state/src/constants.rs index 9df12f3..eb6bec7 100644 --- a/crates/state/src/constants.rs +++ b/crates/state/src/constants.rs @@ -40,7 +40,8 @@ pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"]; pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://search.nos.today"]; /// Default bootstrap relays -pub const BOOTSTRAP_RELAYS: [&str; 3] = [ +pub const BOOTSTRAP_RELAYS: [&str; 4] = [ + "wss://relay.damus.io", "wss://relay.primal.net", "wss://indexer.coracle.social", "wss://user.kindpag.es", diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index 54bd4be..85c465a 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -185,7 +185,7 @@ impl NostrRegistry { } // Connect to all added relays - client.connect().and_wait(Duration::from_secs(2)).await; + client.connect().await; Ok(()) }); diff --git a/crates/ui/src/notification.rs b/crates/ui/src/notification.rs index 02ddded..0dfcb89 100644 --- a/crates/ui/src/notification.rs +++ b/crates/ui/src/notification.rs @@ -405,12 +405,12 @@ impl Render for Notification { } } } else { + let opacity = delta; let y_offset = match placement { placement if placement.is_top() => px(-45.) + delta * px(45.), placement if placement.is_bottom() => px(45.) - delta * px(45.), _ => px(0.), }; - let opacity = delta; this.top(px(0.) + y_offset) .opacity(opacity) .when(opacity < 0.85, |this| this.shadow_none())