nostro2_web_relay/
lib.rs

1#![warn(
2    clippy::all,
3    clippy::missing_errors_doc,
4    clippy::style,
5    clippy::unseparated_literal_suffix,
6    clippy::pedantic,
7    clippy::nursery
8)]
9
10pub mod pool;
11pub mod relay;
12pub extern crate nostro2;
13
14#[cfg(test)]
15mod tests {
16    use nostro2::NostrSigner;
17
18    wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
19
20    #[wasm_bindgen_test::wasm_bindgen_test]
21    async fn _test_wasm_connection() {
22        let relay = crate::relay::NostrRelay::new("wss://relay.illuminodes.com");
23        relay.is_open().await;
24        assert_eq!(
25            relay.relay_state().await,
26            nostro2::relay_events::RelayStatus::OPEN
27        );
28        let filter = nostro2::subscriptions::NostrSubscription {
29            kinds: vec![1].into(),
30            limit: Some(10),
31            ..Default::default()
32        };
33        relay.send(filter).await.expect("Failed to send filter");
34
35        let mut received = false;
36        while let Some(msg) = relay.read().await {
37            let nostro2::relay_events::NostrRelayEvent::EndOfSubscription(_, _) = msg else {
38                received = true;
39                continue;
40            };
41
42            break;
43        }
44        assert!(received);
45        relay.disconnect().await;
46        assert_eq!(
47            relay.relay_state().await,
48            nostro2::relay_events::RelayStatus::CLOSED
49        );
50    }
51    #[wasm_bindgen_test::wasm_bindgen_test]
52    async fn _test_wasm_count() {
53        let relay = crate::relay::NostrRelay::new("wss://relay.arrakis.lat");
54        relay.is_open().await;
55        assert_eq!(
56            relay.relay_state().await,
57            nostro2::relay_events::RelayStatus::OPEN
58        );
59        let filter = nostro2::subscriptions::NostrSubscription {
60            kinds: vec![1].into(),
61            limit: Some(10),
62            ..Default::default()
63        };
64        relay.send(filter).await.expect("Failed to send filter");
65
66        let mut received = 0;
67        while let Some(msg) = relay.read().await {
68            match msg {
69                nostro2::relay_events::NostrRelayEvent::NewNote(..) => {
70                    received += 1;
71                }
72                nostro2::relay_events::NostrRelayEvent::EndOfSubscription(_, _) => {
73                    break;
74                }
75                _ => (),
76            }
77        }
78        assert!(received == 10);
79        relay.disconnect().await;
80        assert_eq!(
81            relay.relay_state().await,
82            nostro2::relay_events::RelayStatus::CLOSED
83        );
84    }
85    #[wasm_bindgen_test::wasm_bindgen_test]
86    async fn _test_closed_relay() {
87        let relay = crate::relay::NostrRelay::new("wss://bouncer.minibolt.info");
88        relay.is_open().await;
89        assert_eq!(
90            relay.relay_state().await,
91            nostro2::relay_events::RelayStatus::CLOSED
92        );
93    }
94    // #[wasm_bindgen_test::wasm_bindgen_test]
95    async fn _test_note_dedup() {
96        let pool: crate::pool::RelayPool = [
97            "wss://relay.illuminodes.com",
98            "wss://relay.arrakis.lat",
99            "wss://frens.nostr1.com",
100            "wss://bitcoiner.social",
101            "wss://bouncer.minibolt.info",
102            "wss://freespeech.casa",
103            "wss://junxingwang.org",
104            "wss://nostr.0x7e.xyz",
105        ]
106        .as_slice()
107        .into();
108        wasm_bindgen_test::console_log!("Created pool");
109        wasm_bindgen_test::console_log!("Connected to pool");
110        let new_keys = nostro2_signer::keypair::NostrKeypair::generate(false);
111        let filter = nostro2::subscriptions::NostrSubscription {
112            kinds: vec![20004].into(),
113            authors: vec![new_keys.public_key()].into(),
114            ..Default::default()
115        };
116        let sub = pool.send(filter).await;
117        assert!(matches!(
118            sub,
119            nostro2::relay_events::NostrClientEvent::Subscribe(..)
120        ));
121        wasm_bindgen_test::console_log!("Sent filter");
122        let mut new_note = nostro2::note::NostrNote {
123            content: "Test".to_string(),
124            kind: 20004,
125            pubkey: new_keys.public_key(),
126            ..Default::default()
127        };
128        new_keys
129            .sign_nostr_note(&mut new_note)
130            .expect("Failed to sign note");
131        pool.send(new_note).await;
132        wasm_bindgen_test::console_log!("Sent note");
133
134        loop {
135            let Some(msg) = pool.read().await else {
136                wasm_bindgen_test::console_log!("Failed to read from pool");
137                continue;
138            };
139            if let nostro2::relay_events::NostrRelayEvent::NewNote(.., note) = msg {
140                assert_eq!(note.kind, 20004);
141                assert_eq!(note.pubkey, new_keys.public_key());
142                wasm_bindgen_test::console_log!("Received note {:?}", note);
143            }
144        }
145    }
146    #[wasm_bindgen_test::wasm_bindgen_test]
147    async fn _test_relay_pool() {
148        let pool: crate::pool::RelayPool = [
149            "wss://relay.illuminodes.com",
150            "wss://relay.arrakis.lat",
151            "wss://frens.nostr1.com",
152            "wss://bitcoiner.social",
153            "wss://bouncer.minibolt.info",
154            "wss://freespeech.casa",
155            "wss://junxingwang.org",
156            "wss://nostr.0x7e.xyz",
157        ]
158        .as_slice()
159        .into();
160        wasm_bindgen_test::console_log!("Created pool");
161        wasm_bindgen_test::console_log!("Connected to pool");
162        let filter = nostro2::subscriptions::NostrSubscription {
163            kinds: vec![1].into(),
164            limit: Some(10),
165            ..Default::default()
166        };
167        pool.send(filter).await;
168        wasm_bindgen_test::console_log!("Sent filter");
169        let mut count = 0;
170        loop {
171            let Some(msg) = pool.read().await else {
172                wasm_bindgen_test::console_log!("Failed to read from pool");
173                continue;
174            };
175            let nostro2::relay_events::NostrRelayEvent::EndOfSubscription(_, _) = msg else {
176                count += 1;
177                if count > 5 {
178                    break;
179                } else {
180                    continue;
181                }
182            };
183            wasm_bindgen_test::console_log!("Received {:?}", msg);
184        }
185        assert!(count > 5);
186    }
187    #[wasm_bindgen_test::wasm_bindgen_test]
188    async fn _test_message_count() {
189        let pool: crate::pool::RelayPool =
190            ["wss://relay.illuminodes.com", "wss://bitcoiner.social"]
191                .as_slice()
192                .into();
193        wasm_bindgen_test::console_log!("Created pool");
194        wasm_bindgen_test::console_log!("Connected to pool");
195        let filter = nostro2::subscriptions::NostrSubscription {
196            kinds: vec![1].into(),
197            limit: Some(10),
198            ..Default::default()
199        };
200        pool.send(filter).await;
201        wasm_bindgen_test::console_log!("Sent filter");
202        let mut count = 0;
203        let mut eose = 0;
204        loop {
205            let Some(msg) = pool.read().await else {
206                wasm_bindgen_test::console_log!("Failed to read from pool");
207                continue;
208            };
209            match msg {
210                nostro2::relay_events::NostrRelayEvent::NewNote(..) => {
211                    count += 1;
212                }
213                nostro2::relay_events::NostrRelayEvent::EndOfSubscription(_, _) => {
214                    wasm_bindgen_test::console_log!("Received {:?}", msg);
215                    eose += 1;
216                }
217                _ => (),
218            }
219            if eose == 2 {
220                break;
221            }
222        }
223        wasm_bindgen_test::console_log!("Received {} messages", count);
224        assert!(count == 20);
225    }
226    //#[wasm_bindgen_test::wasm_bindgen_test]
227    //async fn _stress_test_relay_pool() {
228    //    let pool: crate::pool::RelayPool = [
229    //        "wss://relay.illuminodes.com",
230    //        "wss://relay.arrakis.lat",
231    //        "wss://frens.nostr1.com",
232    //        "wss://bitcoiner.social",
233    //        "wss://bouncer.minibolt.info",
234    //        "wss://freespeech.casa",
235    //        "wss://junxingwang.org",
236    //        "wss://nostr.0x7e.xyz",
237    //    ]
238    //    .as_slice()
239    //    .into();
240
241    //    let filter = nostro2::subscriptions::NostrSubscription {
242    //        kinds: vec![1].into(),
243    //        ..Default::default()
244    //    };
245    //    pool.send(filter).await;
246    //    let mut count = 0;
247    //    loop {
248    //        let Some(msg) = pool.read().await else {
249    //            wasm_bindgen_test::console_log!("Failed to read from pool");
250    //            continue;
251    //        };
252    //        if let nostro2::relay_events::NostrRelayEvent::NewNote(..) = msg {
253    //            wasm_bindgen_test::console_log!("Received {}", count);
254    //            count += 1;
255    //        };
256    //        if count > 10000 {
257    //            break;
258    //        }
259    //    }
260    //    assert!(count > 10000);
261    //}
262}