feat(utas): FIFA17 UTAS migration host + /club adapter mappings
openfut-utas-host: the first live UTAS host. Serves GET /ut/game/<title>/club from OpenFUT Core via the FIFA17 adapter and reverse-proxies every other UTAS route verbatim to the Python oracle. Plaintext HTTP/1.1 keep-alive (no TLS); route classification before execution; a Core error on /club degrades to an empty page and never falls back to Python. CoreAccess is a host-owned boundary (the adapter stays transport-agnostic). openfut-adapter-fifa17::fut: owned_query (wire parse + FIFA id->name mapping, unknown id = hard error), entities (id<->name from committed tables), and club_response (FIFA _item shaping; drops items lacking a real FIFA asset id, never fabricates one). openfut-core submodule advanced to the reconciled trunk (6acae54 = 8c8a4116 multi-game + eab522a replace_squad/SquadRules + the /club semantic query). 11 host tests + adapter fut tests; 10/10 host mutations killed. rare=SP UNKNOWN. Retail rendering of Core inventory still blocked on the Core-card->asset-id identity decision (next phase).
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
//! Environment → [`HostConfig`]. Client-visible bind and the Python upstream are
|
||||
//! REQUIRED with no default (host-family discipline: a defaulted port could
|
||||
//! collide with the live oracle). `core_url` defaults to Bridge's convention.
|
||||
|
||||
use std::env;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HostConfig {
|
||||
/// Where this host listens (the address FIFA reaches for UTAS). Required.
|
||||
pub listen_addr: String,
|
||||
/// Base URL of the Python UTAS oracle for fallback, e.g.
|
||||
/// `http://127.0.0.1:8199`. Required — must NOT be this host's own address.
|
||||
pub python_upstream: String,
|
||||
/// OpenFUT Core base URL. Default `http://127.0.0.1:8080` (Bridge convention).
|
||||
pub core_url: String,
|
||||
/// Directory holding `leagues.json`/`nations.json`/`teams.json`.
|
||||
pub tables_dir: String,
|
||||
/// Optional JSON file mapping Core card id → FIFA asset id. Absent = the
|
||||
/// current reality (no mapping) → Core items cannot render and are dropped.
|
||||
pub asset_map_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConfigError(pub String);
|
||||
|
||||
impl std::fmt::Display for ConfigError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ConfigError {}
|
||||
|
||||
fn required(key: &str) -> Result<String, ConfigError> {
|
||||
match env::var(key) {
|
||||
Ok(v) if !v.is_empty() => Ok(v),
|
||||
_ => Err(ConfigError(format!("{key} is required (no default)"))),
|
||||
}
|
||||
}
|
||||
|
||||
impl HostConfig {
|
||||
pub fn from_env() -> Result<Self, ConfigError> {
|
||||
Ok(HostConfig {
|
||||
listen_addr: required("OPENFUT_UTAS_HOST_ADDR")?,
|
||||
python_upstream: required("OPENFUT_UTAS_PYTHON_URL")?,
|
||||
core_url: env::var("OPENFUT_CORE_URL")
|
||||
.unwrap_or_else(|_| "http://127.0.0.1:8080".into()),
|
||||
tables_dir: env::var("OPENFUT_FIFA17_TABLES_DIR")
|
||||
.unwrap_or_else(|_| "fifa17-recon/data/tables".into()),
|
||||
asset_map_path: env::var("OPENFUT_FIFA17_ASSET_MAP")
|
||||
.ok()
|
||||
.filter(|s| !s.is_empty()),
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user