Skip to main content

nostro2_relay/
lib.rs

1#![warn(
2    clippy::all,
3    clippy::style,
4    clippy::unseparated_literal_suffix,
5    clippy::pedantic,
6    clippy::nursery
7)]
8pub mod errors;
9mod pool;
10mod relay;
11pub extern crate nostro2;
12pub use pool::NostrPool;
13pub use relay::{NostrRelay, ReconnectConfig};
14
15#[cfg(test)]
16mod tests {
17
18    #[tokio::test]
19    async fn test_relay() {
20        let relay = super::relay::NostrRelay::new("wss://relay.illuminodes.com")
21            .await
22            .expect("Failed to create relay");
23        let filter = nostro2::NostrSubscription {
24            kinds: vec![1].into(),
25            limit: Some(100),
26            ..Default::default()
27        };
28        relay.send(filter).expect("Failed to send filter");
29        let msg = relay.recv().await;
30        assert!(msg.is_some());
31    }
32    #[tokio::test]
33    async fn notes_deduped_correctly() {
34        let pool =
35            super::pool::NostrPool::new(&["wss://relay.illuminodes.com", "wss://freespeech.casa"]);
36        let mut seen = std::collections::HashSet::new();
37
38        let pool_clone = pool.clone();
39        let filter = nostro2::NostrSubscription {
40            kinds: vec![24442].into(),
41            ..Default::default()
42        };
43        pool.send(&filter).expect("Failed to send filter");
44
45        let mut test_note = nostro2::NostrNote {
46            content: "test".to_string(),
47            kind: 24442,
48            ..Default::default()
49        };
50        let test_key = nostro2_signer::NostrKeypair::new_extractable();
51        test_key
52            .sign_note(&mut test_note)
53            .expect("Failed to sign note");
54
55        let mut test_note_2 = nostro2::NostrNote {
56            content: "test-2".to_string(),
57            kind: 24442,
58            ..Default::default()
59        };
60        test_key
61            .sign_note(&mut test_note_2)
62            .expect("Failed to sign note");
63        pool.send(test_note).expect("Failed to send note");
64        pool.send(test_note_2).expect("Failed to send note");
65        while let Some(msg) = pool_clone.recv().await {
66            println!("{msg:#?}");
67            if let nostro2::NostrRelayEvent::NewNote(.., ref note) = msg {
68                assert!(seen.insert(note.id.clone()));
69                if seen.len() == 2 {
70                    break;
71                }
72            }
73        }
74    }
75    #[tokio::test]
76    async fn test_relay_pool_count() {
77        let pool = super::pool::NostrPool::new(&[
78            "wss://relay.illuminodes.com",
79            "wss://relay.arrakis.lat",
80            "wss://frens.nostr1.com",
81            "wss://bitcoiner.social",
82            "wss://bouncer.minibolt.info",
83            "wss://freespeech.casa",
84            "wss://junxingwang.org",
85            "wss://nostr.0x7e.xyz",
86        ]);
87        let filter = nostro2::NostrSubscription {
88            kinds: vec![1].into(),
89            limit: Some(10),
90            ..Default::default()
91        };
92        pool.send(&filter).expect("Failed to send filter");
93        let mut count = 0;
94        let mut eose = 0;
95        while let Some(msg) = pool.recv().await {
96            match msg {
97                nostro2::NostrRelayEvent::NewNote(..) => {
98                    println!("{msg:?}");
99                    count += 1;
100                }
101                nostro2::NostrRelayEvent::EndOfSubscription(_, _) => {
102                    println!("{msg:?}");
103                    eose += 1;
104                }
105                _ => {}
106            }
107            if eose == 2 {
108                break;
109            }
110        }
111        assert!(count > 10);
112    }
113
114    #[tokio::test]
115    async fn test_pool() {
116        let time_spent = std::time::Instant::now();
117        let pool = super::pool::NostrPool::new(&[
118            "wss://relay.illuminodes.com",
119            "wss://relay.arrakis.lat",
120            "wss://frens.nostr1.com",
121            "wss://bitcoiner.social",
122            "wss://bouncer.minibolt.info",
123            "wss://freespeech.casa",
124            "wss://junxingwang.org",
125            "wss://nostr.0x7e.xyz",
126        ]);
127        println!("Connected in: {:?}", time_spent.elapsed());
128        let filter = nostro2::NostrSubscription {
129            kinds: vec![1].into(),
130            limit: Some(20),
131            ..Default::default()
132        };
133        pool.send(&filter).expect("Failed to send filter");
134        println!("Sent filter in: {:?}", time_spent.elapsed());
135        let mut count = 0;
136        while let Some(msg) = pool.recv().await {
137            let nostro2::NostrRelayEvent::EndOfSubscription(_, _) = msg else {
138                continue;
139            };
140            println!("{msg:?}");
141            println!("Received in: {:?}", time_spent.elapsed());
142            count += 1;
143            if count >= 3 {
144                break;
145            }
146        }
147        assert!(count >= 3);
148        println!("Done in: {:?}", time_spent.elapsed());
149    }
150}