From 058432130628d00764663ecf819a9adc6793768d Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 8 Nov 2026 03:29:35 +0100 Subject: v5.0.0: protocol v5 and the browser frontend Protocol v5 replaces newline lines with bounded [u32 len][text] frames and REQ/RES/EVT envelopes. Requests carry correlation ids and the server replays the last 256 replies per connection, so a gateway retry cannot double-debit and a late reply cannot clobber a newer request. HELLO/PONG carry server time; crash rounds announce started_at and push coalesced 10 Hz ticks. Crash now commits sha256(seed) before a round and reveals the seed when it ends, so clients recompute the crash point. Adds the webd/ gateway: one blocking thread, one ClientCore and one pinned upstream TLS connection per session, an HttpOnly session cookie, takeover, and a 60-second grace window. The browser sends Command JSON and renders View JSON; it never speaks the game protocol or stores credentials. Adds the vanilla TypeScript browser app at /play/ (login, lobby, all four games, history, notices, crash verification), the nginx /play and /ws routes, and the headless DOM smoke test. webd and the app stay out of the TUI/GUI/server build graph. The client/server version moves to 5.0.0 in lockstep; v4 peers are refused at HELLO. --- CONTEXT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CONTEXT.md (limited to 'CONTEXT.md') diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..6fefd53 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,76 @@ +# Context + +zagan-bet is a small play-money casino: one Rust workspace with a shared +library, a terminal client, a server, a desktop GUI and a browser frontend. This file names the things the code and the docs talk about. Keep it +current when a term changes meaning. + +## Product terms + +- **Play credit** — the unit a player wins and loses. Registration grants a + starting balance. There are no deposits, withdrawals, cash-outs or KYC; the + web app is a game, not a regulated gambling service. +- **Server** — the authoritative process. It owns the database, the game + rules, the balances, the random draws and the clock used to settle crash. +- **Frontend** — a presentation adapter over `ClientCore`: the terminal client, + the egui desktop app, or the browser app behind the web gateway. Frontends + send `Command` values and render `View` values. They never compute payouts. +- **ClientCore** — the I/O-free state machine shared by every frontend. It owns + navigation, the current game view, the pending request, and the local clock + anchor for crash. It contains no terminal, network or egui types. +- **Gateway (`webd`)** — a server-side frontend adapter for the browser. It owns + one upstream TLS connection and one `ClientCore` per browser session, and + translates browser JSON into `Command`/`View`. The browser never speaks the + game wire protocol. +- **Upstream** — the game server the gateway connects to. Its address and SPKI + fingerprint are operator configuration. The browser never sees a certificate. +- **Session** — one browser login held by the gateway. Identified by an + HttpOnly cookie. A refresh or a new tab reattaches to the same session during + the grace window; a later visit starts a new login. + +## Wire terms + +- **Frame** — `[u32 length][UTF-8 payload]`, length big-endian, at most 64 KiB. + The frame is the unit of transport; the payload is text. +- **Envelope** — the first token of a frame payload: + - `REQ [idem=] ` — client request. + - `RES ` — the reply to that request. + - `EVT ` — a server-initiated event, numbered per connection. +- **Request id** — a client-chosen `u64`, unique on the connection while its + reply is cached. It correlates a reply with the request that caused it. +- **Idempotency key** — an optional opaque token on a request. The connection + caches the last 256 request ids; resending the same id and payload replays the + stored reply instead of performing the action twice. +- **Event sequence** — a server-chosen `u64`, incremented once per `EVT` on a + connection. Clients use it to drop duplicates and to notice gaps. +- **HELLO** — the first request after TLS. Client and server must share + `MAJOR.MINOR`; the reply carries the server version, download URL and the + server's Unix time in milliseconds. +- **Tick** — `EVT crash.tick session= t= m=`, pushed + at most every 100 ms while a crash round runs. The server clock still settles + a cash-out. +- **Commit** — `sha256(seed)` in hex, sent with `CRASH_START` before the player + can act. **Reveal** — the seed itself, sent when the round ends. The crash + point is a pure function of the seed, so a player can check both. + +## Deployment terms + +- **Download site** — `web/`: `index.php` lists builds, `latest.php` feeds the + stable installers, `install.sh`/`install.ps1` fetch and verify the newest app. +- **Play app** — the static browser bundle under `/play/`, built from + `web/play/` with esbuild and served by nginx. +- **Grace window** — the 60 seconds the gateway keeps an upstream connection + after the last browser socket closes. Reattaching within it preserves a live + round; expiry closes upstream and the server forfeits per its existing rule. +- **Takeover** — a new browser connection presenting an existing session cookie + replaces the old socket; the old tab is told it was replaced. + +## Invariants + +- One payout formula, one place. `process_action` stores raw data; + `calculate_result` derives the result. Frontends only render. +- Every balance mutation is transactional, and an audit row exists before the + balance moves. +- A crash point never reaches a client before the round ends. +- The server clock, not a browser or gateway clock, settles cash-out. +- `MAJOR.MINOR` is lockstep between client and server; only the patch component + may differ. A wire change is a MAJOR bump. -- cgit v1.2.3