diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 128 |
1 files changed, 47 insertions, 81 deletions
diff --git a/src/main.rs b/src/main.rs index 67cb366..217a9a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,20 +5,18 @@ use std::collections::HashMap; use std::future::IntoFuture; -use std::net::SocketAddr; -use std::path::PathBuf; -use std::sync::atomic::AtomicBool; 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::{broadcast, mpsc, watch, RwLock}; +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; @@ -30,77 +28,21 @@ use api::auth::AuthState; use document::replica::{Epoch, Replica}; use state::{AppState, NodeLifecycle, Timing}; use swarm::{bootstrap, peer, sync}; +use transport::Transport; use transport::firewall::{Firewall, FirewallTransport}; use transport::mycelium::{self, MyceliumSetup, MyceliumSpawnConfig}; -use transport::Transport; - -#[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_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>, - - #[arg(long)] - 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, - - /// 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>, -} +use transport::traffic::{CountingTransport, Traffic}; #[tokio::main] async fn main() -> Result<()> { logging::init(); - let args = Args::parse(); + let config = config::load()?; + if config.print_only { + println!("{}", serde_json::to_string_pretty(&config.report())?); + return Ok(()); + } + let args = &config.settings; // Read before anything starts, so a bad key file fails right away. let swarm_key = match &args.swarm_key_file { @@ -117,13 +59,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, - peers: args.mycelium_peers, + 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.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! { @@ -143,7 +86,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(); @@ -161,6 +104,7 @@ async fn main() -> Result<()> { debug!(epoch = %initial_epoch, "Local epoch"); let firewall = Arc::new(Firewall::default()); + let traffic = Arc::new(Traffic::default()); let mycelium_transport = Arc::new(mycelium::MyceliumTransport::connect(mycelium_setup).await?); debug!(local_id = mycelium_transport.local_id(), "Transport ready"); @@ -172,11 +116,18 @@ async fn main() -> Result<()> { discovered_swarm_id: None, })), peer_states: Arc::new(RwLock::new(HashMap::new())), - transport: Arc::new(FirewallTransport::new( - mycelium_transport, - Arc::clone(&firewall), + // Counted outside the firewall: what it drops outbound counts as sent (it plays a + // lossy network), what it drops inbound never arrived. + transport: Arc::new(CountingTransport::new( + Arc::new(FirewallTransport::new( + mycelium_transport, + Arc::clone(&firewall), + )), + Arc::clone(&traffic), )), firewall, + traffic, + stats: Default::default(), sync_events: sync_tx, change_tx, initial_sync_done: Arc::new(AtomicBool::new(false)), @@ -184,7 +135,22 @@ async fn main() -> Result<()> { timing: Timing::from_keepalive(Duration::from_secs(args.keepalive_secs)), remake: Arc::new(remake::RemakeState::default()), swarm_key, + run_id: uuid::Uuid::new_v4().into_bytes(), + neighbours_k: args.neighbours, + alias: args.alias.clone(), + electorate_window: Duration::from_secs(args.electorate_window_days * 24 * 3600), + blobs: Arc::new(swarm::blob::Blobs::new(args.blob_chunk_kib * 1024)), + protocol_writers: Arc::new(args.protocol_writers.iter().cloned().collect()), + config: Arc::new(config.report()), + neighbours: Default::default(), + pulling: Default::default(), + announce_pending: Default::default(), + rtt: Default::default(), + throughput: Default::default(), + stability: Default::default(), stale: Default::default(), + catch_up_source: Default::default(), + catch_up_preference: Default::default(), }; trace!("Application state initialized"); @@ -194,7 +160,7 @@ async fn main() -> Result<()> { let inner_state = consumer_state.clone(); let _ = consumer_state .transport - .start_consumer(Box::new(move |sender, msg| { + .start_consumer(Box::new(move |sender, msg, _payload_len| { let state_clone = inner_state.clone(); Box::pin(async move { peer::handle_message(&state_clone, sender, msg).await }) })) @@ -287,7 +253,7 @@ async fn main() -> Result<()> { /// Turns SIGINT and SIGTERM into a shutdown request. A second signal exits at once (the /// supervised Mycelium still gets its parent-death signal then). fn watch_for_shutdown() -> Result<watch::Receiver<bool>> { - use tokio::signal::unix::{signal, SignalKind}; + use tokio::signal::unix::{SignalKind, signal}; let mut interrupt = signal(SignalKind::interrupt())?; let mut terminate = signal(SignalKind::terminate())?; |
