From 965df59f1441c97b8525dfca85b770b9bf887912 Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Tue, 9 Apr 2024 15:54:38 +0200 Subject: [PATCH] database: add `NostrDatabaseExt::relay_list` Signed-off-by: Yuki Kishimoto --- crates/nostr-database/src/lib.rs | 27 ++++++++++++++++++++++++++- crates/nostr/src/nips/nip65.rs | 7 ++++--- crates/nostr/src/types/url.rs | 6 ++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/nostr-database/src/lib.rs b/crates/nostr-database/src/lib.rs index 4b462e68e..ed6662456 100644 --- a/crates/nostr-database/src/lib.rs +++ b/crates/nostr-database/src/lib.rs @@ -14,7 +14,10 @@ use std::sync::Arc; pub use async_trait::async_trait; pub use nostr; use nostr::nips::nip01::Coordinate; -use nostr::{Event, EventId, Filter, JsonUtil, Kind, Metadata, PublicKey, Timestamp, Url}; +use nostr::nips::nip65; +use nostr::{ + Event, EventId, Filter, JsonUtil, Kind, Metadata, PublicKey, RelayMetadata, Timestamp, Url, +}; mod error; #[cfg(feature = "flatbuf")] @@ -255,6 +258,28 @@ pub trait NostrDatabaseExt: NostrDatabase { None => Ok(BTreeSet::new()), } } + + /// Get relays list for [PublicKey] + /// + /// + #[tracing::instrument(skip_all, level = "trace")] + async fn relay_list( + &self, + public_key: PublicKey, + ) -> Result)>, Self::Err> { + // Query + let filter: Filter = Filter::default() + .author(public_key) + .kind(Kind::RelayList) + .limit(1); + let events: Vec = self.query(vec![filter], Order::Desc).await?; + + // Extract relay list (NIP65) + match events.first() { + Some(event) => Ok(nip65::extract_relay_list(event)), + None => Ok(Vec::new()), + } + } } #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] diff --git a/crates/nostr/src/nips/nip65.rs b/crates/nostr/src/nips/nip65.rs index 53e3daa98..773b884ed 100644 --- a/crates/nostr/src/nips/nip65.rs +++ b/crates/nostr/src/nips/nip65.rs @@ -8,15 +8,16 @@ use alloc::vec::Vec; -use crate::{Event, RelayMetadata, Tag, UncheckedUrl}; +use crate::{Event, RelayMetadata, Tag, Url}; /// Extracts the relay info (url, optional read/write flag) from the event -pub fn extract_relay_list(event: &Event) -> Vec<(UncheckedUrl, Option)> { +#[inline] +pub fn extract_relay_list(event: &Event) -> Vec<(Url, Option)> { event .iter_tags() .filter_map(|tag| { if let Tag::RelayMetadata(url, metadata) = tag { - Some((url.clone(), metadata.clone())) + Some((Url::parse(url.as_str()).ok()?, metadata.clone())) } else { None } diff --git a/crates/nostr/src/types/url.rs b/crates/nostr/src/types/url.rs index 836eec484..b3d7fcca4 100644 --- a/crates/nostr/src/types/url.rs +++ b/crates/nostr/src/types/url.rs @@ -70,6 +70,12 @@ impl UncheckedUrl { pub fn empty() -> Self { Self(String::new()) } + + /// Get unchecked url as `&str` + #[inline] + pub fn as_str(&self) -> &str { + &self.0 + } } impl From for UncheckedUrl