use anyhow::Result; use std::path::PathBuf; #[derive(Debug, Clone)] pub struct Config { pub listen_addr: String, pub database_url: String, pub data_dir: String, pub max_connections: u32, /// Games whose opt-in development content pack (`data/games//dev/`) is /// loaded IN ADDITION to the default `data/cards` catalog. Empty by default — /// default/test content is never affected unless a game is named here. pub dev_content_games: Vec, /// Explicit PRODUCTION content pack file paths (each a `CardDefinition[]` /// JSON), loaded IN ADDITION to `data/cards` and any dev pack. This is the /// production real-profile content path — deliberately NOT gated behind the /// dev-only `dev_content_games`. pub content_packs: Vec, } impl Config { pub fn from_env() -> Result { Ok(Self { listen_addr: std::env::var("LISTEN_ADDR").unwrap_or_else(|_| "127.0.0.1:8080".into()), database_url: std::env::var("DATABASE_URL") .unwrap_or_else(|_| "sqlite://openfut.db".into()), data_dir: std::env::var("DATA_DIR").unwrap_or_else(|_| "data".into()), max_connections: std::env::var("DB_MAX_CONNECTIONS") .ok() .and_then(|v| v.parse().ok()) .unwrap_or(5), dev_content_games: std::env::var("OPENFUT_DEV_CONTENT_GAMES") .ok() .map(|v| { v.split(',') .map(str::trim) .filter(|s| !s.is_empty()) .map(String::from) .collect() }) .unwrap_or_default(), content_packs: std::env::var("OPENFUT_CONTENT_PACKS") .ok() .map(|v| { v.split(',') .map(str::trim) .filter(|s| !s.is_empty()) .map(PathBuf::from) .collect() }) .unwrap_or_default(), }) } }