use anyhow::Context; use minecraft_log_viewer::{ auth::{client_ip::ClientIpPolicy, whitelist::Whitelist, AuthorizationService}, config::Config, http::{self, AppState}, logs::{ follower, index::{HistoryIndex, HistoryStore}, }, }; use std::sync::{atomic::AtomicUsize, Arc}; use tokio::sync::broadcast; #[tokio::main] async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt() .json() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .init(); let config = Arc::new(Config::from_env().context("configuration validation failed")?); config .validate_paths() .context("filesystem validation failed")?; let whitelist = Whitelist::load(&config.whitelist) .context("initial whitelist load failed; refusing to start")?; let auth = AuthorizationService::new(config.latest_log.clone(), whitelist); auth.rebuild() .await .context("authorization reconstruction failed")?; let index = HistoryIndex::scan(&config.log_dir).context("historical index scan failed")?; let history = HistoryStore::new( index, config.archive_cache_max_bytes, config.archive_cache_max_files, config.max_archive_bytes, config.redact_player_ips, ); let (tx, _) = broadcast::channel(config.ws_queue_capacity); let ip_policy = ClientIpPolicy { trust_proxy: config.trust_proxy, trusted_proxies: config.trusted_proxy_cidrs.clone(), header: config.client_ip_header.clone(), }; let state = AppState { config: config.clone(), auth: auth.clone(), history: history.clone(), live_tx: tx.clone(), ip_policy, ws_count: Arc::new(AtomicUsize::new(0)), }; let _watcher = follower::spawn_watcher( config.log_dir.clone(), config.latest_log.clone(), config.whitelist.clone(), auth, history, tx, config.redact_player_ips, ) .context("filesystem watcher startup failed")?; let listener = tokio::net::TcpListener::bind(config.listen_addr) .await .context("HTTP bind failed")?; let ip_whitelist_file = config .ip_whitelist_file .as_deref() .map(|path| path.display().to_string()) .unwrap_or_else(|| "disabled".into()); tracing::info!( event = "application_startup", listen_addr = %config.listen_addr, trust_proxy = config.trust_proxy, ip_whitelist_file ); axum::serve( listener, http::router(state).into_make_service_with_connect_info::(), ) .await .context("HTTP server failed")?; Ok(()) }