use std::net::SocketAddr; use tower_http::cors::{Any, CorsLayer}; use tower_http::trace::TraceLayer; use tracing::info; mod errors; mod extractors; mod factory; mod handlers; mod mappers; mod openapi; mod routes; mod state; #[tokio::main] async fn main() -> anyhow::Result<()> { let _ = dotenvy::dotenv(); tracing_subscriber::fmt() .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "info".into()), ) .init(); let config = infra_wiring::Config::from_env() .map_err(|e| anyhow::anyhow!("Config error: {}", e))?; let host = config.host.clone(); let port = config.port; let cors_origins = config.cors_origins.clone(); info!("Starting k-tv server on {}:{}", host, port); let app_state = factory::build_app_state(config).await?; let cors = if cors_origins.iter().any(|o| o == "*") { CorsLayer::new() .allow_origin(Any) .allow_methods(Any) .allow_headers(Any) } else { let origins: Vec<_> = cors_origins .iter() .filter_map(|o| o.parse().ok()) .collect(); CorsLayer::new() .allow_origin(origins) .allow_methods(Any) .allow_headers(Any) }; let app = axum::Router::new() .nest("/api/v1", routes::api_v1_router()) .nest("/api", routes::docs_router()) .layer(cors) .layer(TraceLayer::new_for_http()) .with_state(app_state); let addr: SocketAddr = format!("{}:{}", host, port).parse()?; let listener = tokio::net::TcpListener::bind(addr).await?; info!("Listening on {}", addr); axum::serve(listener, app).await?; Ok(()) }