summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-24 15:11:37 +0200
committertv <tv@krebsco.de>2026-10-24 15:11:37 +0200
commite5d590f4e927a18fbed334a3d90650015ed75106 (patch)
tree81483f982a9f719ded1d60b2dd3caa97e6a53a3a /src/main.rs
parente66c24101a0a93e49c3959dc6094879d51e823e8 (diff)
add configuration files
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs118
1 files changed, 11 insertions, 107 deletions
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<Url>,
-
- #[arg(long)]
- pub mycelium_key_file: Option<PathBuf>,
-
- #[arg(long)]
- pub mycelium_network_key_file: Option<PathBuf>,
-
- #[arg(long)]
- pub mycelium_network_name: Option<String>,
-
- /// 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<u16>,
-
- #[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<String>,
-
- /// 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<Vec<String>>,
-
- #[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<PathBuf>,
-
- /// 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<String>,
-
- /// 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<u64>,
-}
-
-/// Up to 64 characters, no control characters, not blank.
-fn parse_alias(value: &str) -> Result<String, String> {
- 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<String> = args.seeds.unwrap_or_default();
+ let seeds: Vec<String> = 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(),