#![doc = include_str!("../README.md")] use clap::{Parser, Subcommand}; use commonware_runtime::{ Runner, Supervisor as _, tokio::{self, telemetry::Logs}, }; use std::path::PathBuf; use tracing::Level; mod application; mod config; mod dkg; mod setup; mod types; mod validator; #[derive(Parser)] struct Cli { /// Minimum trace level emitted by the node. #[arg(long, default_value_t = Level::INFO)] log_level: Level, /// Number of Tokio worker threads. #[arg(long, default_value_t = 3)] worker_threads: usize, /// Command to run. #[command(subcommand)] command: Command, } #[derive(Subcommand)] enum Command { Dkg(dkg::Dkg), Setup(setup::Setup), Validator(validator::Validator), } impl Command { fn runtime_dir(&self) -> PathBuf { match self { Self::Dkg(args) => args.node_dir.join("runtime"), Self::Setup(args) => args.node_dir.join("runtime"), Self::Validator(args) => args.node_dir.join("runtime"), } } } fn main() { let cli = Cli::parse(); // Setup generates configuration and needs no runtime. Run it before the // runner starts, since `Runner::start` acquires a hold on (and creates) the // storage directory inside the node directory setup requires to be empty. if let Command::Setup(args) = cli.command { return setup::run(args); } // The remaining commands run a node, so they get a runtime whose storage // lives inside the node directory. let runtime_dir = cli.command.runtime_dir(); let config = tokio::Config::new() .with_worker_threads(cli.worker_threads) .with_catch_panics(false) .with_storage_directory(runtime_dir); let runner = tokio::Runner::new(config); runner.start(|context| async move { tokio::telemetry::init( context.child("telemetry"), Logs { level: cli.log_level, json: false, }, None, None, ); match cli.command { Command::Dkg(args) => dkg::run(context, args).await, Command::Validator(args) => validator::run(context, args).await, Command::Setup(_) => unreachable!("setup runs without a runtime"), } }); }