style: rustfmt squad host + adapter files

Formatting-only. Runs the project formatter over the files authored/edited
this session (host lib+tests, adapter item/squad_ext/squad_projection/mod +
projection test). The intentionally-preserved dirty catalog.rs and
pre-existing /club-era host drift beyond these files are out of scope.
This commit is contained in:
funman300
2026-08-12 03:59:15 +00:00
parent afc909fd3b
commit c2e2e0d8f2
7 changed files with 744 additions and 177 deletions
+165 -39
View File
@@ -164,8 +164,14 @@ pub struct CoreSquadSlot {
/// when Stale — the host decides policy).
#[derive(Debug, Clone)]
pub enum CoreExtState {
Fresh { schema_version: i64, payload: String },
Stale { schema_version: i64, payload: String },
Fresh {
schema_version: i64,
payload: String,
},
Stale {
schema_version: i64,
payload: String,
},
Missing,
}
@@ -299,7 +305,11 @@ impl CoreAccess for HttpCoreClient {
}
let v: Value = resp.json().map_err(|e| CoreError::Parse(e.to_string()))?;
Ok(CoreReplaceResult {
squad_id: v.get("squad_id").and_then(|x| x.as_str()).unwrap_or("").to_string(),
squad_id: v
.get("squad_id")
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string(),
canonical_fingerprint: v
.get("canonical_fingerprint")
.and_then(|x| x.as_str())
@@ -343,8 +353,14 @@ pub fn replace_request_body(req: &CoreReplaceRequest) -> Value {
/// Parse Core's `GET /squad/ext` response into a [`CoreSquadRead`].
pub fn parse_core_squad_read(v: &Value) -> Result<CoreSquadRead, CoreError> {
let squad = v.get("squad").ok_or_else(|| CoreError::Parse("missing `squad`".into()))?;
let name = squad.get("name").and_then(|x| x.as_str()).unwrap_or("").to_string();
let squad = v
.get("squad")
.ok_or_else(|| CoreError::Parse("missing `squad`".into()))?;
let name = squad
.get("name")
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string();
let formation = squad
.get("formation")
.and_then(|x| x.as_str())
@@ -360,25 +376,56 @@ pub fn parse_core_squad_read(v: &Value) -> Result<CoreSquadRead, CoreError> {
Some(CoreSquadSlot {
owned_card_id: p.get("owned_card_id")?.as_str()?.to_string(),
index: p.get("position_index")?.as_i64()?,
is_captain: p.get("is_captain").and_then(|x| x.as_bool()).unwrap_or(false),
is_on_bench: p.get("is_on_bench").and_then(|x| x.as_bool()).unwrap_or(false),
is_captain: p
.get("is_captain")
.and_then(|x| x.as_bool())
.unwrap_or(false),
is_on_bench: p
.get("is_on_bench")
.and_then(|x| x.as_bool())
.unwrap_or(false),
})
})
.collect();
let ext_v = v.get("extension").ok_or_else(|| CoreError::Parse("missing `extension`".into()))?;
let ext_v = v
.get("extension")
.ok_or_else(|| CoreError::Parse("missing `extension`".into()))?;
let ext = match ext_v.get("state").and_then(|x| x.as_str()) {
Some("fresh") => CoreExtState::Fresh {
schema_version: ext_v.get("schema_version").and_then(|x| x.as_i64()).unwrap_or(0),
payload: ext_v.get("payload").and_then(|x| x.as_str()).unwrap_or("").to_string(),
schema_version: ext_v
.get("schema_version")
.and_then(|x| x.as_i64())
.unwrap_or(0),
payload: ext_v
.get("payload")
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string(),
},
Some("stale") => CoreExtState::Stale {
schema_version: ext_v.get("schema_version").and_then(|x| x.as_i64()).unwrap_or(0),
payload: ext_v.get("payload").and_then(|x| x.as_str()).unwrap_or("").to_string(),
schema_version: ext_v
.get("schema_version")
.and_then(|x| x.as_i64())
.unwrap_or(0),
payload: ext_v
.get("payload")
.and_then(|x| x.as_str())
.unwrap_or("")
.to_string(),
},
Some("missing") => CoreExtState::Missing,
other => return Err(CoreError::Parse(format!("unknown extension state {other:?}"))),
other => {
return Err(CoreError::Parse(format!(
"unknown extension state {other:?}"
)))
}
};
Ok(CoreSquadRead { name, formation, slots, ext })
Ok(CoreSquadRead {
name,
formation,
slots,
ext,
})
}
/// Parse Core's `/collection` response `{ "collection": [...], "total": n }` into
@@ -655,7 +702,10 @@ fn project_active_squad(deps: &SquadDeps<'_>) -> HostProjection {
Err(e) => return HostProjection::Error(e.to_string()),
};
let ext = match &read.ext {
CoreExtState::Fresh { schema_version, payload } => {
CoreExtState::Fresh {
schema_version,
payload,
} => {
match Fifa17SquadExtensionV1::from_payload(*schema_version, payload) {
Ok(e) => e,
// Fresh but the payload does not parse as our schema: corruption,
@@ -670,8 +720,10 @@ fn project_active_squad(deps: &SquadDeps<'_>) -> HostProjection {
Ok(v) => v,
Err(e) => return HostProjection::Error(e.to_string()),
};
let owned_by_id: std::collections::HashMap<String, CoreOwnedItem> =
owned.into_iter().map(|i| (i.owned_card_id.clone(), i)).collect();
let owned_by_id: std::collections::HashMap<String, CoreOwnedItem> = owned
.into_iter()
.map(|i| (i.owned_card_id.clone(), i))
.collect();
let slots: Vec<ProjectionSlot> = read
.slots
.iter()
@@ -718,7 +770,10 @@ pub fn handle_put_squad(body: &[u8], deps: &SquadDeps<'_>) -> (WireResponse, Squ
Err(e) => {
return (
error_response(400, "parse_error"),
SquadLog { outcome: "parse_error", detail: e.to_string() },
SquadLog {
outcome: "parse_error",
detail: e.to_string(),
},
)
}
};
@@ -729,13 +784,19 @@ pub fn handle_put_squad(body: &[u8], deps: &SquadDeps<'_>) -> (WireResponse, Squ
Err(SquadBuildError::UnresolvedWireIds(ids)) => {
return (
error_response(400, "unresolved_wire_ids"),
SquadLog { outcome: "unresolved_wire_ids", detail: format!("{ids:?}") },
SquadLog {
outcome: "unresolved_wire_ids",
detail: format!("{ids:?}"),
},
)
}
Err(SquadBuildError::DuplicateOwnedItem(id)) => {
return (
error_response(400, "duplicate_owned_item"),
SquadLog { outcome: "duplicate_owned_item", detail: id },
SquadLog {
outcome: "duplicate_owned_item",
detail: id,
},
)
}
};
@@ -747,7 +808,10 @@ pub fn handle_put_squad(body: &[u8], deps: &SquadDeps<'_>) -> (WireResponse, Squ
Err(e) => {
return (
error_response(502, "core_error"),
SquadLog { outcome: "core_error", detail: e.to_string() },
SquadLog {
outcome: "core_error",
detail: e.to_string(),
},
)
}
};
@@ -755,7 +819,10 @@ pub fn handle_put_squad(body: &[u8], deps: &SquadDeps<'_>) -> (WireResponse, Squ
if !owned_set.contains(&slot.owned_card_id) {
return (
error_response(403, "not_owned"),
SquadLog { outcome: "unauthorized_item", detail: slot.owned_card_id.clone() },
SquadLog {
outcome: "unauthorized_item",
detail: slot.owned_card_id.clone(),
},
);
}
}
@@ -786,11 +853,17 @@ pub fn handle_put_squad(body: &[u8], deps: &SquadDeps<'_>) -> (WireResponse, Squ
match deps.core.replace_squad(&req) {
Ok(_) => (
json_response(&save_ack(put.id)),
SquadLog { outcome: "ok", detail: String::new() },
SquadLog {
outcome: "ok",
detail: String::new(),
},
),
Err(e) => (
error_response(502, "core_error"),
SquadLog { outcome: "core_error", detail: e.to_string() },
SquadLog {
outcome: "core_error",
detail: e.to_string(),
},
),
}
}
@@ -802,19 +875,31 @@ pub fn handle_squad_list(deps: &SquadDeps<'_>) -> (WireResponse, SquadLog) {
match project_active_squad(deps) {
HostProjection::Squad(v) => (
json_response(&squad_list(&v)),
SquadLog { outcome: "ok", detail: String::new() },
SquadLog {
outcome: "ok",
detail: String::new(),
},
),
HostProjection::Stale => (
json_response(&json!({ "squad": [] })),
SquadLog { outcome: "stale_integrity", detail: "stale extension not applied".into() },
SquadLog {
outcome: "stale_integrity",
detail: "stale extension not applied".into(),
},
),
HostProjection::Missing => (
json_response(&json!({ "squad": [] })),
SquadLog { outcome: "missing_integrity", detail: "no extension stored".into() },
SquadLog {
outcome: "missing_integrity",
detail: "no extension stored".into(),
},
),
HostProjection::Error(e) => (
json_response(&json!({ "squad": [] })),
SquadLog { outcome: "core_error", detail: e },
SquadLog {
outcome: "core_error",
detail: e,
},
),
}
}
@@ -841,8 +926,10 @@ fn set_json_body(resp: &mut WireResponse, body: Vec<u8>) {
&& !k.eq_ignore_ascii_case("content-type")
&& !k.eq_ignore_ascii_case("transfer-encoding")
});
resp.headers.push(("Content-Type".to_string(), "application/json".to_string()));
resp.headers.push(("Content-Length".to_string(), body.len().to_string()));
resp.headers
.push(("Content-Type".to_string(), "application/json".to_string()));
resp.headers
.push(("Content-Length".to_string(), body.len().to_string()));
resp.body = body;
}
@@ -862,44 +949,83 @@ pub fn handle_user_mass_info(
Err(e) => {
return (
error_response(502, "upstream_unavailable"),
SquadLog { outcome: "python_unreachable", detail: e.to_string() },
SquadLog {
outcome: "python_unreachable",
detail: e.to_string(),
},
)
}
};
// Only a successful JSON object carrying `.squad` is overlaid; anything else
// is returned verbatim (we never invent a squad into an unrelated response).
if !(200..300).contains(&resp.status) {
return (resp, SquadLog { outcome: "python_non_2xx_passthrough", detail: String::new() });
return (
resp,
SquadLog {
outcome: "python_non_2xx_passthrough",
detail: String::new(),
},
);
}
let mut root: Value = match serde_json::from_slice::<Value>(&resp.body) {
Ok(v) if v.is_object() => v,
_ => return (resp, SquadLog { outcome: "python_body_unusable_passthrough", detail: String::new() }),
_ => {
return (
resp,
SquadLog {
outcome: "python_body_unusable_passthrough",
detail: String::new(),
},
)
}
};
if root.get("squad").is_none() {
return (resp, SquadLog { outcome: "python_no_squad_passthrough", detail: String::new() });
return (
resp,
SquadLog {
outcome: "python_no_squad_passthrough",
detail: String::new(),
},
);
}
// Preserve the client's persona from Python's own response.
let persona = root["squad"]
.get("personaId")
.and_then(|x| x.as_i64())
.or_else(|| root.get("userInfo").and_then(|u| u.get("personaId")).and_then(|x| x.as_i64()))
.or_else(|| {
root.get("userInfo")
.and_then(|u| u.get("personaId"))
.and_then(|x| x.as_i64())
})
.unwrap_or(0);
let (squad_val, log) = match project_active_squad(deps) {
HostProjection::Squad(v) => (
user_mass_info_squad(v, persona),
SquadLog { outcome: "ok", detail: String::new() },
SquadLog {
outcome: "ok",
detail: String::new(),
},
),
HostProjection::Stale => (
empty_squad_overlay(persona),
SquadLog { outcome: "stale_integrity", detail: "stale extension not applied".into() },
SquadLog {
outcome: "stale_integrity",
detail: "stale extension not applied".into(),
},
),
HostProjection::Missing => (
empty_squad_overlay(persona),
SquadLog { outcome: "missing_integrity", detail: "no extension stored".into() },
SquadLog {
outcome: "missing_integrity",
detail: "no extension stored".into(),
},
),
HostProjection::Error(e) => (
empty_squad_overlay(persona),
SquadLog { outcome: "core_error", detail: e },
SquadLog {
outcome: "core_error",
detail: e,
},
),
};
root["squad"] = squad_val;