Game sync and live services for independent game developers (targeting itch.io)
1use std::sync::Arc;
2
3use anyhow::Result;
4use poem::middleware::Cors;
5use poem::{EndpointExt, Route};
6use poem_openapi::OpenApiService;
7use std::net::SocketAddr;
8use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
9
10mod api;
11mod auth;
12mod config;
13mod cost;
14mod db;
15mod storage;
16mod web;
17
18use crate::auth::AuthService;
19use crate::storage::StorageProvider;
20
21#[tokio::main]
22async fn main() -> Result<()> {
23 let app_config = config::AppConfig::load()?;
24
25 tracing_subscriber::registry()
26 .with(tracing_subscriber::EnvFilter::new(
27 app_config.log_level.clone(),
28 ))
29 .with(tracing_subscriber::fmt::layer())
30 .init();
31
32 // Initialize database
33 let db_pool = db::init_database(std::path::Path::new(&app_config.database.path)).await?;
34
35 // Initialize storage
36 let storage = StorageProvider::new(&app_config.storage.provider, &app_config.storage).await?;
37
38 // Initialize auth service wrapped in Arc for sharing across endpoints
39 let auth_service = Arc::new(AuthService::new(app_config.auth.clone(), db_pool.clone()));
40
41 // Create API - tuple of endpoints
42 let api = (
43 api::games::GamesEndpoint::new(db_pool.clone()),
44 api::saves::SavesEndpoint::new(db_pool.clone(), storage, auth_service.clone()),
45 api::AuthEndpoint::new(auth_service),
46 api::cost::CostEndpoint::new(db_pool.clone()),
47 );
48
49 // Initialize OpenAPI service
50 let api_service = OpenApiService::new(api, "Scratchback API", "1.0")
51 .server(format!("http://{}/api", app_config.server_addr()));
52
53 let app = Route::new()
54 .nest("/api", api_service)
55 .at("/", web::StaticAssets::new())
56 .at("/*", web::StaticAssets::new())
57 .with(Cors::new());
58
59 let addr: SocketAddr = app_config.server_addr();
60 tracing::info!("Starting server on {}", addr);
61
62 poem::Server::new(poem::listener::TcpListener::bind(addr))
63 .run(app)
64 .await?;
65
66 Ok(())
67}