radrootsd

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

commit 2b5e92190530b66d3c8e0bb832ae1e674187610f
parent 636d97ce68652365a6a1f4ab8c0bc6bc429393d9
Author: triesap <triesap@radroots.dev>
Date:   Mon,  5 Jan 2026 22:57:13 +0000

events: remove test event override support

- Drop author_secret_key and created_at from publish APIs
- Remove shared send_event_with_options helper
- Restore direct event publishing via nostr client
- Delete allow_test_events config and related plumbing

Diffstat:
Msrc/api/jsonrpc/methods/events/farm/publish.rs | 18+++++-------------
Msrc/api/jsonrpc/methods/events/helpers.rs | 104++-----------------------------------------------------------------------------
Msrc/api/jsonrpc/methods/events/list_set/publish.rs | 13++++---------
Msrc/api/jsonrpc/methods/events/listing/publish.rs | 18+++++-------------
Msrc/api/jsonrpc/methods/events/plot/publish.rs | 18+++++-------------
Msrc/api/jsonrpc/methods/events/post/publish.rs | 18+++++-------------
Msrc/api/jsonrpc/methods/events/profile/publish.rs | 18+++++-------------
Msrc/config.rs | 3---
Msrc/lib.rs | 7+------
Msrc/radrootsd.rs | 8+-------
10 files changed, 33 insertions(+), 192 deletions(-)

