commit d67dffa14a6ffdc6367d9b2eca0b26c474de35f4
parent ef63e2dfca1e5f1f48ccd0b6889f93b4281d0901
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Fri, 22 Aug 2025 14:28:01 -0700
Add nostr relays rpc events module.
Diffstat:
3 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/crates/radrootsd/src/rpc/error.rs b/crates/radrootsd/src/rpc/error.rs
@@ -3,6 +3,12 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum RpcError {
+ #[error("failed to add relay {0}: {1}")]
+ AddRelay(String, String),
+ #[error("no relays configured; call relays.add first")]
+ NoRelays,
+ #[error("invalid params: {0}")]
+ InvalidParams(String),
#[error("{0}")]
Other(String),
}
diff --git a/crates/radrootsd/src/rpc/mod.rs b/crates/radrootsd/src/rpc/mod.rs
@@ -6,6 +6,7 @@ use jsonrpsee::server::{RpcModule, Server, ServerHandle};
use crate::radrootsd::Radrootsd;
mod error;
+mod relays;
mod system;
pub use error::RpcError;
@@ -15,6 +16,7 @@ pub async fn start_rpc(radrootsd: Radrootsd, addr: SocketAddr) -> Result<ServerH
let mut root = RpcModule::new(radrootsd.clone());
root.merge(system::module(radrootsd.clone())?)?;
+ root.merge(relays::module(radrootsd.clone())?)?;
let handle = server.start(root);
Ok(handle)
diff --git a/crates/radrootsd/src/rpc/relays.rs b/crates/radrootsd/src/rpc/relays.rs
@@ -0,0 +1,52 @@
+use anyhow::Result;
+use jsonrpsee::RpcModule;
+use serde::Deserialize;
+// note: bring JsonValue into scope to turbofish Ok later
+use serde_json::{Value as JsonValue, json};
+
+use crate::radrootsd::Radrootsd;
+use crate::rpc::RpcError;
+
+#[derive(Debug, Deserialize)]
+struct AddParams {
+ url: String,
+}
+
+pub fn module(radrootsd: Radrootsd) -> Result<RpcModule<Radrootsd>> {
+ let mut m = RpcModule::new(radrootsd);
+
+ // relays.add
+ m.register_async_method("relays.add", |params, ctx, _| async move {
+ let AddParams { url } = params
+ .parse()
+ .map_err(|e| RpcError::InvalidParams(e.to_string()))?;
+ ctx.client
+ .add_relay(&url)
+ .await
+ .map_err(|e| RpcError::AddRelay(url.clone(), e.to_string()))?;
+
+ Ok::<JsonValue, RpcError>(json!({ "added": url }))
+ })?;
+
+ // relays.list
+ m.register_async_method("relays.list", |_p, ctx, _| async move {
+ let relays = ctx.client.relays().await;
+ Ok::<JsonValue, RpcError>(json!(
+ relays.keys().map(|u| u.to_string()).collect::<Vec<_>>()
+ ))
+ })?;
+
+ // relays.connect
+ m.register_async_method("relays.connect", |_p, ctx, _| async move {
+ let relays = ctx.client.relays().await;
+ if relays.is_empty() {
+ return Err(RpcError::NoRelays);
+ }
+ let client = ctx.client.clone();
+ tokio::spawn(async move { client.connect().await });
+
+ Ok::<JsonValue, RpcError>(json!({ "connecting": relays.len() }))
+ })?;
+
+ Ok(m)
+}