109 lines
3.5 KiB
Rust
109 lines
3.5 KiB
Rust
use clap::Parser;
|
|
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
|
|
|
|
use nx9_auth::{
|
|
cli::{self, Cli, Commands},
|
|
config::Config,
|
|
runtime::{Application, Lifecycle},
|
|
};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
// Parse CLI arguments first (before any logging so --help works cleanly)
|
|
let cli = Cli::parse();
|
|
|
|
// Initialize logging based on the command and verbosity
|
|
let is_serve = matches!(cli.command, Commands::Serve);
|
|
if is_serve {
|
|
// Structured JSON logging for production server deployment
|
|
tracing_subscriber::registry()
|
|
.with(
|
|
EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| "nx9_auth=info,tower_http=info".parse().unwrap()),
|
|
)
|
|
.with(fmt::layer().json())
|
|
.init();
|
|
} else if cli.verbose {
|
|
// Human-readable compact logging for verbosity in subcommands
|
|
tracing_subscriber::registry()
|
|
.with(
|
|
EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| "nx9_auth=debug".parse().unwrap()),
|
|
)
|
|
.with(fmt::layer().compact())
|
|
.init();
|
|
} else {
|
|
// Silence info/debug logging for clean operator CLI commands
|
|
tracing_subscriber::registry()
|
|
.with(
|
|
EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| "nx9_auth=warn".parse().unwrap()),
|
|
)
|
|
.with(fmt::layer().compact())
|
|
.init();
|
|
}
|
|
|
|
// Load configuration
|
|
let config_opt = if matches!(
|
|
cli.command,
|
|
Commands::Init { .. } | Commands::ConfigPath { .. }
|
|
) {
|
|
// For init/config-path commands, a missing override config is fine
|
|
if let Some(ref path) = cli.config {
|
|
if path.exists() {
|
|
Some(Config::load(path)?)
|
|
} else {
|
|
let mut cfg = Config {
|
|
config_path: Some(path.clone()),
|
|
..Default::default()
|
|
};
|
|
cfg.resolve_paths();
|
|
Some(cfg)
|
|
}
|
|
} else {
|
|
Config::find_and_load(None)?
|
|
}
|
|
} else {
|
|
Config::find_and_load(cli.config.as_deref())?
|
|
};
|
|
|
|
let config = match config_opt {
|
|
Some(cfg) => cfg,
|
|
None => {
|
|
// init and config-path are allowed to run without an existing config file.
|
|
// We use default Config structure for them.
|
|
if matches!(
|
|
cli.command,
|
|
Commands::Init { .. } | Commands::ConfigPath { .. }
|
|
) {
|
|
let mut cfg = Config::default();
|
|
cfg.resolve_paths();
|
|
cfg
|
|
} else {
|
|
eprintln!(
|
|
"\nError: No configuration found.\n\nRun:\n\n nx9-auth init\n\nOr if running in Docker:\n\n docker exec -it nx9-auth nx9-auth init\n"
|
|
);
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
};
|
|
|
|
tracing::info!(
|
|
version = env!("CARGO_PKG_VERSION"),
|
|
git_commit = env!("GIT_COMMIT"),
|
|
"nx9-auth starting"
|
|
);
|
|
|
|
// Dispatch to serve or CLI command
|
|
match cli.command {
|
|
Commands::Serve => run_server(config).await,
|
|
cmd => cli::run(cmd, config).await,
|
|
}
|
|
}
|
|
|
|
/// Start the HTTP server using the runtime lifecycle.
|
|
async fn run_server(config: Config) -> anyhow::Result<()> {
|
|
let mut app = Application::builder(config).build().await?;
|
|
app.start().await
|
|
}
|