use std::path::PathBuf;
use http_smtp_rele::{api, config, logging, security, AppState};
const DEFAULT_CONFIG_PATH: &str = "/etc/http-smtp-rele.toml";
#[tokio::main]
async fn main() {
let config_path = parse_config_path();
if let Err(e) = security::apply_initial_restrictions(&config_path) {
eprintln!("fatal: security restriction failed: {}", e);
std::process::exit(1);
}
let config = config::load(&config_path).unwrap_or_else(|e| {
eprintln!("fatal: {}", e);
std::process::exit(1);
});
logging::init_logging(&config.logging);
let state = AppState::new(config.clone());
let bind_addr = config.server.bind_address.clone();
let listener = tokio::net::TcpListener::bind(&bind_addr)
.await
.unwrap_or_else(|e| {
tracing::error!(address = %bind_addr, error = %e, "failed to bind");
std::process::exit(1);
});
if let Err(e) = security::apply_runtime_restrictions(security::RuntimeMode::SmtpRelay) {
tracing::error!(error = %e, "runtime security restriction failed");
std::process::exit(1);
}
tracing::info!(
version = env!("CARGO_PKG_VERSION"),
bind_address = %bind_addr,
"app.started"
);
let router = api::build_router(state);
axum::serve(listener, router).await.unwrap_or_else(|e| {
tracing::error!(error = %e, "server error");
std::process::exit(1);
});
tracing::info!("app.stopped");
}
fn parse_config_path() -> PathBuf {
let args: Vec<String> = std::env::args().collect();
let mut i = 1;
while i < args.len() {
if args[i] == "--config" {
if let Some(path) = args.get(i + 1) {
return PathBuf::from(path);
}
}
i += 1;
}
PathBuf::from(DEFAULT_CONFIG_PATH)
}