From 490734803340f62b184fc4724dab410d7c4dc32b Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Wed, 10 Apr 2024 10:11:54 +0200 Subject: [PATCH] pool: add some gossip methods to `InternalRelayPool` Signed-off-by: Yuki Kishimoto --- crates/nostr-relay-pool/src/pool/error.rs | 4 + crates/nostr-relay-pool/src/pool/internal.rs | 84 +++++++++++++++++++- crates/nostr-relay-pool/src/pool/options.rs | 13 +++ crates/nostr-sdk/src/client/options.rs | 10 +++ 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/crates/nostr-relay-pool/src/pool/error.rs b/crates/nostr-relay-pool/src/pool/error.rs index 19342da99..9e0c3d00f 100644 --- a/crates/nostr-relay-pool/src/pool/error.rs +++ b/crates/nostr-relay-pool/src/pool/error.rs @@ -5,6 +5,7 @@ use async_utility::thread; use nostr::message::MessageHandleError; use nostr::types::url; +use nostr::PublicKey; use nostr_database::DatabaseError; use thiserror::Error; @@ -46,6 +47,9 @@ pub enum Error { /// Relay not found #[error("relay not found")] RelayNotFound, + /// Relay not found + #[error("relay metadata not found for `{0}` public key")] + RelayMetadataNotFound(PublicKey), /// Notification Handler error #[error("notification handler error: {0}")] Handler(String), diff --git a/crates/nostr-relay-pool/src/pool/internal.rs b/crates/nostr-relay-pool/src/pool/internal.rs index 55b7beac2..1e2b81d8a 100644 --- a/crates/nostr-relay-pool/src/pool/internal.rs +++ b/crates/nostr-relay-pool/src/pool/internal.rs @@ -13,7 +13,11 @@ use std::time::Duration; use async_utility::{thread, time}; use atomic_destructor::AtomicDestroyer; -use nostr::{ClientMessage, Event, EventId, Filter, SubscriptionId, Timestamp, TryIntoUrl, Url}; +use nostr::nips::nip65; +use nostr::{ + ClientMessage, Event, EventId, Filter, Kind, PublicKey, RelayMetadata, SubscriptionId, + Timestamp, TryIntoUrl, Url, +}; use nostr_database::{DynNostrDatabase, IntoNostrDatabase, Order}; use tokio::sync::{broadcast, Mutex, RwLock}; @@ -29,7 +33,7 @@ pub struct InternalRelayPool { relays: Arc>>, notification_sender: broadcast::Sender, subscriptions: Arc>>>, - // opts: RelayPoolOptions, + opts: RelayPoolOptions, } impl AtomicDestroyer for InternalRelayPool { @@ -59,7 +63,7 @@ impl InternalRelayPool { relays: Arc::new(RwLock::new(HashMap::new())), notification_sender, subscriptions: Arc::new(RwLock::new(HashMap::new())), - //opts, + opts, } } @@ -620,3 +624,77 @@ impl InternalRelayPool { Ok(()) } } + +// Gossip methods +impl InternalRelayPool { + pub async fn add_discovery_relay(&self, url: U) -> Result + where + U: TryIntoUrl, + Error: From<::Err>, + { + // Compose flags + let mut flags: RelayServiceFlags = RelayServiceFlags::NONE; + flags.add(RelayServiceFlags::DISCOVERY); + + // Add relay + let opts: RelayOptions = RelayOptions::default().flags(flags); + self.add_relay(url, opts).await + } + + pub async fn add_inbox_relay(&self, url: U) -> Result + where + U: TryIntoUrl, + Error: From<::Err>, + { + // Compose flags + let mut flags: RelayServiceFlags = RelayServiceFlags::NONE; + flags.add(RelayServiceFlags::READ); + flags.add(RelayServiceFlags::INBOX); + + // Add relay + let opts: RelayOptions = RelayOptions::default().flags(flags); + self.add_relay(url, opts).await + } + + pub async fn add_outbox_relay(&self, url: U) -> Result + where + U: TryIntoUrl, + Error: From<::Err>, + { + // Compose flags + let mut flags: RelayServiceFlags = RelayServiceFlags::NONE; + flags.add(RelayServiceFlags::WRITE); + flags.add(RelayServiceFlags::OUTBOX); + + // Add relay + let opts: RelayOptions = RelayOptions::default().flags(flags); + self.add_relay(url, opts).await + } + + pub async fn get_relays_for_public_key( + &self, + public_key: PublicKey, + timeout: Duration, + ) -> Result)>, Error> { + // Get discovery relays + let relays = self + .relays_with_flag(RelayServiceFlags::DISCOVERY) + .await + .into_keys(); + + // Get events + let filter: Filter = Filter::default() + .author(public_key) + .kind(Kind::RelayList) + .limit(1); + let events: Vec = self + .get_events_from(relays, vec![filter], timeout, FilterOptions::ExitOnEOSE) + .await?; + + // Extract relay list (NIP65) + let event: &Event = events + .first() + .ok_or(Error::RelayMetadataNotFound(public_key))?; + Ok(nip65::extract_relay_list(event)) + } +} diff --git a/crates/nostr-relay-pool/src/pool/options.rs b/crates/nostr-relay-pool/src/pool/options.rs index 7b73b8437..252524d94 100644 --- a/crates/nostr-relay-pool/src/pool/options.rs +++ b/crates/nostr-relay-pool/src/pool/options.rs @@ -8,25 +8,38 @@ #[derive(Debug, Clone, Copy)] pub struct RelayPoolOptions { pub(super) notification_channel_size: usize, + pub(super) gossip: bool, + pub(super) restore_relays_from_database: bool, } impl Default for RelayPoolOptions { fn default() -> Self { Self { notification_channel_size: 4096, + gossip: false, + restore_relays_from_database: false, } } } impl RelayPoolOptions { /// New default options + #[inline] pub fn new() -> Self { Self::default() } /// Notification channel size (default: 4096) + #[inline] pub fn notification_channel_size(mut self, size: usize) -> Self { self.notification_channel_size = size; self } + + /// Enable gossip model (default: false) + #[inline] + pub fn gossip(mut self, enable: bool) -> Self { + self.gossip = enable; + self + } } diff --git a/crates/nostr-sdk/src/client/options.rs b/crates/nostr-sdk/src/client/options.rs index 26c9d1efe..538ba9fa6 100644 --- a/crates/nostr-sdk/src/client/options.rs +++ b/crates/nostr-sdk/src/client/options.rs @@ -38,6 +38,8 @@ pub struct Options { pub connection_timeout: Option, /// Send timeout (default: 20 secs) pub send_timeout: Option, + /// Enable gossip model (default: false) + pub gossip: bool, /// Proxy #[cfg(not(target_arch = "wasm32"))] pub proxy: Option, @@ -59,6 +61,7 @@ impl Default for Options { timeout: Duration::from_secs(60), connection_timeout: None, send_timeout: Some(DEFAULT_SEND_TIMEOUT), + gossip: false, #[cfg(not(target_arch = "wasm32"))] proxy: None, relay_limits: RelayLimits::default(), @@ -188,6 +191,13 @@ impl Options { } } + /// Enable gossip model (default: false) + #[inline] + pub fn gossip(mut self, enable: bool) -> Self { + self.gossip = enable; + self + } + /// Proxy #[cfg(not(target_arch = "wasm32"))] pub fn proxy(mut self, proxy: Option) -> Self {