352ad11bc4
Production real-profile content is loaded via an explicit path, NOT the dev-only OPENFUT_DEV_CONTENT_GAMES gate: - Config.content_packs from env OPENFUT_CONTENT_PACKS (comma-sep file paths). - CardDb::load_pack(path): merge an explicit CardDefinition[] production pack. - app::build loads dev packs then production packs. Preflight (app::build, always on): every owned_cards.card_id MUST resolve to a loaded CardDefinition. A real profile with owned players but even ONE missing definition fails LOUDLY instead of silently serving an empty /collection; an empty owned_cards table (fresh DB / tests) passes. 2 preflight integration tests (missing def fails, loaded def passes). clippy -D warnings clean; full suite 151 tests green.
55 lines
2.1 KiB
Rust
55 lines
2.1 KiB
Rust
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/<game>/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<String>,
|
|
/// 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<PathBuf>,
|
|
}
|
|
|
|
impl Config {
|
|
pub fn from_env() -> Result<Self> {
|
|
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(),
|
|
})
|
|
}
|
|
}
|