//! `kvitt-server`: parses the subcommand, sets up JSON logging and the runtime (2 worker threads, SPEC §6.3), and //! runs it. // No unwrap/expect outside tests (CLAUDE.md server rule); integration tests are separate crates and may use them. #![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))] use std::process::ExitCode; use clap::Parser; use kvitt_server::cli::{self, Cli}; use kvitt_server::config::{Config, DEFAULT_LOG_FILTER}; use tracing_subscriber::EnvFilter; /// Worker threads of the tokio runtime (SPEC §6.3). const WORKER_THREADS: usize = 2; fn main() -> ExitCode { let cli = Cli::parse(); let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(DEFAULT_LOG_FILTER)); tracing_subscriber::fmt() .json() .with_env_filter(filter) .with_current_span(true) .with_span_list(false) .with_writer(std::io::stdout) .init(); let config = match Config::from_env() { Ok(config) => config, Err(error) => { eprintln!("configuration: {}", error.message); return ExitCode::FAILURE; } }; let runtime = match tokio::runtime::Builder::new_multi_thread() .worker_threads(WORKER_THREADS) .enable_all() .build() { Ok(runtime) => runtime, Err(error) => { eprintln!("cannot start the runtime: {error}"); return ExitCode::FAILURE; } }; runtime.block_on(cli::run(cli.command, config)) }