use std::{fs::File, path::PathBuf}; use tower_http::services::ServeDir; use tracing::level_filters::LevelFilter; use tracing_subscriber::EnvFilter; use statsrv::{service::ServiceConfig, AppState}; #[tokio::main] async fn main() -> Result<(), Box> { let filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) .from_env_lossy(); tracing_subscriber::fmt().with_env_filter(filter).init(); let config = match Config::parse() { Ok(c) => c, Err(err) => { tracing::error!("Failed to read config file, using defaults: `{err}`"); Default::default() } }; let state = AppState::new(config.services); let mut router = statsrv::router().with_state(state); if let Some(path) = config.serve_dir { router = router.nest_service("/", ServeDir::new(path)); } router = router.layer(tower_http::trace::TraceLayer::new_for_http()); let listener = tokio::net::TcpListener::bind(config.address).await?; tracing::info!("listening on {}", listener.local_addr().unwrap()); axum::serve(listener, router).await.map_err(Into::into) } #[derive(Debug, Clone, serde::Deserialize)] #[serde(default)] pub struct Config { pub serve_dir: Option, pub address: String, pub services: Vec, } impl Config { const DEFAULT_CONFIG: &str = "/etc/statsrv.toml"; fn parse() -> Result> { let config_file = match std::env::args().nth(1) { Some(p) => File::open(&p)?, None => { tracing::debug!("Falling back to default config location"); File::open(Self::DEFAULT_CONFIG)? } }; let config_toml = std::io::read_to_string(config_file)?; toml::from_str(&config_toml).map_err(Into::into) } } impl Default for Config { fn default() -> Self { Self { serve_dir: None, address: String::from("127.0.0.1:8080"), services: Default::default(), } } }