crabidy/crabidy-server/src/main.rs

77 lines
2.5 KiB
Rust

//! The standalone server binary: stderr tracing plus
//! [`crabidy_server::serve`] on the fixed listen address. The whole stack
//! lives in the library so the bundled `cbd` binary can host it too
//! (architecture/cbd-bundle.md D1).
use clap::Parser;
use tracing_subscriber::{prelude::*, EnvFilter};
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
#[command(subcommand)]
command: Option<Command>,
}
#[derive(clap::Subcommand)]
enum Command {
/// Hash a password for the `[auth]` section of crabidy-server.toml
/// (architecture/roles-auth.md). Reads the password as one line
/// from stdin and prints the PHC string — nothing else, so output
/// can be piped. The password itself is never printed or logged.
HashPassword,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let cli = Cli::parse();
if let Some(Command::HashPassword) = cli.command {
return hash_password();
}
let _log_guard = init_tracing();
crabidy_server::serve(crabidy_server::LISTEN_ADDR.parse()?).await?;
Ok(())
}
/// Reads one line from stdin and prints its argon2 PHC hash.
fn hash_password() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut password = String::new();
std::io::stdin().read_line(&mut password)?;
let password = password.trim_end_matches(['\r', '\n']);
if password.is_empty() {
return Err("empty password".into());
}
println!("{}", crabidy_server::auth::hash_password(password)?);
Ok(())
}
/// Installs the global tracing subscriber.
///
/// The filter honors `RUST_LOG`; without it, our own crates log at debug and
/// everything else at info. Returns the guard that flushes the non-blocking
/// writer on shutdown.
fn init_tracing() -> tracing_appender::non_blocking::WorkerGuard {
let (non_blocking, guard) = tracing_appender::non_blocking(std::io::stderr());
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new(
"info,crabidy_server=debug,crabidy_core=debug,tidaldy=debug,ytdy=debug,audio_player=debug",
)
});
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(non_blocking)
.with_target(true)
.with_file(true)
.with_line_number(true);
// .init() also installs the log-to-tracing bridge for libraries that
// use the `log` crate (symphonia, cpal, ...).
tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.init();
guard
}