fifa17-python: sync tools to running container state
The frozen baseline image predates two hot-patches made in the running container after build: * utas_server.py: FUT_MODES-gated offlineSeason block in GetHubData's club response (keeps the offline-season summary valid) * test_hub_offline_season_contract.py added to /app/tools Sync fifa17-python/tools to the running container (verified byte-identical, 237 files incl. the redir cert pair) and snapshot the live FS as openfut-fut-backend:python-running-2026-08-10 (docker commit). A fresh build from the committed sources now reproduces the running backend exactly (baked SHA256SUMS.txt diffed against the container manifest: identical).
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Regression for the FIFA 17 FUT hub offline-Seasons summary.
|
||||||
|
|
||||||
|
CardsDLL's hub parser at 0x180139610 recognizes offlineSeason (atom 0x1ec)
|
||||||
|
and passes its object to 0x18013c3a0. That nested parser recognizes the
|
||||||
|
string-valued divisionId, gamesPlayed, points, totalGames, and
|
||||||
|
progressDataVersion fields. Without offlineSeason, the Single Player Season
|
||||||
|
UI rejects the otherwise-successful GetHubData response before /season is sent.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
TOOLS = pathlib.Path(__file__).resolve().parent
|
||||||
|
sys.path.insert(0, str(TOOLS))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with tempfile.TemporaryDirectory(prefix="openfut-hub-season-test-") as state:
|
||||||
|
os.environ["FUT_PROFILE_ROOT"] = os.path.join(state, "accounts")
|
||||||
|
os.environ.pop("FUT_PROFILE", None)
|
||||||
|
os.environ["FUT_MODES"] = "1"
|
||||||
|
|
||||||
|
import utas_server
|
||||||
|
|
||||||
|
body = utas_server.hub_data()
|
||||||
|
assert isinstance(body, dict), "hub response root must be an object"
|
||||||
|
summary = body.get("offlineSeason")
|
||||||
|
assert isinstance(summary, dict), "hub.offlineSeason must be an object"
|
||||||
|
|
||||||
|
expected = {"divisionId", "gamesPlayed", "points", "totalGames",
|
||||||
|
"progressDataVersion"}
|
||||||
|
assert set(summary) == expected, repr(summary)
|
||||||
|
for key in expected:
|
||||||
|
assert isinstance(summary[key], str), "%s must be a string: %r" % (key, summary[key])
|
||||||
|
|
||||||
|
assert summary["divisionId"] == "10", repr(summary)
|
||||||
|
assert summary["gamesPlayed"] == "0", repr(summary)
|
||||||
|
assert summary["points"] == "0", repr(summary)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
print("PASS: FUT hub includes the recovered offline-Seasons summary")
|
||||||
@@ -1449,8 +1449,23 @@ def hub_data():
|
|||||||
players = len([i for i in STORE.items() if _is_player(i)])
|
players = len([i for i in STORE.items() if _is_player(i)])
|
||||||
auctions = len(STORE.listings())
|
auctions = len(STORE.listings())
|
||||||
log(" HUB: clubPlayers=%d auctionCount=%d selling=%d" % (players, auctions, auctions))
|
log(" HUB: clubPlayers=%d auctionCount=%d selling=%d" % (players, auctions, auctions))
|
||||||
return {"clubPlayers": players, "auctionCount": auctions,
|
body = {"clubPlayers": players, "auctionCount": auctions,
|
||||||
"tradePile": {"count": auctions, "selling": auctions, "sold": 0}}
|
"tradePile": {"count": auctions, "selling": auctions, "sold": 0}}
|
||||||
|
if _MODES:
|
||||||
|
# GetHubData's parser 0x180139610 recognises offlineSeason (atom 0x1ec)
|
||||||
|
# and passes it to 0x18013c3a0. The nested scalar fields are STRING
|
||||||
|
# getters, despite representing numbers. Omitting the object leaves the
|
||||||
|
# offline-season summary invalid and the UI aborts before requesting
|
||||||
|
# /season. The initial division matches season_list()/season_user(); the
|
||||||
|
# ten-game length is a live-test hypothesis, isolated behind FUT_MODES.
|
||||||
|
body["offlineSeason"] = {
|
||||||
|
"divisionId": "10",
|
||||||
|
"gamesPlayed": "0",
|
||||||
|
"points": "0",
|
||||||
|
"totalGames": "10",
|
||||||
|
"progressDataVersion": "0",
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
# ---- club stats: the CLUB STATS panel, and probably the MY CLUB tile too ------
|
# ---- club stats: the CLUB STATS panel, and probably the MY CLUB tile too ------
|
||||||
|
|||||||
@@ -97,3 +97,25 @@ docker compose up -d --build
|
|||||||
location.
|
location.
|
||||||
- TURN/relay re-addressing (multiplayer) and long-tail endpoints (weather,
|
- TURN/relay re-addressing (multiplayer) and long-tail endpoints (weather,
|
||||||
matchday, kit assets) are deferred feature gaps — tracked separately.
|
matchday, kit assets) are deferred feature gaps — tracked separately.
|
||||||
|
|
||||||
|
## Running state vs image — what the frozen image does NOT contain
|
||||||
|
|
||||||
|
The baseline image (`python-baseline-2026-08-10` / `dev`) was built at 02:14Z,
|
||||||
|
but the container's `/app` was hot-patched afterwards:
|
||||||
|
|
||||||
|
* `tools/utas_server.py` — gained the `FUT_MODES`-gated `offlineSeason` block in
|
||||||
|
GetHubData's club response (keeps the hub's offline-season summary valid).
|
||||||
|
* `tools/test_hub_offline_season_contract.py` — added to `/app/tools`.
|
||||||
|
|
||||||
|
`docker save` captures the image, not the container's writable layer, so the
|
||||||
|
baseline tar.gz lacks those two changes. Two paths cover the exact runtime:
|
||||||
|
|
||||||
|
* `openfut-fut-backend:python-running-2026-08-10` — `docker commit` of the
|
||||||
|
running container (sha256:093a98fa0496...), the exact runtime FS.
|
||||||
|
* The committed `fifa17-python/tools` + `data` — synced to match the running
|
||||||
|
container byte-for-byte (237 files verified, incl. the redir cert pair), so a
|
||||||
|
fresh build reproduces the actual running backend. Proven by rebuilding from
|
||||||
|
the committed sources and diffing the baked `/app/SHA256SUMS.txt` against the
|
||||||
|
container manifest: identical.
|
||||||
|
|
||||||
|
Archive: `docker-backups/openfut-fut-backend-python-running-2026-08-10.tar.gz`.
|
||||||
|
|||||||
Reference in New Issue
Block a user