feat(fifa17): cut over FUT economy authority to Rust
The economy authority barrier. `handle_with_ip` now dispatches every economy-touching route to Rust/Core via `try_handle_economy` BEFORE consulting `classify()`, so a migrated route can never also reach the Python passthrough (NEVER BOTH). With economy services wired (production `from_config`) an economy route ALWAYS returns Some — fail-closed 503 on any Core error — so there is no Python economy fallback. `userMassInfo` stays a hybrid by design: Python supplies the non-economy envelope; Rust overlays BOTH the squad and the economy fields (coins + unopened-pack count from Core), so no stale Python economy value is visible. Routing only — no handler/test changes buried here. Routes now Rust-owned: /user/credits, /store/purchasegroup, /store/transaction, POST+GET /purchased, PUT /item, item DELETE forms, /match (ut/delete), /auctionhouse, /tradePile, /trade, ut/delete trade; plus the userMassInfo economy overlay.
This commit is contained in:
@@ -2084,6 +2084,21 @@ impl Server {
|
||||
client_ip: Option<&str>,
|
||||
) -> WireResponse {
|
||||
let path = target.split('?').next().unwrap_or(target);
|
||||
// ─────────────────────── Economy authority barrier ───────────────────
|
||||
// Every economy-touching route is owned by Rust/Core. Classified and
|
||||
// dispatched HERE, before `classify()`, so a migrated route can NEVER also
|
||||
// reach the Python passthrough (NEVER BOTH). When the economy services are
|
||||
// wired (production `from_config`), an economy route ALWAYS returns `Some`
|
||||
// — fail-closed (503) on any Core error — so there is no Python economy
|
||||
// fallback. `None` means "not an economy route" (or no economy wired, i.e.
|
||||
// a bare test server), which falls through to the classifier below.
|
||||
if let Some(resp) = self.try_handle_economy(method, target, headers, body, client_ip) {
|
||||
eprintln!(
|
||||
"utas-host owner=RUST route=economy method={} path={} status={}",
|
||||
method, path, resp.status
|
||||
);
|
||||
return resp;
|
||||
}
|
||||
match classify(method, path) {
|
||||
Route::Club => {
|
||||
let query = target.split_once('?').map(|(_, q)| q).unwrap_or("");
|
||||
@@ -2128,11 +2143,31 @@ impl Server {
|
||||
}
|
||||
Route::UserMassInfo => {
|
||||
let deps = self.squad_deps();
|
||||
let (resp, log) =
|
||||
let (mut resp, log) =
|
||||
handle_user_mass_info(method, target, headers, body, &deps, self.pass.as_ref());
|
||||
// Overlay the authoritative Core economy (coins + unopened-pack
|
||||
// count) so NO stale Python economy value is visible post-barrier.
|
||||
// userMassInfo remains a hybrid by design: Python supplies the
|
||||
// non-economy envelope; Rust owns the squad AND the economy fields.
|
||||
let mut econ_overlaid = false;
|
||||
if let Some(svc) = &self.economy {
|
||||
if (200..300).contains(&resp.status) {
|
||||
if let (Ok(coins), Ok(ents)) = (svc.econ.balance(), svc.econ.entitlements())
|
||||
{
|
||||
if let Ok(mut root) = serde_json::from_slice::<Value>(&resp.body) {
|
||||
if overlay_massinfo_economy(&mut root, coins, ents.len()) {
|
||||
if let Ok(nb) = serde_json::to_vec(&root) {
|
||||
set_json_body(&mut resp, nb);
|
||||
econ_overlaid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!(
|
||||
"utas-host owner=RUST_OVERLAY route=userMassInfo status={} squad_outcome={} detail=[{}]",
|
||||
resp.status, log.outcome, log.detail
|
||||
"utas-host owner=RUST_OVERLAY route=userMassInfo status={} squad_outcome={} econ_overlaid={} detail=[{}]",
|
||||
resp.status, log.outcome, econ_overlaid, log.detail
|
||||
);
|
||||
resp
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user