use std::sync::Arc; use anyhow::Result; use poem::middleware::Cors; use poem::{EndpointExt, Route}; use poem_openapi::OpenApiService; use std::net::SocketAddr; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod api; mod auth; mod config; mod cost; mod db; mod storage; mod web; use crate::auth::AuthService; use crate::storage::StorageProvider; #[tokio::main] async fn main() -> Result<()> { let app_config = config::AppConfig::load()?; tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new( app_config.log_level.clone(), )) .with(tracing_subscriber::fmt::layer()) .init(); // Initialize database let db_pool = db::init_database(std::path::Path::new(&app_config.database.path)).await?; // Initialize storage let storage = StorageProvider::new(&app_config.storage.provider, &app_config.storage).await?; // Initialize auth service wrapped in Arc for sharing across endpoints let auth_service = Arc::new(AuthService::new(app_config.auth.clone(), db_pool.clone())); // Create API - tuple of endpoints let api = ( api::games::GamesEndpoint::new(db_pool.clone()), api::saves::SavesEndpoint::new(db_pool.clone(), storage, auth_service.clone()), api::AuthEndpoint::new(auth_service), api::cost::CostEndpoint::new(db_pool.clone()), ); // Initialize OpenAPI service let api_service = OpenApiService::new(api, "Scratchback API", "1.0") .server(format!("http://{}/api", app_config.server_addr())); let app = Route::new() .nest("/api", api_service) .at("/", web::StaticAssets::new()) .at("/*", web::StaticAssets::new()) .with(Cors::new()); let addr: SocketAddr = app_config.server_addr(); tracing::info!("Starting server on {}", addr); poem::Server::new(poem::listener::TcpListener::bind(addr)) .run(app) .await?; Ok(()) }