Skip to content

Commit e902ad5

Browse files
committed
nwc: allow usage of multiple relays
Use `RelayPool` instead of `Relay`. Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 8c374f1 commit e902ad5

File tree

5 files changed

+38
-31
lines changed

5 files changed

+38
-31
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
* ndb: avoid event clone when calling `NostrEventsDatabase::save_event` ([Yuki Kishimoto])
6565
* sdk: auto-update the gossip data when sending an event ([Yuki Kishimoto])
6666
* sdk: avoid full clone of relays when only urls are needed ([Yuki Kishimoto])
67+
* nwc: allow usage of multiple relays ([Yuki Kishimoto])
6768
* ffi: improve `Events::merge` and `Events::to_vec` performance ([Yuki Kishimoto])
6869
* ci: release wheels also for python `3.13` ([Yuki Kishimoto])
6970

bindings/nostr-sdk-ffi/src/nwc/mod.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) 2023-2025 Rust Nostr Developers
33
// Distributed under the MIT software license
44

5+
use std::collections::HashMap;
56
use std::ops::Deref;
67

78
use uniffi::Object;
@@ -49,9 +50,14 @@ impl NWC {
4950
}
5051
}
5152

52-
/// Get relay status
53-
pub fn status(&self) -> RelayStatus {
54-
self.inner.status().into()
53+
/// Get relays status
54+
pub async fn status(&self) -> HashMap<String, RelayStatus> {
55+
self.inner
56+
.status()
57+
.await
58+
.into_iter()
59+
.map(|(k, v)| (k.to_string(), v.into()))
60+
.collect()
5561
}
5662

5763
/// Pay invoice

bindings/nostr-sdk-js/src/nwc/mod.rs

-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::protocol::nips::nip47::{
1717
JsMakeInvoiceRequest, JsMakeInvoiceResponse, JsNostrWalletConnectURI, JsPayInvoiceRequest,
1818
JsPayInvoiceResponse, JsPayKeysendRequest, JsPayKeysendResponse,
1919
};
20-
use crate::relay::JsRelayStatus;
2120

2221
#[wasm_bindgen]
2322
extern "C" {
@@ -58,11 +57,6 @@ impl JsNwc {
5857
}
5958
}
6059

61-
/// Get relay status
62-
pub fn status(&self) -> JsRelayStatus {
63-
self.inner.status().into()
64-
}
65-
6660
/// Pay invoice
6761
#[wasm_bindgen(js_name = payInvoice)]
6862
pub async fn pay_invoice(&self, params: &JsPayInvoiceRequest) -> Result<JsPayInvoiceResponse> {

crates/nwc/src/error.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
use std::fmt;
88

99
use nostr::nips::nip47;
10-
use nostr_relay_pool::relay;
10+
use nostr_relay_pool::pool;
1111

1212
/// NWC error
1313
#[derive(Debug)]
1414
pub enum Error {
1515
/// NIP47 error
1616
NIP47(nip47::Error),
17-
/// Relay
18-
Relay(relay::Error),
17+
/// Relay Pool
18+
Pool(pool::Error),
1919
/// Premature exit
2020
PrematureExit,
2121
/// Request timeout
@@ -28,7 +28,7 @@ impl fmt::Display for Error {
2828
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2929
match self {
3030
Self::NIP47(e) => write!(f, "{e}"),
31-
Self::Relay(e) => write!(f, "{e}"),
31+
Self::Pool(e) => write!(f, "{e}"),
3232
Self::PrematureExit => write!(f, "premature exit"),
3333
Self::Timeout => write!(f, "timeout"),
3434
}
@@ -41,8 +41,8 @@ impl From<nip47::Error> for Error {
4141
}
4242
}
4343

44-
impl From<relay::Error> for Error {
45-
fn from(e: relay::Error) -> Self {
46-
Self::Relay(e)
44+
impl From<pool::Error> for Error {
45+
fn from(e: pool::Error) -> Self {
46+
Self::Pool(e)
4747
}
4848
}

crates/nwc/src/lib.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![allow(unknown_lints)] // TODO: remove when MSRV >= 1.72.0, required for `clippy::arc_with_non_send_sync`
1212
#![allow(clippy::arc_with_non_send_sync)]
1313

14+
use std::collections::HashMap;
1415
use std::sync::atomic::{AtomicBool, Ordering};
1516
use std::sync::Arc;
1617

@@ -35,7 +36,7 @@ const ID: &str = "nwc";
3536
#[derive(Debug, Clone)]
3637
pub struct NWC {
3738
uri: NostrWalletConnectURI,
38-
relay: Relay,
39+
pool: RelayPool,
3940
opts: NostrWalletConnectOptions,
4041
bootstrapped: Arc<AtomicBool>,
4142
}
@@ -50,17 +51,17 @@ impl NWC {
5051
/// New `NWC` client with custom [`NostrWalletConnectOptions`].
5152
pub fn with_opts(uri: NostrWalletConnectURI, opts: NostrWalletConnectOptions) -> Self {
5253
Self {
53-
relay: Relay::with_opts(uri.relays.first().cloned().unwrap(), opts.relay.clone()),
5454
uri,
55+
pool: RelayPool::default(),
5556
opts,
5657
bootstrapped: Arc::new(AtomicBool::new(false)),
5758
}
5859
}
5960

60-
/// Get relay status
61-
#[inline]
62-
pub fn status(&self) -> RelayStatus {
63-
self.relay.status()
61+
/// Get relays status
62+
pub async fn status(&self) -> HashMap<RelayUrl, RelayStatus> {
63+
let relays = self.pool.relays().await;
64+
relays.into_iter().map(|(u, r)| (u, r.status())).collect()
6465
}
6566

6667
/// Connect and subscribe
@@ -70,16 +71,21 @@ impl NWC {
7071
return Ok(());
7172
}
7273

73-
// Connect
74-
self.relay.connect();
74+
// Add relays
75+
for url in self.uri.relays.iter() {
76+
self.pool.add_relay(url, self.opts.relay.clone()).await?;
77+
}
78+
79+
// Connect to relays
80+
self.pool.connect().await;
7581

7682
let filter = Filter::new()
7783
.author(self.uri.public_key)
7884
.kind(Kind::WalletConnectResponse)
7985
.limit(0); // Limit to 0 means give me 0 events until EOSE
8086

8187
// Subscribe
82-
self.relay
88+
self.pool
8389
.subscribe_with_id(SubscriptionId::new(ID), filter, SubscribeOptions::default())
8490
.await?;
8591

@@ -96,16 +102,16 @@ impl NWC {
96102
// Convert request to event
97103
let event: Event = req.to_event(&self.uri)?;
98104

99-
let mut notifications = self.relay.notifications();
105+
let mut notifications = self.pool.notifications();
100106

101107
// Send request
102-
let id: EventId = self.relay.send_event(&event).await?;
108+
let output: Output<EventId> = self.pool.send_event(&event).await?;
103109

104110
time::timeout(Some(self.opts.timeout), async {
105111
while let Ok(notification) = notifications.recv().await {
106-
if let RelayNotification::Event { event, .. } = notification {
112+
if let RelayPoolNotification::Event { event, .. } = notification {
107113
if event.kind == Kind::WalletConnectResponse
108-
&& event.tags.event_ids().next().copied() == Some(id)
114+
&& event.tags.event_ids().next() == Some(output.id())
109115
{
110116
return Ok(Response::from_event(&self.uri, &event)?);
111117
}
@@ -185,7 +191,7 @@ impl NWC {
185191

186192
/// Completely shutdown [NWC] client
187193
#[inline]
188-
pub fn shutdown(self) {
189-
self.relay.disconnect()
194+
pub async fn shutdown(self) {
195+
self.pool.disconnect().await
190196
}
191197
}

0 commit comments

Comments
 (0)