use config::{Config as ConfigLoader, File}; use serde::Deserialize; use std::net::SocketAddr; #[derive(Debug, Deserialize, Clone)] pub struct AppConfig { pub server: ServerConfig, pub database: DatabaseConfig, pub storage: StorageConfig, pub auth: AuthConfig, pub log_level: String, } #[derive(Debug, Deserialize, Clone)] pub struct ServerConfig { pub host: String, pub port: u16, } #[derive(Debug, Deserialize, Clone)] pub struct DatabaseConfig { pub path: String, } #[derive(Debug, Deserialize, Clone)] pub struct StorageConfig { pub provider: String, pub do_spaces_endpoint: Option, pub do_spaces_bucket: Option, pub do_spaces_access_key: Option, pub do_spaces_secret_key: Option, } #[derive(Debug, Deserialize, Clone)] pub struct AuthConfig { pub jwt_secret: String, pub itchio_client_id: String, pub itchio_oauth_url: String, } impl AppConfig { pub fn load() -> anyhow::Result { let config = ConfigLoader::builder() .add_source(File::with_name("config").required(false)) .add_source(File::with_name("/etc/scratchback/config").required(false)) .add_source(config::Environment::default()) .build()?; let mut app_config: AppConfig = config.try_deserialize()?; if let Ok(server_host) = std::env::var("SCRATCHBACK_HOST") { app_config.server.host = server_host; } if let Ok(server_port) = std::env::var("SCRATCHBACK_PORT") { if let Ok(port) = server_port.parse() { app_config.server.port = port; } } Ok(app_config) } pub fn server_addr(&self) -> SocketAddr { format!("{}:{}", self.server.host, self.server.port) .parse() .unwrap_or_else(|_| SocketAddr::from(([0, 0, 0, 0], 3000))) } } impl Default for AppConfig { fn default() -> Self { Self { server: ServerConfig { host: "0.0.0.0".to_string(), port: 3000, }, database: DatabaseConfig { path: "/var/data/scratchback/scratchback.db".to_string(), }, storage: StorageConfig { provider: "local".to_string(), do_spaces_endpoint: None, do_spaces_bucket: None, do_spaces_access_key: None, do_spaces_secret_key: None, }, auth: AuthConfig { jwt_secret: "dev-secret-change-in-production".to_string(), itchio_client_id: "".to_string(), itchio_oauth_url: "https://itch.io/user/oauth".to_string(), }, log_level: "info".to_string(), } } } impl std::fmt::Display for AppConfig { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}:{} (db: {}, storage: {})", self.server.host, self.server.port, self.database.path, self.storage.provider ) } }