1use std::collections::{BTreeSet, HashMap, HashSet};
8
9use nostr::prelude::*;
10
11use crate::{DatabaseError, Events, NostrDatabase, Profile, RelaysMap};
12
13pub trait NostrDatabaseExt: NostrDatabase {
15 fn metadata(
17 &self,
18 public_key: PublicKey,
19 ) -> BoxedFuture<Result<Option<Metadata>, DatabaseError>> {
20 Box::pin(async move {
21 let filter = Filter::new()
22 .author(public_key)
23 .kind(Kind::Metadata)
24 .limit(1);
25 let events: Events = self.query(filter).await?;
26 match events.first_owned() {
27 Some(event) => Ok(Some(
28 Metadata::from_json(event.content).map_err(DatabaseError::backend)?,
29 )),
30 None => Ok(None),
31 }
32 })
33 }
34
35 fn contacts_public_keys(
37 &self,
38 public_key: PublicKey,
39 ) -> BoxedFuture<Result<HashSet<PublicKey>, DatabaseError>> {
40 Box::pin(async move {
41 let filter = Filter::new()
42 .author(public_key)
43 .kind(Kind::ContactList)
44 .limit(1);
45 let events: Events = self.query(filter).await?;
46 match events.first_owned() {
47 Some(event) => Ok(event.tags.public_keys().copied().collect()),
48 None => Ok(HashSet::new()),
49 }
50 })
51 }
52
53 fn contacts(
55 &self,
56 public_key: PublicKey,
57 ) -> BoxedFuture<Result<BTreeSet<Profile>, DatabaseError>> {
58 Box::pin(async move {
59 let filter = Filter::new()
60 .author(public_key)
61 .kind(Kind::ContactList)
62 .limit(1);
63 let events: Events = self.query(filter).await?;
64 match events.first_owned() {
65 Some(event) => {
66 let filter = Filter::new()
68 .authors(event.tags.public_keys().copied())
69 .kind(Kind::Metadata);
70 let mut contacts: HashSet<Profile> = self
71 .query(filter)
72 .await?
73 .into_iter()
74 .map(|e| {
75 let metadata: Metadata =
76 Metadata::from_json(&e.content).unwrap_or_default();
77 Profile::new(e.pubkey, metadata)
78 })
79 .collect();
80
81 contacts.extend(event.tags.public_keys().copied().map(Profile::from));
83
84 Ok(contacts.into_iter().collect())
85 }
86 None => Ok(BTreeSet::new()),
87 }
88 })
89 }
90
91 fn relay_list(&self, public_key: PublicKey) -> BoxedFuture<Result<RelaysMap, DatabaseError>> {
95 Box::pin(async move {
96 let filter: Filter = Filter::default()
98 .author(public_key)
99 .kind(Kind::RelayList)
100 .limit(1);
101 let events: Events = self.query(filter).await?;
102
103 match events.first_owned() {
105 Some(event) => Ok(nip65::extract_owned_relay_list(event).collect()),
106 None => Ok(HashMap::new()),
107 }
108 })
109 }
110
111 fn relay_lists<'a, I>(
115 &'a self,
116 public_keys: I,
117 ) -> BoxedFuture<'a, Result<HashMap<PublicKey, RelaysMap>, DatabaseError>>
118 where
119 I: IntoIterator<Item = PublicKey> + Send + 'a,
120 {
121 Box::pin(async move {
122 let filter: Filter = Filter::default().authors(public_keys).kind(Kind::RelayList);
124 let events: Events = self.query(filter).await?;
125
126 let mut map = HashMap::with_capacity(events.len());
127
128 for event in events.into_iter() {
129 map.insert(
130 event.pubkey,
131 nip65::extract_owned_relay_list(event).collect(),
132 );
133 }
134
135 Ok(map)
136 })
137 }
138}
139
140impl<T: NostrDatabase + ?Sized> NostrDatabaseExt for T {}