rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

commit c639934736779f309f1f18bc4ac63705ed5e545e
parent 937182ebfecfec3db08587e877d7e54477bad23d
Author: triesap <tyson@radroots.org>
Date:   Sun, 15 Feb 2026 18:16:14 +0000

app: use shared runtime config and nostr presence primitives

- replace local cli flag definitions with shared runtime service cli args
- flatten shared nostr service config into rhi configuration
- switch startup presence publishing to shared nostr bootstrap helper
- route nip89 identifier and extra tags through shared service config fields

Diffstat:
Msrc/cli.rs | 30++++--------------------------
Msrc/config.rs | 10+++-------
Msrc/lib.rs | 68++++++++++++++++++++------------------------------------------------
Msrc/main.rs | 4++--
4 files changed, 29 insertions(+), 83 deletions(-)

diff --git a/src/cli.rs b/src/cli.rs @@ -1,6 +1,5 @@ -use std::path::PathBuf; - -use clap::{Parser, ValueHint, command}; +use clap::Parser; +use radroots_runtime::RadrootsServiceCliArgs; #[derive(Parser, Debug, Clone)] #[command( @@ -9,27 +8,6 @@ use clap::{Parser, ValueHint, command}; version = env!("CARGO_PKG_VERSION") )] pub struct Args { - #[arg( - long, - value_name = "PATH", - value_hint = ValueHint::FilePath, - default_value = "config.toml", - help = "Path to the daemon configuration file (defaults to config.toml)" - )] - pub config: PathBuf, - - #[arg( - long, - value_name = "PATH", - value_hint = ValueHint::FilePath, - help = "Path to the daemon identity file (json, txt, or raw 32-byte key; defaults to identity.json)", - )] - pub identity: Option<PathBuf>, - - #[arg( - long, - action = clap::ArgAction::SetTrue, - help = "Allow generating a new identity file if missing; if not set and identity file is absent, the daemon will fail" - )] - pub allow_generate_identity: bool, + #[command(flatten)] + pub service: RadrootsServiceCliArgs, } diff --git a/src/config.rs b/src/config.rs @@ -1,15 +1,11 @@ use radroots_nostr::prelude::RadrootsNostrMetadata; -use radroots_runtime::BackoffConfig; +use radroots_runtime::{BackoffConfig, RadrootsNostrServiceConfig}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Configuration { - pub logs_dir: String, - pub relays: Vec<String>, - #[serde(default)] - pub nip89_identifier: Option<String>, - #[serde(default)] - pub nip89_extra_tags: Vec<Vec<String>>, + #[serde(flatten)] + pub service: RadrootsNostrServiceConfig, #[serde(default)] pub subscriber: SubscriberConfig, } diff --git a/src/lib.rs b/src/lib.rs @@ -13,86 +13,58 @@ pub use cli::Args as cli_args; use anyhow::Result; use std::time::Duration; -use crate::{ - rhi::{Rhi, start_subscriber}, -}; +use crate::rhi::{Rhi, start_subscriber}; use radroots_identity::RadrootsIdentity; use radroots_nostr::prelude::{ - radroots_nostr_publish_application_handler, - radroots_nostr_publish_identity_profile, - RadrootsNostrApplicationHandlerSpec, - RadrootsNostrMetadata, + RadrootsNostrApplicationHandlerSpec, radroots_nostr_bootstrap_service_presence, }; use radroots_trade::listing::dvm_kinds::TRADE_LISTING_DVM_KINDS; use tracing::{info, warn}; -fn metadata_has_fields(md: &RadrootsNostrMetadata) -> bool { - md.name.is_some() - || md.display_name.is_some() - || md.about.is_some() - || md.website.is_some() - || md.picture.is_some() - || md.banner.is_some() - || md.nip05.is_some() - || md.lud06.is_some() - || md.lud16.is_some() - || !md.custom.is_empty() -} - pub async fn run_rhi(settings: &config::Settings, args: &cli_args) -> Result<()> { let identity = RadrootsIdentity::load_or_generate( - args.identity.as_ref(), - args.allow_generate_identity, + args.service.identity.as_ref(), + args.service.allow_generate_identity, )?; let keys = identity.keys().clone(); let rhi = Rhi::new(keys.clone()); let client = rhi.client.clone(); - let relays = settings.config.relays.clone(); + let service_cfg = settings.config.service.clone(); + let relays = service_cfg.relays.clone(); for relay in &relays { client.add_relay(relay).await?; } let md = settings.metadata.clone(); - let has_metadata = metadata_has_fields(&md); if !relays.is_empty() { - client.connect().await; - client.wait_for_connection(Duration::from_secs(5)).await; - let profile_published = match radroots_nostr_publish_identity_profile(&client, &identity).await - { - Ok(Some(_)) => true, - Ok(None) => false, - Err(e) => { - warn!("Failed to publish identity profile: {e}"); - false - } - }; - if has_metadata && !profile_published { - if let Err(e) = client.set_metadata(&md).await { - warn!("Failed to publish metadata on startup: {e}"); - } else { - info!("Published metadata on startup"); - } - } - let handler_kinds = TRADE_LISTING_DVM_KINDS .iter() .map(|kind| *kind as u32) .collect(); let handler_spec = RadrootsNostrApplicationHandlerSpec { kinds: handler_kinds, - identifier: settings.config.nip89_identifier.clone(), + identifier: service_cfg.nip89_identifier.clone(), metadata: Some(md.clone()), - extra_tags: settings.config.nip89_extra_tags.clone(), + extra_tags: service_cfg.nip89_extra_tags.clone(), relays: relays.clone(), nostrconnect_url: None, }; - if let Err(e) = radroots_nostr_publish_application_handler(&client, &handler_spec).await { - warn!("Failed to publish NIP-89 announcement: {e}"); + if let Err(e) = radroots_nostr_bootstrap_service_presence( + &client, + &identity, + None, + &md, + &handler_spec, + Duration::from_secs(5), + ) + .await + { + warn!("Failed to publish service presence on startup: {e}"); } else { - info!("Published NIP-89 announcement"); + info!("Published service presence on startup"); } } diff --git a/src/main.rs b/src/main.rs @@ -18,8 +18,8 @@ async fn main() -> ExitCode { async fn run() -> Result<()> { let (args, settings): (cli_args, config::Settings) = radroots_runtime::parse_and_load_path_with_init( - |a: &cli_args| Some(a.config.as_path()), - |cfg: &config::Settings| cfg.config.logs_dir.as_str(), + |a: &cli_args| Some(a.service.config.as_path()), + |cfg: &config::Settings| cfg.config.service.logs_dir.as_str(), None, ) .context("load configuration")?;