diff --git a/Cargo.lock b/Cargo.lock index b94cb7d3..f793a864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -977,26 +977,11 @@ dependencies = [ "atty", "bitflags 1.3.2", "strsim 0.8.0", - "textwrap 0.11.0", + "textwrap", "unicode-width", "vec_map", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim 0.10.0", - "termcolor", - "textwrap 0.16.0", -] - [[package]] name = "clap" version = "4.3.23" @@ -1016,8 +1001,9 @@ checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.0", + "clap_lex", "strsim 0.10.0", + "terminal_size", ] [[package]] @@ -1032,15 +1018,6 @@ dependencies = [ "syn 2.0.29", ] -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "clap_lex" version = "0.5.0" @@ -3570,12 +3547,6 @@ dependencies = [ "hashbrown 0.12.3", ] -[[package]] -name = "os_str_bytes" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" - [[package]] name = "oslog" version = "0.2.0" @@ -4942,6 +4913,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.23", + "windows-sys 0.48.0", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -4951,12 +4932,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.47" @@ -5818,7 +5793,7 @@ dependencies = [ "backtrace", "bugsalot", "cfg-if 1.0.0", - "clap 3.2.25", + "clap 4.3.23", "color-eyre", "config", "console-subscriber", diff --git a/veilid-cli/Cargo.toml b/veilid-cli/Cargo.toml index 54564617..a1238834 100644 --- a/veilid-cli/Cargo.toml +++ b/veilid-cli/Cargo.toml @@ -27,7 +27,7 @@ cursive_buffered_backend = { path = "../external/cursive_buffered_backend" } cursive_table_view = "0.14.0" arboard = "3.2.0" # cursive-tabs = "0.5.0" -clap = {version= "4", features = ["derive"]} +clap = { version= "4", features = ["derive"] } directories = "^4" log = "^0" futures = "^0" diff --git a/veilid-server/Cargo.toml b/veilid-server/Cargo.toml index 2321928f..2f70f433 100644 --- a/veilid-server/Cargo.toml +++ b/veilid-server/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "veilid-server" +description = "Veilid Server" version = "0.1.10" authors = ["Veilid Team "] license = "MPL-2.0" @@ -37,7 +38,7 @@ tokio-util = { version = "^0", features = ["compat"], optional = true} async-tungstenite = { version = "^0", features = ["async-tls"] } color-eyre = { version = "^0", default-features = false } backtrace = "^0" -clap = "^3" +clap = { version= "4", features = ["derive", "string", "wrap_help"] } directories = "^4" parking_lot = "^0" config = { version = "^0", features = ["yaml"] } diff --git a/veilid-server/src/cmdline.rs b/veilid-server/src/cmdline.rs deleted file mode 100644 index 5e57e9b8..00000000 --- a/veilid-server/src/cmdline.rs +++ /dev/null @@ -1,337 +0,0 @@ -use crate::settings::*; -use crate::*; -use clap::{Arg, ArgMatches, Command}; -use std::ffi::OsStr; -use std::path::Path; -use std::str::FromStr; -use veilid_core::{TypedKeyGroup, TypedSecretGroup}; - -fn do_clap_matches(default_config_path: &OsStr) -> Result { - let matches = Command::new("veilid-server") - .version(env!("CARGO_PKG_VERSION")) - .about("Veilid Server") - .color(clap::ColorChoice::Auto) - .arg( - Arg::new("daemon") - .long("daemon") - .short('d') - .help("Run in daemon mode in the background"), - ) - .arg( - Arg::new("foreground") - .long("foreground") - .short('f') - .conflicts_with("daemon") - .help("Run in the foreground"), - ) - .arg( - Arg::new("config-file") - .short('c') - .long("config-file") - .takes_value(true) - .value_name("FILE") - .default_value_os(default_config_path) - .allow_invalid_utf8(true) - .help("Specify a configuration file to use"), - ) - .arg( - Arg::new("set-config") - .short('s') - .long("set-config") - .takes_value(true) - .multiple_occurrences(true) - .help("Specify configuration value to set (key in dot format, value in json format), eg: logging.api.enabled=true") - ) - .arg( - Arg::new("password") - .short('p') - .long("password") - .takes_value(true) - .help("Specify password to use to protect the device encryption key") - ) - .arg( - Arg::new("new-password") - .long("new-password") - .takes_value(true) - .help("Change password used to protect the device encryption key. Device storage will be migrated.") - ) - .arg( - Arg::new("attach") - .long("attach") - .takes_value(true) - .value_name("BOOL") - .possible_values(&["false", "true"]) - .help("Automatically attach the server to the Veilid network"), - ) - // Dev options - .arg( - Arg::new("debug") - .long("debug") - .help("Turn on debug logging on the terminal"), - ) - .arg( - Arg::new("trace") - .long("trace") - .conflicts_with("debug") - .help("Turn on trace logging on the terminal"), - ) - .arg( - Arg::new("otlp") - .long("otlp") - .takes_value(true) - .value_name("endpoint") - .default_missing_value("localhost:4317") - .help("Turn on OpenTelemetry tracing") - .long_help("This option uses the GRPC OpenTelemetry protocol, not HTTP. The format for the endpoint is host:port, like 'localhost:4317'"), - ) - .arg( - Arg::new("subnode-index") - .long("subnode-index") - .takes_value(true) - .help("Run as an extra daemon on the same machine for testing purposes, specify a number greater than zero to offset the listening ports"), - ) - .arg( - Arg::new("generate-key-pair") - .long("generate-key-pair") - .takes_value(true) - .value_name("crypto_kind") - .default_missing_value("") - .help("Only generate a new keypair and print it") - .long_help("Generate a new keypair for a specific crypto kind and print both the key and its secret to the terminal, then exit immediately."), - ) - .arg( - Arg::new("set-node-id") - .long("set-node-id") - .takes_value(true) - .value_name("key_set") - .help("Set the node ids and secret keys") - .long_help("Specify node ids in typed key set format ('[VLD0:xxxx,VLD1:xxxx]') on the command line, a prompt appears to enter the secret key set interactively.") - ) - .arg( - Arg::new("delete-protected-store") - .long("delete-protected-store") - .help("Delete the entire contents of the protected store (DANGER, NO UNDO!)"), - ) - .arg( - Arg::new("delete-table-store") - .long("delete-table-store") - .help("Delete the entire contents of the table store (DANGER, NO UNDO!)"), - ) - .arg( - Arg::new("delete-block-store") - .long("delete-block-store") - .help("Delete the entire contents of the block store (DANGER, NO UNDO!)"), - ) - .arg( - Arg::new("dump-config") - .long("dump-config") - .help("Instead of running the server, print the configuration it would use to the console"), - ) - .arg( - Arg::new("dump-txt-record") - .long("dump-txt-record") - .help("Prints the bootstrap TXT record for this node and then quits") - ) - .arg( - Arg::new("emit-schema") - .long("emit-schema") - .takes_value(true) - .value_name("schema_name") - .default_missing_value("") - .help("Emits a JSON-Schema for a named type") - ) - .arg( - Arg::new("bootstrap") - .long("bootstrap") - .takes_value(true) - .value_name("BOOTSTRAP_LIST") - .help("Specify a list of bootstrap hostnames to use") - ) - .arg( - Arg::new("panic") - .long("panic") - .help("panic on ctrl-c instead of graceful shutdown"), - ) - .arg( - Arg::new("network-key") - .long("network-key") - .takes_value(true) - .help("password override to use for network isolation"), - ) - ; - - #[cfg(feature = "rt-tokio")] - let matches = matches.arg( - Arg::new("console") - .long("console") - .help("enable tokio console"), - ); - - #[cfg(debug_assertions)] - let matches = matches.arg( - Arg::new("wait-for-debug") - .long("wait-for-debug") - .help("Wait for debugger to attach"), - ); - - Ok(matches.get_matches()) -} - -pub fn process_command_line() -> EyreResult<(Settings, ArgMatches)> { - // Get command line options - let default_config_path = Settings::get_default_config_path(); - let matches = do_clap_matches(default_config_path.as_os_str()) - .wrap_err("failed to parse command line: {}")?; - - // Check for one-off commands - #[cfg(debug_assertions)] - if matches.occurrences_of("wait-for-debug") != 0 { - use bugsalot::debugger; - debugger::wait_until_attached(None).expect("state() not implemented on this platform"); - } - - // Attempt to load configuration - let settings_path = if let Some(config_file) = matches.value_of_os("config-file") { - if Path::new(config_file).exists() { - Some(config_file) - } else { - None - } - } else { - None - }; - - let settings = Settings::new(settings_path).wrap_err("configuration is invalid")?; - - // write lock the settings - let mut settingsrw = settings.write(); - - // Set config from command line - if matches.occurrences_of("daemon") != 0 { - settingsrw.daemon.enabled = true; - settingsrw.logging.terminal.enabled = false; - } - if matches.occurrences_of("foreground") != 0 { - settingsrw.daemon.enabled = false; - } - if matches.occurrences_of("subnode-index") != 0 { - let subnode_index = match matches.value_of("subnode-index") { - Some(x) => x.parse().wrap_err("couldn't parse subnode index")?, - None => { - bail!("value not specified for subnode-index"); - } - }; - if subnode_index == 0 { - bail!("value of subnode_index should be between 1 and 65535"); - } - settingsrw.testing.subnode_index = subnode_index; - } - - if matches.occurrences_of("debug") != 0 { - settingsrw.logging.terminal.enabled = true; - settingsrw.logging.terminal.level = LogLevel::Debug; - } - if matches.occurrences_of("trace") != 0 { - settingsrw.logging.terminal.enabled = true; - settingsrw.logging.terminal.level = LogLevel::Trace; - } - if matches.occurrences_of("otlp") != 0 { - settingsrw.logging.otlp.enabled = true; - settingsrw.logging.otlp.grpc_endpoint = NamedSocketAddrs::from_str( - &matches - .value_of("otlp") - .expect("should not be null because of default missing value") - .to_string(), - ) - .wrap_err("failed to parse OTLP address")?; - settingsrw.logging.otlp.level = LogLevel::Trace; - } - if matches.is_present("attach") { - settingsrw.auto_attach = !matches!(matches.value_of("attach"), Some("true")); - } - if matches.occurrences_of("delete-protected-store") != 0 { - settingsrw.core.protected_store.delete = true; - } - if matches.occurrences_of("delete-block-store") != 0 { - settingsrw.core.block_store.delete = true; - } - if matches.occurrences_of("delete-table-store") != 0 { - settingsrw.core.table_store.delete = true; - } - if matches.occurrences_of("password") != 0 { - settingsrw.core.protected_store.device_encryption_key_password = matches.value_of("password").unwrap().to_owned(); - } - if matches.occurrences_of("new-password") != 0 { - settingsrw.core.protected_store.new_device_encryption_key_password = Some(matches.value_of("new-password").unwrap().to_owned()); - } - if matches.occurrences_of("network-key") != 0 { - settingsrw.core.network.network_key_password = Some(matches.value_of("network-key").unwrap().to_owned()); - } - - if matches.occurrences_of("dump-txt-record") != 0 { - // Turn off terminal logging so we can be interactive - settingsrw.logging.terminal.enabled = false; - } - if let Some(v) = matches.value_of("set-node-id") { - // Turn off terminal logging so we can be interactive - settingsrw.logging.terminal.enabled = false; - - // Split or get secret - let tks = - TypedKeyGroup::from_str(v).wrap_err("failed to decode node id set from command line")?; - - let buffer = rpassword::prompt_password("Enter secret key set (will not echo): ") - .wrap_err("invalid secret key")?; - let buffer = buffer.trim().to_string(); - let tss = TypedSecretGroup::from_str(&buffer).wrap_err("failed to decode secret set")?; - - settingsrw.core.network.routing_table.node_id = Some(tks); - settingsrw.core.network.routing_table.node_id_secret = Some(tss); - } - - if matches.occurrences_of("bootstrap") != 0 { - let bootstrap_list = match matches.value_of("bootstrap") { - Some(x) => { - println!("Overriding bootstrap list with: "); - let mut out: Vec = Vec::new(); - for x in x.split(',') { - let x = x.trim().to_string(); - if !x.is_empty() { - println!(" {}", x); - out.push(x); - } - } - out - } - None => { - bail!("value not specified for bootstrap"); - } - }; - settingsrw.core.network.routing_table.bootstrap = bootstrap_list; - } - - #[cfg(feature = "rt-tokio")] - if matches.occurrences_of("console") != 0 { - settingsrw.logging.console.enabled = true; - } - - drop(settingsrw); - - // Set specific config settings - if let Some(set_configs) = matches.values_of("set-config") { - for set_config in set_configs { - if let Some((k, v)) = set_config.split_once('=') { - let k = k.trim(); - let v = v.trim(); - settings.set(k, v)?; - } - } - } - - // Apply subnode index if we're testing - settings - .apply_subnode_index() - .wrap_err("failed to apply subnode index")?; - - Ok((settings, matches)) -} diff --git a/veilid-server/src/main.rs b/veilid-server/src/main.rs index b8d77e94..10ce9c79 100644 --- a/veilid-server/src/main.rs +++ b/veilid-server/src/main.rs @@ -4,7 +4,6 @@ #![recursion_limit = "256"] mod client_api; -mod cmdline; mod server; mod settings; mod tools; @@ -14,82 +13,337 @@ mod veilid_logs; #[cfg(windows)] mod windows; +use crate::settings::*; + +use clap::{Args, Parser}; use server::*; +use settings::LogLevel; use std::collections::HashMap; +use std::ffi::{OsString, OsStr}; +use std::path::Path; use std::str::FromStr; use tools::*; +use veilid_core::{TypedKeyGroup, TypedSecretGroup}; use veilid_logs::*; +#[derive(Args, Debug, Clone)] +#[group(multiple = false)] +pub struct Logging { + /// Turn on debug logging on the terminal + #[arg(long)] + debug: bool, + /// Turn on trace logging on the terminal + #[arg(long)] + trace: bool, +} + +#[derive(Parser, Debug, Clone)] +#[command(author, version, about)] +pub struct CmdlineArgs { + + /// Run in daemon mode in the background + #[arg(short, long)] + daemon: bool, + + /// Run in the foreground + #[arg(short, long)] + foreground: bool, + + /// Specify a configuration file to use + #[arg(short, long, value_name = "FILE", default_value = OsString::from(Settings::get_default_config_path()))] + config_file: Option, + + /// Specify configuration value to set (key in dot format, value in json format), eg: logging.api.enabled=true + #[arg(short, long, value_name = "CONFIG")] + set_config: Vec, + + /// Specify password to use to protect the device encryption key + #[arg(short, long, value_name = "PASSWORD")] + password: Option, + + /// Change password used to protect the device encryption key. Device storage will be migrated. + #[arg(long, value_name = "PASSWORD")] + new_password: Option, + + /// Do not automatically attach the server to the Veilid network + /// + /// Default behaviour is to automatically attach the server to the Veilid network, this option disables this behaviour. + #[arg(long, value_name = "BOOL")] + no_attach: bool, + + #[command(flatten)] + logging: Logging, + + /// Turn on OpenTelemetry tracing + /// + /// This option uses the GRPC OpenTelemetry protocol, not HTTP. The format for the endpoint is host:port, like 'localhost:4317' + #[arg(long, value_name = "endpoint")] + otlp: Option, + + /// Run as an extra daemon on the same machine for testing purposes, specify a number greater than zero to offset the listening ports + #[arg(long)] + subnode_index: Option, + + /// Only generate a new keypair and print it + /// + /// Generate a new keypair for a specific crypto kind and print both the key and its secret to the terminal, then exit immediately. + #[arg(long, value_name = "crypto_kind")] + generate_key_pair: Option, + + /// Set the node ids and secret keys + /// + /// Specify node ids in typed key set format ('[VLD0:xxxx,VLD1:xxxx]') on the command line, a prompt appears to enter the secret key set interactively. + #[arg(long, value_name = "key_set")] + set_node_id: Option, + + /// Delete the entire contents of the protected store (DANGER, NO UNDO!) + #[arg(long)] + delete_protected_store: bool, + + /// Delete the entire contents of the table store (DANGER, NO UNDO!) + #[arg(long)] + delete_table_store: bool, + + /// Delete the entire contents of the block store (DANGER, NO UNDO!) + #[arg(long)] + delete_block_store: bool, + + /// Instead of running the server, print the configuration it would use to the console + #[arg(long)] + dump_config: bool, + + /// Prints the bootstrap TXT record for this node and then quits + #[arg(long)] + dump_txt_record: bool, + + /// Emits a JSON-Schema for a named type + #[arg(long, value_name = "schema_name")] + emit_schema: Option, + + /// Specify a list of bootstrap hostnames to use + #[arg(long, value_name = "BOOTSTRAP_LIST")] + bootstrap: Option, + + /// panic on ctrl-c instead of graceful shutdown + #[arg(long)] + panic: bool, + + /// password override to use for network isolation + #[arg(long, value_name = "KEY")] + network_key: Option, + + /// Wait for debugger to attach + #[cfg(debug_assertions)] + #[arg(long)] + wait_for_debug: bool, + + /// enable tokio console + #[cfg(feature = "rt-tokio")] + #[arg(long)] + console: bool, +} + #[instrument(err)] fn main() -> EyreResult<()> { #[cfg(windows)] let _ = ansi_term::enable_ansi_support(); color_eyre::install()?; - let (settings, matches) = cmdline::process_command_line()?; + // Get command line options + let args = CmdlineArgs::parse(); + + let svc_args = args.clone(); + + // Check for one-off commands + #[cfg(debug_assertions)] + if args.wait_for_debug{ + use bugsalot::debugger; + debugger::wait_until_attached(None).expect("state() not implemented on this platform"); + } + + // Attempt to load configuration + let settings_path: Option<&OsStr> = if let Some(config_file) = &args.config_file { + if Path::new(&config_file).exists() { + Some(config_file) + } else { + None + } + } else { + None + }; + + let settings = Settings::new(settings_path).wrap_err("configuration is invalid")?; + + // write lock the settings + let mut settingsrw = settings.write(); + + // Set config from command line + if args.daemon { + settingsrw.daemon.enabled = true; + settingsrw.logging.terminal.enabled = false; + } + if args.foreground { + settingsrw.daemon.enabled = false; + } + if let Some(subnode_index) = args.subnode_index { + if subnode_index == 0 { + bail!("value of subnode_index should be between 1 and 65535"); + } + settingsrw.testing.subnode_index = subnode_index; + }; + + if args.logging.debug { + settingsrw.logging.terminal.enabled = true; + settingsrw.logging.terminal.level = LogLevel::Debug; + } + if args.logging.trace { + settingsrw.logging.terminal.enabled = true; + settingsrw.logging.terminal.level = LogLevel::Trace; + } + if args.otlp.is_some() { + println!("Enabling OTLP tracing"); + settingsrw.logging.otlp.enabled = true; + settingsrw.logging.otlp.grpc_endpoint = NamedSocketAddrs::from_str( + args.otlp.expect("should not be null because of default missing value").as_str(), + ) + .wrap_err("failed to parse OTLP address")?; + settingsrw.logging.otlp.level = LogLevel::Trace; + } + if args.no_attach { + settingsrw.auto_attach = false; + } + if args.delete_protected_store { + settingsrw.core.protected_store.delete = true; + } + if args.delete_block_store { + settingsrw.core.block_store.delete = true; + } + if args.delete_table_store { + settingsrw.core.table_store.delete = true; + } + if let Some(password) = args.password { + settingsrw.core.protected_store.device_encryption_key_password = password; + } + if let Some(new_password) = args.new_password { + settingsrw.core.protected_store.new_device_encryption_key_password = Some(new_password); + } + if let Some(network_key) = args.network_key { + settingsrw.core.network.network_key_password = Some(network_key); + } + if args.dump_txt_record { + // Turn off terminal logging so we can be interactive + settingsrw.logging.terminal.enabled = false; + } + let mut node_id_set = false; + if let Some(key_set) = args.set_node_id { + node_id_set = true; + // Turn off terminal logging so we can be interactive + settingsrw.logging.terminal.enabled = false; + + // Split or get secret + let tks = + TypedKeyGroup::from_str(&key_set).wrap_err("failed to decode node id set from command line")?; + + let buffer = rpassword::prompt_password("Enter secret key set (will not echo): ") + .wrap_err("invalid secret key")?; + let buffer = buffer.trim().to_string(); + let tss = TypedSecretGroup::from_str(&buffer).wrap_err("failed to decode secret set")?; + + settingsrw.core.network.routing_table.node_id = Some(tks); + settingsrw.core.network.routing_table.node_id_secret = Some(tss); + } + + if let Some(bootstrap) = args.bootstrap { + println!("Overriding bootstrap list with: "); + let mut bootstrap_list: Vec = Vec::new(); + for x in bootstrap.split(',') { + let x = x.trim().to_string(); + if !x.is_empty() { + println!(" {}", x); + bootstrap_list.push(x); + } + } + settingsrw.core.network.routing_table.bootstrap = bootstrap_list; + }; + + #[cfg(feature = "rt-tokio")] + if args.console { + settingsrw.logging.console.enabled = true; + } + + drop(settingsrw); + + // Set specific config settings + for set_config in args.set_config { + if let Some((k, v)) = set_config.split_once('=') { + let k = k.trim(); + let v = v.trim(); + settings.set(k, v)?; + } + } + + // Apply subnode index if we're testing + settings + .apply_subnode_index() + .wrap_err("failed to apply subnode index")?; // --- Dump Config --- - if matches.occurrences_of("dump-config") != 0 { + if args.dump_config { return serde_yaml::to_writer(std::io::stdout(), &*settings.read()) .wrap_err("failed to write yaml"); } // --- Generate DHT Key --- - if matches.occurrences_of("generate-key-pair") != 0 { - if let Some(ckstr) = matches.get_one::("generate-key-pair") { - if ckstr == "" { - let mut tks = veilid_core::TypedKeyGroup::new(); - let mut tss = veilid_core::TypedSecretGroup::new(); - for ck in veilid_core::VALID_CRYPTO_KINDS { - let tkp = veilid_core::Crypto::generate_keypair(ck) - .wrap_err("invalid crypto kind")?; - tks.add(veilid_core::TypedKey::new(tkp.kind, tkp.value.key)); - tss.add(veilid_core::TypedSecret::new(tkp.kind, tkp.value.secret)); - } - println!( - "Public Keys:\n{}\nSecret Keys:\n{}\n", - tks.to_string(), - tss.to_string() - ); - } else { - let ck: veilid_core::CryptoKind = - veilid_core::FourCC::from_str(ckstr).wrap_err("couldn't parse crypto kind")?; - let tkp = - veilid_core::Crypto::generate_keypair(ck).wrap_err("invalid crypto kind")?; - println!("{}", tkp.to_string()); + if let Some(ckstr) = args.generate_key_pair { + if ckstr == "" { + let mut tks = veilid_core::TypedKeyGroup::new(); + let mut tss = veilid_core::TypedSecretGroup::new(); + for ck in veilid_core::VALID_CRYPTO_KINDS { + let tkp = veilid_core::Crypto::generate_keypair(ck) + .wrap_err("invalid crypto kind")?; + tks.add(veilid_core::TypedKey::new(tkp.kind, tkp.value.key)); + tss.add(veilid_core::TypedSecret::new(tkp.kind, tkp.value.secret)); } - return Ok(()); + println!( + "Public Keys:\n{}\nSecret Keys:\n{}\n", + tks.to_string(), + tss.to_string() + ); } else { - bail!("missing crypto kind"); + let ck: veilid_core::CryptoKind = + veilid_core::FourCC::from_str(&ckstr).wrap_err("couldn't parse crypto kind")?; + let tkp = + veilid_core::Crypto::generate_keypair(ck).wrap_err("invalid crypto kind")?; + println!("{}", tkp.to_string()); } + return Ok(()); } + // -- Emit JSON-Schema -- - if matches.occurrences_of("emit-schema") != 0 { - if let Some(esstr) = matches.value_of("emit-schema") { - let mut schemas = HashMap::::new(); - veilid_core::json_api::emit_schemas(&mut schemas); + if let Some(esstr) = args.emit_schema { + let mut schemas = HashMap::::new(); + veilid_core::json_api::emit_schemas(&mut schemas); - if let Some(schema) = schemas.get(esstr) { - println!("{}", schema); - } else { - println!("Valid schemas:"); - for s in schemas.keys() { - println!(" {}", s); - } + if let Some(schema) = schemas.get(&esstr) { + println!("{}", schema); + } else { + println!("Valid schemas:"); + for s in schemas.keys() { + println!(" {}", s); } - - return Ok(()); } + + return Ok(()); } // See if we're just running a quick command - let (server_mode, success, failure) = if matches.occurrences_of("set-node-id") != 0 { + let (server_mode, success, failure) = if node_id_set { ( ServerMode::ShutdownImmediate, "Node Id and Secret set successfully", "Failed to set Node Id and Secret", ) - } else if matches.occurrences_of("dump-txt-record") != 0 { + } else if args.dump_txt_record { (ServerMode::DumpTXTRecord, "", "Failed to dump txt record") } else { (ServerMode::Normal, "", "") @@ -118,9 +372,9 @@ fn main() -> EyreResult<()> { if settings.read().daemon.enabled { cfg_if! { if #[cfg(windows)] { - return windows::run_service(settings, matches); + return windows::run_service(settings, svc_args); } else if #[cfg(unix)] { - return unix::run_daemon(settings, matches); + return unix::run_daemon(settings, svc_args); } } } @@ -138,7 +392,7 @@ fn main() -> EyreResult<()> { std::process::exit(1); })); - let panic_on_shutdown = matches.occurrences_of("panic") != 0; + let panic_on_shutdown = args.panic; ctrlc::set_handler(move || { if panic_on_shutdown { panic!("panic requested"); diff --git a/veilid-server/src/settings.rs b/veilid-server/src/settings.rs index 631e405a..498882fd 100644 --- a/veilid-server/src/settings.rs +++ b/veilid-server/src/settings.rs @@ -1,5 +1,6 @@ #![allow(clippy::bool_assert_comparison)] +use clap::ValueEnum; use directories::*; use crate::tools::*; @@ -229,7 +230,7 @@ pub fn load_config(cfg: config::Config, config_file: &Path) -> EyreResult EyreResult<()> { +pub fn run_daemon(settings: Settings, _args: CmdlineArgs) -> EyreResult<()> { let daemon = { let mut daemon = daemonize::Daemonize::new(); let s = settings.read(); diff --git a/veilid-server/src/windows.rs b/veilid-server/src/windows.rs index 405d5916..0b9718a1 100644 --- a/veilid-server/src/windows.rs +++ b/veilid-server/src/windows.rs @@ -1,6 +1,5 @@ use crate::settings::*; use crate::*; -use clap::ArgMatches; use std::ffi::OsString; use std::time::Duration; use tracing::*; @@ -12,7 +11,7 @@ use windows_service::*; // Register generated `ffi_service_main` with the system and start the service, blocking // this thread until the service is stopped. -pub fn run_service(settings: Settings, matches: ArgMatches) -> EyreResult<()> { +pub fn run_service(settings: Settings, _args: CmdlineArgs) -> EyreResult<()> { eprintln!("Windows Service mode not implemented yet."); //service_dispatcher::start("veilid-server", ffi_veilid_service_main)?;