economy(fifa17): land Store + Market writer handlers + pack generator (unrouted)
Implements the FIFA17 economy WRITER cluster on top of the landed Core
economy authority + host CoreEconomy client + identity/item-shaper infra.
Handlers are pub, unit-tested, and NOT yet routed: classify() and
ROUTE_AUTHORITY are untouched — the classifier barrier is a later single
coherent flip. No stubs; real Core-backed behavior; fail-closed on CoreError.
Pack generator (adapter fut/pack_content.rs):
generate_pack_contents(&PackDef, &mut impl Rng, &[GeneratedCandidate])
-> Vec<GeneratedCard>. Pure, seeded (deterministic), gold-tier split +
special_chance gate as documented OPENFUT PLACEHOLDER policy (Python
open_pack/_pack_body parity note inline). Fail-closed empty on empty pool.
Store/item writers (host economy_store.rs), matching oracle wire shapes:
- handle_store_buy PUT /store/transaction -> purchase_items (debit+mint N)
-> createPackResponse; cancel/unknown/owned_only -> 200 {}; insufficient
-> 461 {reason,credits}; CoreError -> 503.
- handle_pack_open POST /purchased -> owned_only consumes the unopened
entitlement (redeem_entitlement, consume-once); normal packs debit+mint.
- handle_quick_sell{_path,_body} DELETE .../item/<id> + POST /ut/delete/.../item
-> reverse-resolve wire->Core id (SquadWireResolver) -> sell_item ->
{items:[{id}],totalCredits}; not-owned skipped.
Production OwnedItemLookup = CoreItemLookup over CoreAccess.
Market (host market_store.rs / pile_store.rs / market.rs), synthetic-seller:
- MarketStore over sqlx SQLite (WAL-once + busy_timeout=5s + BEGIN IMMEDIATE
for writes, mirroring openfut-core::db). listings(active/reserved/sold/
cancelled), owner-checked cancel, CAS reserve/complete_sale/rollback.
Typed errors NotFound/Sold/Cancelled/WrongOwner/Conflict.
- PileStore: durable pile/location metadata keyed by Core item id.
- handle_market_{list,query,cancel,buy} + handle_move_items. Buy-now =
reserve (CAS) -> balance precheck (461) -> Core purchase_item (mint+debit)
-> complete_sale; any Core failure rolls the reservation back active.
Two concurrent buyers -> exactly one sale + one debit.
Deps (additive): rand 0.8 (adapter+host), sqlx 0.7 sqlite/runtime-tokio (host).
Tests: adapter +7 (pack_content), host +43 (economy_store 20, market/store 23
incl two_reservers_exactly_one_wins, two_buyers_exactly_one_sale_one_debit,
state_survives_reopen, move_persists_across_reopen). All green; clippy
-D warnings clean; rustfmt clean.
This commit is contained in:
@@ -14,6 +14,15 @@ serde_json = "1"
|
||||
# Plain-HTTP client for Core queries and Python passthrough. UTAS is plaintext
|
||||
# HTTP (worker D: no wrap_socket, no cert), so no TLS backend is linked.
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json"] }
|
||||
# Durable FIFA-specific market listing + item-pile state. These are host-owned
|
||||
# FIFA policy stores (NOT generic Core inventory), backed by their own SQLite
|
||||
# file, opened exactly like openfut-core/src/db.rs::init_pool (WAL-once +
|
||||
# foreign_keys + busy_timeout, BEGIN IMMEDIATE for writes).
|
||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio"] }
|
||||
# Seeded RNG for the Store pack-content generator injected into the economy
|
||||
# writer handlers (`economy_store`). Production seeds it from entropy (so minted
|
||||
# Core instance ids never collide); tests seed a fixed value for reproducibility.
|
||||
rand = "0.8"
|
||||
|
||||
[dev-dependencies]
|
||||
parking_lot = "0.12"
|
||||
|
||||
Reference in New Issue
Block a user