From e5d590f4e927a18fbed334a3d90650015ed75106 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 24 Oct 2026 15:11:37 +0200 Subject: add configuration files --- src/main.rs | 118 ++++++------------------------------------------------------ 1 file changed, 11 insertions(+), 107 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index f6c7b5d..f89cd13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,21 +5,18 @@ use std::collections::HashMap; use std::future::IntoFuture; -use std::net::SocketAddr; -use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::time::Duration; use anyhow::{Context, Result}; use automerge::AutoCommit; -use clap::Parser; use tokio::sync::{RwLock, broadcast, mpsc, watch}; use tracing::{debug, error, info, trace, warn}; -use url::Url; mod api; mod backoff; +mod config; mod document; mod logging; mod remake; @@ -36,105 +33,12 @@ use transport::firewall::{Firewall, FirewallTransport}; use transport::mycelium::{self, MyceliumSetup, MyceliumSpawnConfig}; use transport::traffic::{CountingTransport, Traffic}; -#[derive(Parser, Debug)] -#[command(version, about = "continuum messaging system", long_about = None)] -struct Args { - #[arg(long)] - debug_api: bool, - - #[arg(long, value_name = "HOSTNAME:PORT", default_value = "127.0.0.1:3000")] - bind_addr: SocketAddr, - - #[arg( - long, - value_name = "SCHEME://HOSTNAME:PORT", - default_value = None, - conflicts_with_all = &["mycelium_key_file", "mycelium_network_key_file", "mycelium_network_name", "mycelium_tcp_listen_port"], - )] - mycelium_rest_url: Option, - - #[arg(long)] - pub mycelium_key_file: Option, - - #[arg(long)] - pub mycelium_network_key_file: Option, - - #[arg(long)] - pub mycelium_network_name: Option, - - /// TCP port the supervised Mycelium daemon listens on for overlay peers; a free - /// port if absent. - #[arg(long, value_name = "PORT")] - pub mycelium_tcp_listen_port: Option, - - #[arg( - long, - use_value_delimiter = true, - default_value = "tls://127.0.0.1:9651" - )] - /// Peers of the supervised Mycelium daemon (overlay links such as - /// `tls://host:9651`), not continuum peers. - pub mycelium_peers: Vec, - - /// Seeds: how to reach a node of the swarm to join, as a Mycelium public key, a - /// Mycelium IPv6 address, or a host name with an AAAA record for one. Without seeds, - /// the node starts a new swarm (genesis). - #[arg(long, value_name = "STRING,[STRING...]", value_delimiter = ',')] - seeds: Option>, - - #[arg(long, value_name = "PATH")] - htpasswd: String, - - /// Pre-shared swarm key: only nodes that know it may join (raw bytes, at least 16; - /// e.g. `head -c 32 /dev/urandom`). Without it, anyone who knows the swarm ID can. - #[arg(long, value_name = "PATH")] - swarm_key_file: Option, - - /// Keepalive interval; dormancy, resync and probe timings derive from it. - #[arg(long, value_name = "SECONDS", default_value_t = 60)] - keepalive_secs: u64, - - /// Neighbours each node keeps (at least 2). Swarms of up to this many + 1 nodes are - /// a full mesh; larger ones sync over several hops. - #[arg(long, value_name = "COUNT", default_value_t = 12)] - neighbours: usize, - - /// A name for this node, shown next to its public key (/peers, metrics). - /// Published in the swarm's member list; not unique, never an identity. - #[arg(long, value_name = "NAME", value_parser = parse_alias)] - alias: Option, - - /// Members that renewed their alive stamp within this many days vote on remakes - /// (a majority of them must agree). Matters on the node that coordinates a remake. - #[arg(long, value_name = "DAYS", default_value_t = 7, value_parser = clap::value_parser!(u64).range(1..))] - electorate_window_days: u64, - - /// Test hook: start on a non-genesis epoch of this generation (with a fixed dummy - /// id), to check that nodes on different epochs refuse to sync. - #[arg(long, hide = true, requires = "debug_api", value_name = "GENERATION")] - debug_epoch: Option, -} - -/// Up to 64 characters, no control characters, not blank. -fn parse_alias(value: &str) -> Result { - let alias = value.trim(); - if alias.is_empty() { - return Err("must not be blank".to_owned()); - } - if alias.chars().count() > 64 { - return Err("must be at most 64 characters".to_owned()); - } - if alias.chars().any(char::is_control) { - return Err("must not contain control characters".to_owned()); - } - Ok(alias.to_owned()) -} - #[tokio::main] async fn main() -> Result<()> { logging::init(); - let args = Args::parse(); + let config = config::load()?; + let args = &config.settings; // Read before anything starts, so a bad key file fails right away. let swarm_key = match &args.swarm_key_file { @@ -151,14 +55,14 @@ async fn main() -> Result<()> { let mycelium_setup = { let mut spawn_config = MyceliumSpawnConfig { - rest_url_opt: args.mycelium_rest_url, - key_file_opt: args.mycelium_key_file, - network_key_file: args.mycelium_network_key_file, + rest_url_opt: args.mycelium_rest_url(), + key_file_opt: args.mycelium_key_file.clone(), + network_key_file: args.mycelium_network_key_file.clone(), tcp_port: args.mycelium_tcp_listen_port, - peers: args.mycelium_peers, + peers: args.mycelium_peers.clone(), ..Default::default() }; - if let Some(net_name) = args.mycelium_network_name { + if let Some(net_name) = args.mycelium_network_name.clone() { spawn_config.network_name = net_name; } tokio::select! { @@ -178,7 +82,7 @@ async fn main() -> Result<()> { "Using Mycelium REST API" ); - let seeds: Vec = args.seeds.unwrap_or_default(); + let seeds: Vec = args.seeds.clone(); debug!(seed_count = seeds.len(), "Loaded bootstrap configuration"); let (sync_tx, sync_rx) = mpsc::unbounded_channel(); @@ -228,8 +132,8 @@ async fn main() -> Result<()> { remake: Arc::new(remake::RemakeState::default()), swarm_key, run_id: uuid::Uuid::new_v4().into_bytes(), - neighbours_k: args.neighbours.max(2), - alias: args.alias, + neighbours_k: args.neighbours, + alias: args.alias.clone(), electorate_window: Duration::from_secs(args.electorate_window_days * 24 * 3600), neighbours: Default::default(), pulling: Default::default(), -- cgit v1.3.1