diff --git a/src/api/jsonrpc/methods/events/farm/publish.rs b/src/api/jsonrpc/methods/events/farm/publish.rs @@ -2,23 +2,18 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::farm::RadrootsFarm; use radroots_events::kinds::KIND_FARM; use radroots_events_codec::farm::encode::farm_build_tags; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; #[derive(Debug, Deserialize)] struct PublishFarmParams { farm: RadrootsFarm, #[serde(default)] tags: Option<Vec<Vec<String>>>, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -29,12 +24,7 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res return Err(RpcError::NoRelays); } - let PublishFarmParams { - farm, - tags, - author_secret_key, - created_at, - } = params + let PublishFarmParams { farm, tags } = params .parse() .map_err(|e| RpcError::InvalidParams(e.to_string()))?; @@ -49,7 +39,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(KIND_FARM, content, tag_slices) .map_err(|e| RpcError::Other(format!("failed to build farm event: {e}")))?; - let output = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let output = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish farm: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(output)) })?; diff --git a/src/api/jsonrpc/methods/events/helpers.rs b/src/api/jsonrpc/methods/events/helpers.rs @@ -3,18 +3,12 @@ use std::time::Duration; use crate::api::jsonrpc::params::{parse_pubkeys, timeout_or}; -use crate::api::jsonrpc::{RpcContext, RpcError}; +use crate::api::jsonrpc::RpcError; use radroots_nostr::prelude::{ - radroots_nostr_send_event, RadrootsNostrClient, RadrootsNostrEvent, - RadrootsNostrEventBuilder, - RadrootsNostrEventId, RadrootsNostrFilter, - RadrootsNostrKeys, - RadrootsNostrOutput, RadrootsNostrPublicKey, - RadrootsNostrTimestamp, }; pub(crate) fn parse_author_or_default( @@ -41,68 +35,6 @@ pub(crate) fn require_non_empty(label: &str, value: String) -> Result<String, Rp } } -pub(crate) fn validate_test_event_options( - allow_test_events: bool, - author_secret_key: Option<String>, - created_at: Option<u64>, -) -> Result<(Option<String>, Option<u64>), RpcError> { - let has_test_options = author_secret_key.is_some() || created_at.is_some(); - if has_test_options && !allow_test_events { - return Err(RpcError::InvalidParams( - "test event overrides require config.rpc.allow_test_events = true".to_string(), - )); - } - let author_secret_key = match author_secret_key { - Some(value) => { - let value = value.trim().to_string(); - if value.is_empty() { - return Err(RpcError::InvalidParams( - "author_secret_key cannot be empty".to_string(), - )); - } - Some(value) - } - None => None, - }; - Ok((author_secret_key, created_at)) -} - -pub(crate) async fn send_event_with_options( - ctx: &RpcContext, - builder: RadrootsNostrEventBuilder, - author_secret_key: Option<String>, - created_at: Option<u64>, -) -> Result<RadrootsNostrOutput<RadrootsNostrEventId>, RpcError> { - let (author_secret_key, created_at) = validate_test_event_options( - ctx.state.allow_test_events, - author_secret_key, - created_at, - )?; - let builder = match created_at { - Some(created_at) => { - builder.custom_created_at(RadrootsNostrTimestamp::from_secs(created_at)) - } - None => builder, - }; - - if let Some(author_secret_key) = author_secret_key { - let keys = RadrootsNostrKeys::parse(&author_secret_key) - .map_err(|e| RpcError::InvalidParams(format!("invalid author_secret_key: {e}")))?; - let event = builder - .sign_with_keys(&keys) - .map_err(|e| RpcError::Other(format!("failed to sign event: {e}")))?; - ctx.state - .client - .send_event(&event) - .await - .map_err(|e| RpcError::Other(format!("failed to publish event: {e}"))) - } else { - radroots_nostr_send_event(&ctx.state.client, builder) - .await - .map_err(|e| RpcError::Other(format!("failed to publish event: {e}"))) - } -} - pub(crate) async fn fetch_latest_event( client: &RadrootsNostrClient, filter: RadrootsNostrFilter, @@ -141,8 +73,7 @@ where #[cfg(test)] mod tests { - use super::{select_latest_event, validate_test_event_options}; - use crate::api::jsonrpc::RpcError; + use super::select_latest_event; use radroots_nostr::prelude::RadrootsNostrEvent; use serde_json::json; @@ -171,35 +102,4 @@ mod tests { assert_eq!(latest.created_at.as_secs(), 200); } - #[test] - fn test_event_options_require_flag() { - let err = - validate_test_event_options(false, Some("deadbeef".to_string()), None).unwrap_err(); - match err { - RpcError::InvalidParams(message) => { - assert!(message.contains("allow_test_events")); - } - _ => panic!("unexpected error type"), - } - } - - #[test] - fn test_event_options_reject_empty_secret() { - let err = validate_test_event_options(true, Some(" ".to_string()), None).unwrap_err(); - match err { - RpcError::InvalidParams(message) => { - assert!(message.contains("author_secret_key")); - } - _ => panic!("unexpected error type"), - } - } - - #[test] - fn test_event_options_pass_through() { - let (secret_key, created_at) = - validate_test_event_options(true, Some("deadbeef".to_string()), Some(42)) - .expect("options"); - assert_eq!(secret_key, Some("deadbeef".to_string())); - assert_eq!(created_at, Some(42)); - } } diff --git a/src/api/jsonrpc/methods/events/list_set/publish.rs b/src/api/jsonrpc/methods/events/list_set/publish.rs @@ -4,13 +4,12 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::kinds::{is_nip51_list_set_kind, KIND_LIST_SET_GENERIC}; use radroots_events::list_set::RadrootsListSet; use radroots_events_codec::list_set::encode::list_set_build_tags; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; #[derive(Debug, Deserialize)] struct PublishListSetParams { @@ -19,10 +18,6 @@ struct PublishListSetParams { kind: Option<u32>, #[serde(default)] tags: Option<Vec<Vec<String>>>, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -37,8 +32,6 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res list_set, kind, tags, - author_secret_key, - created_at, } = params .parse() .map_err(|e| RpcError::InvalidParams(e.to_string()))?; @@ -60,7 +53,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(kind, content, tag_slices) .map_err(|e| RpcError::Other(format!("failed to build list_set event: {e}")))?; - let output = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let output = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish list_set: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(output)) })?; diff --git a/src/api/jsonrpc/methods/events/listing/publish.rs b/src/api/jsonrpc/methods/events/listing/publish.rs @@ -2,12 +2,11 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::kinds::KIND_LISTING; use radroots_events::listing::RadrootsListing; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; use radroots_trade::listing::codec::listing_tags_build; #[derive(Debug, Deserialize)] @@ -15,10 +14,6 @@ struct PublishListingParams { listing: RadrootsListing, #[serde(default)] tags: Option<Vec<Vec<String>>>, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -28,12 +23,7 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res return Err(RpcError::NoRelays); } - let PublishListingParams { - listing, - tags, - author_secret_key, - created_at, - } = + let PublishListingParams { listing, tags } = params.parse().map_err(|e| RpcError::InvalidParams(e.to_string()))?; let content = serde_json::to_string(&listing) @@ -46,7 +36,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(KIND_LISTING, content, tag_slices) .map_err(|e| RpcError::Other(format!("failed to build listing event: {e}")))?; - let out = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let out = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish listing: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(out)) })?; diff --git a/src/api/jsonrpc/methods/events/plot/publish.rs b/src/api/jsonrpc/methods/events/plot/publish.rs @@ -2,23 +2,18 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::kinds::KIND_PLOT; use radroots_events::plot::RadrootsPlot; use radroots_events_codec::plot::encode::plot_build_tags; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; #[derive(Debug, Deserialize)] struct PublishPlotParams { plot: RadrootsPlot, #[serde(default)] tags: Option<Vec<Vec<String>>>, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -29,12 +24,7 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res return Err(RpcError::NoRelays); } - let PublishPlotParams { - plot, - tags, - author_secret_key, - created_at, - } = params + let PublishPlotParams { plot, tags } = params .parse() .map_err(|e| RpcError::InvalidParams(e.to_string()))?; @@ -49,7 +39,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(KIND_PLOT, content, tag_slices) .map_err(|e| RpcError::Other(format!("failed to build plot event: {e}")))?; - let output = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let output = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish plot: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(output)) })?; diff --git a/src/api/jsonrpc/methods/events/post/publish.rs b/src/api/jsonrpc/methods/events/post/publish.rs @@ -2,21 +2,16 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::kinds::KIND_POST; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; #[derive(Debug, Deserialize)] struct PublishPostParams { content: String, #[serde(default)] tags: Option<Vec<Vec<String>>>, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -27,12 +22,7 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res return Err(RpcError::NoRelays); } - let PublishPostParams { - content, - tags, - author_secret_key, - created_at, - } = params + let PublishPostParams { content, tags } = params .parse() .map_err(|e| RpcError::InvalidParams(e.to_string()))?; @@ -43,7 +33,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(KIND_POST, content, tags.unwrap_or_default()) .map_err(|e| RpcError::Other(format!("failed to build note: {e}")))?; - let output = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let output = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish note: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(output)) })?; diff --git a/src/api/jsonrpc/methods/events/profile/publish.rs b/src/api/jsonrpc/methods/events/profile/publish.rs @@ -2,22 +2,17 @@ use anyhow::Result; use jsonrpsee::server::RpcModule; use serde::Deserialize; -use crate::api::jsonrpc::methods::events::helpers::send_event_with_options; use crate::api::jsonrpc::nostr::{publish_response, PublishResponse}; use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError}; use radroots_events::profile::{RadrootsProfile, RadrootsProfileType}; use radroots_events_codec::profile::encode::to_wire_parts_with_profile_type; -use radroots_nostr::prelude::radroots_nostr_build_event; +use radroots_nostr::prelude::{radroots_nostr_build_event, radroots_nostr_send_event}; #[derive(Debug, Deserialize)] struct PublishProfileParams { profile: RadrootsProfile, profile_type: RadrootsProfileType, - #[serde(default)] - author_secret_key: Option<String>, - #[serde(default)] - created_at: Option<u64>, } pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> { @@ -28,12 +23,7 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res return Err(RpcError::NoRelays); } - let PublishProfileParams { - profile, - profile_type, - author_secret_key, - created_at, - } = params + let PublishProfileParams { profile, profile_type } = params .parse() .map_err(|e| RpcError::InvalidParams(e.to_string()))?; @@ -42,7 +32,9 @@ pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Res let builder = radroots_nostr_build_event(parts.kind, parts.content, parts.tags) .map_err(|e| RpcError::Other(format!("failed to build profile event: {e}")))?; - let output = send_event_with_options(&ctx, builder, author_secret_key, created_at).await?; + let output = radroots_nostr_send_event(&ctx.state.client, builder) + .await + .map_err(|e| RpcError::Other(format!("failed to publish metadata: {e}")))?; Ok::<PublishResponse, RpcError>(publish_response(output)) })?; diff --git a/src/config.rs b/src/config.rs @@ -40,8 +40,6 @@ pub struct RpcConfig { #[serde(default = "default_message_buffer_capacity")] pub message_buffer_capacity: u32, #[serde(default)] - pub allow_test_events: bool, - #[serde(default)] pub batch_request_limit: Option<u32>, } @@ -54,7 +52,6 @@ impl Default for RpcConfig { max_connections: default_max_connections(), max_subscriptions_per_connection: default_max_subscriptions_per_connection(), message_buffer_capacity: default_message_buffer_capacity(), - allow_test_events: false, batch_request_limit: None, } } diff --git a/src/lib.rs b/src/lib.rs @@ -28,8 +28,7 @@ pub async fn run_radrootsd(settings: &config::Settings, args: &cli_args) -> Resu )?; let keys = identity.keys().clone(); - let allow_test_events = settings.config.rpc.allow_test_events; - let radrootsd = Radrootsd::new(keys, settings.metadata.clone(), allow_test_events); + let radrootsd = Radrootsd::new(keys, settings.metadata.clone()); for relay in settings.config.relays.iter() { radrootsd.client.add_relay(relay).await?; @@ -39,7 +38,6 @@ pub async fn run_radrootsd(settings: &config::Settings, args: &cli_args) -> Resu let client = radrootsd.client.clone(); let md = settings.metadata.clone(); let identity = identity.clone(); - let allow_test_events = allow_test_events; let has_metadata = serde_json::to_value(&md) .ok() .and_then(|v| v.as_object().cloned()) @@ -48,9 +46,6 @@ pub async fn run_radrootsd(settings: &config::Settings, args: &cli_args) -> Resu tokio::spawn(async move { client.connect().await; - if allow_test_events { - return; - } let profile_published = match radroots_nostr_publish_identity_profile_with_type( &client, diff --git a/src/radrootsd.rs b/src/radrootsd.rs @@ -14,15 +14,10 @@ pub struct Radrootsd { pub pubkey: RadrootsNostrPublicKey, pub metadata: RadrootsNostrMetadata, pub info: serde_json::Value, - pub(crate) allow_test_events: bool, } impl Radrootsd { - pub fn new( - keys: RadrootsNostrKeys, - metadata: RadrootsNostrMetadata, - allow_test_events: bool, - ) -> Self { + pub fn new(keys: RadrootsNostrKeys, metadata: RadrootsNostrMetadata) -> Self { let pubkey = keys.public_key(); let client = RadrootsNostrClient::new(keys); let info = serde_json::json!({ @@ -36,7 +31,6 @@ impl Radrootsd { pubkey, metadata, info, - allow_test_events, } } }