rhi

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

commit 9f673e9e59a27336cb98037730802e92f18a7bac
parent 270b64d5782668c9cda9107332c35845bc765ffe
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sat, 12 Apr 2025 19:14:14 +0000

Adds file based configuration interface and initial schema for Nostr kind 0 metadata.

Diffstat:
M.gitignore | 4++--
MCargo.lock | 332++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
MCargo.toml | 1+
Aconfig.toml | 29+++++++++++++++++++++++++++++
Asrc/config.rs | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib.rs | 1+
Msrc/main.rs | 41+++++++++++------------------------------
7 files changed, 429 insertions(+), 33 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -11,4 +11,5 @@ notes*.txt .DS_Store *.pem -*keys*.json -\ No newline at end of file +*keys*.json +*rhi*.toml diff --git a/Cargo.lock b/Cargo.lock @@ -93,12 +93,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + +[[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "async-utility" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -158,6 +175,12 @@ dependencies = [ [[package]] name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" @@ -223,6 +246,9 @@ name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -360,6 +386,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] +name = "config" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "winnow", + "yaml-rust2", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -369,6 +443,12 @@ dependencies = [ ] [[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -408,12 +488,36 @@ dependencies = [ ] [[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] name = "errno" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -436,6 +540,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -563,6 +673,30 @@ dependencies = [ ] [[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -749,6 +883,16 @@ dependencies = [ ] [[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + +[[package]] name = "inout" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -793,6 +937,17 @@ dependencies = [ ] [[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -882,7 +1037,7 @@ version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f900ddcdc28395759fcd44b18a03255e7deee8858551bfe5d5d5a07311d82ea" dependencies = [ - "base64", + "base64 0.22.1", "bech32", "bip39", "bitcoin_hashes 0.14.0", @@ -975,6 +1130,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + +[[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1015,6 +1180,12 @@ dependencies = [ ] [[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] name = "pbkdf2" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1031,6 +1202,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1190,6 +1406,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "config", "nostr", "nostr-sdk", "serde", @@ -1217,6 +1434,29 @@ dependencies = [ ] [[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags", + "serde", + "serde_derive", +] + +[[package]] +name = "rust-ini" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + +[[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1358,6 +1598,15 @@ dependencies = [ ] [[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1532,6 +1781,15 @@ dependencies = [ ] [[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1624,6 +1882,40 @@ dependencies = [ ] [[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1681,6 +1973,12 @@ dependencies = [ ] [[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + +[[package]] name = "tungstenite" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1706,6 +2004,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1721,6 +2025,12 @@ dependencies = [ ] [[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2003,6 +2313,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "winnow" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +dependencies = [ + "memchr", +] + +[[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2024,6 +2343,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] +name = "yaml-rust2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818913695e83ece1f8d2a1c52d54484b7b46d0f9c06beeb2649b9da50d9b512d" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + +[[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -9,6 +9,7 @@ description = "rhizome is a Nostr data vending machine (NIP-90)" [dependencies] anyhow = "1.0" clap = { version = "4", features = ["derive"] } +config = "0.15" nostr = "0.40.0" nostr-sdk = "0.40.0" serde = "1.0" diff --git a/config.toml b/config.toml @@ -0,0 +1,29 @@ +# rhizome Nostr data vending machine configuration + +[metadata] +# The name shown on the profile +name = "rhi" + +# A full display name that can include emojis or symbols +# display_name = "" + +# A profile biography or description +# about = "" + +# URL of profile picture +# picture = "" + +# URL of banner image +# banner = "" + +# URL of website +# banner = "" + +# Profile mapping to DNS-based internet identifier +# nip05 = "" + +# Lightning address LNURL format +# lud06 = "" + +# Lightning address internet identifiers format +# lud16 = "" diff --git a/src/config.rs b/src/config.rs @@ -0,0 +1,54 @@ +use anyhow::Result; +use config::{Config, ConfigError, File}; +use nostr::Metadata; +use serde::{Deserialize, Serialize}; +use thiserror::Error; +use tracing::{error, warn}; + +#[derive(Debug, Error)] +pub enum SettingsError { + #[error("Configuration loading failed: {0}")] + Load(#[from] ConfigError), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Settings { + pub metadata: Metadata, +} + +impl Settings { + pub fn load(config_path: &Option<String>) -> Result<Self, SettingsError> { + let default = Self::default(); + + match Self::load_from_file(config_path) { + Ok(settings) => Ok(settings), + Err(err) if config_path.is_none() => { + warn!("Could not read config file: {err}. Using default configuration.",); + Ok(default) + } + Err(err) => Err(err), + } + } + + fn load_from_file(config_path: &Option<String>) -> Result<Self, SettingsError> { + let path = config_path.as_deref().unwrap_or("config.toml"); + + let config = Config::builder() + .add_source(File::with_name(path).required(false)) + .build()? + .try_deserialize::<Settings>()?; + + Ok(config) + } +} + +impl Default for Settings { + fn default() -> Self { + Self { + metadata: Metadata { + name: Some("rhi".to_string()), + ..Default::default() + }, + } + } +} diff --git a/src/lib.rs b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod keys; pub const KIND_JOB_REQUEST: u16 = 5300; diff --git a/src/main.rs b/src/main.rs @@ -1,16 +1,11 @@ use anyhow::Result; use clap::Parser; -use nostr::{Filter, Keys, Kind, Timestamp, event::Event, nips::nip01::Metadata}; +use nostr::{Filter, Keys, Kind, Timestamp, event::Event}; use nostr_sdk::{Client, RelayPoolNotification}; -use rhi::{KIND_JOB_REQUEST, keys::KeyProfile}; +use rhi::{KIND_JOB_REQUEST, config::Settings, keys::KeyProfile}; use tokio::signal::unix::{SignalKind, signal}; use tracing::{error, info}; -struct ConfigMetadata { - name: String, - nip_05: Option<String>, -} - fn init_tracing() { tracing_subscriber::fmt::init(); } @@ -56,15 +51,15 @@ async fn subscribe(keys: Keys, relays: Vec<String>) -> Result<()> { version = env!("CARGO_PKG_VERSION") )] pub struct Args { - #[arg(long, help = "Adds the keys profiles file path.", required = true)] + #[arg(long, help = "Adds the keys profiles file path", required = true)] pub keys: String, - #[arg(long, help = "Adds nostr relays to the subscription.", required = true)] + #[arg(long, help = "Adds nostr relays to the subscription", required = true)] pub relays: Vec<String>, #[arg( long, - help = "(Optional) Sets flag to generate keys if none are found.", + help = "(Optional) Sets flag to generate keys if none are found", required = false )] pub generate_keys: bool, @@ -78,10 +73,10 @@ pub struct Args { #[arg( long, - help = "(Optional) Adds the domain name (NIP-05) to metadata", + help = "(Optional) Adds the config file path. Defaults to 'config.toml'", required = false )] - pub nip05_domain: Option<String>, + pub config: Option<String>, } #[tokio::main] @@ -89,6 +84,8 @@ async fn main() -> Result<()> { init_tracing(); let args = Args::parse(); + let config = Settings::load(&args.config)?; + let relays = args.relays.clone(); info!("Starting"); @@ -97,21 +94,7 @@ async fn main() -> Result<()> { let keys = key_profile.keys()?; - let config = ConfigMetadata { - name: "rhi".to_string(), - nip_05: args.nip05_domain, - }; - - let metadata = Metadata { - name: Some(config.name.clone()), - display_name: None, - picture: None, - nip05: config - .nip_05 - .as_ref() - .map(|domain| format!("{}@{}", config.name, domain)), - ..Default::default() - }; + let metadata = config.metadata.clone(); let mut events: Vec<Event> = vec![]; @@ -131,9 +114,7 @@ async fn main() -> Result<()> { client.connect().await; for event in events { client.send_event(&event).await?; - info!("Sent kind {} event for key profile", { - event.clone().kind - }) + info!("Sent kind {} event for key profile", { event.clone().kind }) } client.disconnect().await; }