use std::{ collections::HashMap, process::ExitCode, sync::{LazyLock, OnceLock}, }; use axum::{routing::get, Router}; use config::{DispatchConfig, ResVersionConfig}; use tokio::net::TcpListener; use tracing::error; use trigger_sv::{ config::{ServerEnvironmentConfiguration, TomlConfig}, die, logging, print_banner, }; mod config; mod data; mod ping; mod query_dispatch; mod query_gateway; const CONFIG_FILE: &str = "dispatch.toml"; const RES_CONFIG_FILE: &str = "res_versions.toml"; struct AppState { pub config: &'static DispatchConfig, pub environment: &'static ServerEnvironmentConfiguration, pub res_versions: HashMap, } #[tokio::main] async fn main() -> ExitCode { static APP_STATE: OnceLock = OnceLock::new(); static ENVIRONMENT: LazyLock = LazyLock::new(|| { ServerEnvironmentConfiguration::load_from_toml("environment.toml").unwrap_or_else(|err| { error!("{err}"); die(); }) }); static CONFIG: LazyLock = LazyLock::new(|| DispatchConfig::load_or_create(CONFIG_FILE)); print_banner(); logging::init_tracing(tracing::Level::DEBUG); let res_versions = ResVersionConfig::load_version_map_from_file(RES_CONFIG_FILE) .unwrap_or_else(|err| { error!("failed to load {RES_CONFIG_FILE}: {err}"); die(); }); let state = APP_STATE.get_or_init(|| AppState { config: &CONFIG, environment: &ENVIRONMENT, res_versions, }); let app = Router::new() .route(ping::ROUTE_ENDPOINT, get(ping::process)) .route(query_dispatch::ROUTE_ENDPOINT, get(query_dispatch::process)) .route(query_gateway::ROUTE_ENDPOINT, get(query_gateway::process)) .with_state(state); let listener = TcpListener::bind(CONFIG.network.http_addr).await.unwrap_or_else(|err| { error!("TcpListener::bind failed. Is another instance of the server already running? Error: {err}"); die(); }); axum::serve(listener, app).await.unwrap_or_else(|err| { error!("axum::serve failed: {err}"); die(); }); ExitCode::SUCCESS }