use anyhow::Result; use sqlx::postgres::PgPoolOptions; use std::sync::Arc; use tower_http::cors::{Any, CorsLayer}; use tower_http::services::ServeDir; use tower_http::trace::TraceLayer; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod api; mod auth_middleware; mod db; mod presence; mod relay; mod signaling; mod state; pub use state::AppState; #[tokio::main] async fn main() -> Result<()> { dotenvy::dotenv().ok(); tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new( std::env::var("RUST_LOG").unwrap_or_else(|_| "funmc_server=debug,tower_http=info".into()), )) .with(tracing_subscriber::fmt::layer()) .init(); let database_url = std::env::var("DATABASE_URL") .unwrap_or_else(|_| "postgres://postgres:password@localhost/funmc".into()); let pool = PgPoolOptions::new() .max_connections(10) .connect(&database_url) .await?; sqlx::migrate!("./migrations").run(&pool).await?; let jwt_secret = std::env::var("JWT_SECRET") .unwrap_or_else(|_| "dev-secret-change-in-production".into()); let state = Arc::new(AppState::new(pool, jwt_secret.clone())); // Start QUIC relay server in background let jwt_for_relay = jwt_secret.clone(); tokio::spawn(async move { if let Err(e) = relay::server::RelayServer::start(jwt_for_relay).await { tracing::error!("QUIC relay server error: {}", e); } }); let cors = CorsLayer::new() .allow_origin(Any) .allow_methods(Any) .allow_headers(Any); // Admin panel static files (default to dist directory for production) let admin_dir = std::env::var("ADMIN_PANEL_DIR").unwrap_or_else(|_| "./admin-panel/dist".into()); let app = axum::Router::new() .nest("/api/v1", api::router(state.clone())) .nest("/download", api::download_router()) .nest_service("/admin", ServeDir::new(&admin_dir).append_index_html_on_directories(true)) .layer(TraceLayer::new_for_http()) .layer(cors) .with_state(state); let addr = std::env::var("LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0:3000".into()); tracing::info!("HTTP API listening on {}", addr); tracing::info!("Admin panel at http://{}/admin", addr); tracing::info!("Download page at http://{}/download", addr); tracing::info!("QUIC relay listening on port 3001"); let listener = tokio::net::TcpListener::bind(&addr).await?; axum::serve(listener, app).await?; Ok(()) }