radrootsd

JSON-RPC bridge for Radroots event publishing
git clone https://radroots.dev/git/radrootsd.git
Log | Files | Refs | README | LICENSE

commit eb59dfdd3ee94792c9638ae17a61c83b99805d27
parent 6820aa55412b4d6822ebdd72a902a067e9e5865f
Author: triesap <triesap@radroots.dev>
Date:   Tue,  6 Jan 2026 16:43:27 +0000

nip46: accept single relay values in connect URLs

- allow relay param to be string or list
- normalize relay values into a clean Vec<String>
- keep bunker and nostrconnect parsing consistent
- preserve existing perms and metadata parsing

Diffstat:
MCargo.lock | 12++++++++++++
Msrc/transport/jsonrpc/nip46/connection.rs | 26+++++++++++++++++++++++---
2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1871,6 +1871,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "serde_qs", "thiserror 1.0.69", "tokio", "tracing", @@ -2226,6 +2227,17 @@ dependencies = [ ] [[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror 1.0.69", +] + +[[package]] name = "serde_spanned" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/transport/jsonrpc/nip46/connection.rs b/src/transport/jsonrpc/nip46/connection.rs @@ -24,8 +24,15 @@ pub struct Nip46ConnectInfo { } #[derive(Debug, Deserialize)] +#[serde(untagged)] +enum RelayParam { + One(String), + Many(Vec<String>), +} + +#[derive(Debug, Deserialize)] struct Nip46ConnectQuery { - relay: Option<Vec<String>>, + relay: Option<RelayParam>, secret: Option<String>, perms: Option<String>, name: Option<String>, @@ -47,7 +54,7 @@ fn parse_bunker_url(url: &Url) -> Result<Nip46ConnectInfo, RpcError> { let query: Nip46ConnectQuery = serde_qs::from_str(url.query().unwrap_or_default()) .map_err(|e| RpcError::InvalidParams(e.to_string()))?; - let relays = query.relay.unwrap_or_default(); + let relays = relay_list(query.relay); let perms = parse_perms(query.perms); Ok(Nip46ConnectInfo { @@ -73,7 +80,7 @@ fn parse_nostrconnect_url(url: &Url) -> Result<Nip46ConnectInfo, RpcError> { let query: Nip46ConnectQuery = serde_qs::from_str(url.query().unwrap_or_default()) .map_err(|e| RpcError::InvalidParams(e.to_string()))?; - let relays = query.relay.unwrap_or_default(); + let relays = relay_list(query.relay); let perms = parse_perms(query.perms); Ok(Nip46ConnectInfo { @@ -97,3 +104,16 @@ fn parse_perms(perms: Option<String>) -> Vec<String> { .filter(|entry| !entry.is_empty()) .collect() } + +fn relay_list(relay: Option<RelayParam>) -> Vec<String> { + let relays = match relay { + Some(RelayParam::One(value)) => vec![value], + Some(RelayParam::Many(values)) => values, + None => Vec::new(), + }; + relays + .into_iter() + .map(|value| value.trim().to_string()) + .filter(|value| !value.is_empty()) + .collect() +}