92 lines
4.6 KiB
Markdown
92 lines
4.6 KiB
Markdown
# maze32 WebSocket protocol v1
|
||
|
||
## Limits and ordering
|
||
|
||
- Endpoint: `/ws`.
|
||
- At most six WebSocket connections are accepted: two players and four
|
||
observers.
|
||
- A text frame is at most 512 bytes. Binary frames are rejected.
|
||
- Each connection may submit at most 20 messages in a one-second monotonic
|
||
window.
|
||
- The gateway uses a fixed 12-entry outgoing queue with 768 bytes per entry.
|
||
- Client sequence numbers start above zero and strictly increase for the life
|
||
of one WebSocket connection. Replayed or decreasing values are rejected.
|
||
- Server sequence numbers strictly increase until reboot. Clients discard
|
||
stale server messages.
|
||
|
||
All messages use this envelope:
|
||
|
||
```json
|
||
{"v":1,"type":"message_type","seq":1,"requestId":"optional","payload":{}}
|
||
```
|
||
|
||
Envelope keys may appear in any order except that `type` must precede
|
||
`payload`. Unknown and duplicate keys are rejected. `requestId` is optional and
|
||
is only echoed for correlation; it grants no authority.
|
||
|
||
## Client messages
|
||
|
||
- `join`: `{"role":"player","name":"..."}` or `{"role":"observer"}`.
|
||
Player names contain 1–32 UTF-8 bytes, have no control bytes or outer spaces,
|
||
and are unique within the current lobby.
|
||
- `restore`: `{"token":"32 lowercase hexadecimal characters"}`.
|
||
- `start`: `{}`. Only connected Player 1 may use it, and both player slots must
|
||
be connected.
|
||
- `move`: `{"direction":"north|east|south|west"}`. Only a player in an active,
|
||
unpaused match may submit movement intent.
|
||
- `drop_key`: `{}`. Only a player in an active, unpaused match may submit the
|
||
key-drop intent.
|
||
- `restart`: `{}`. Only connected Player 1 may reset a finished match, and both
|
||
players must be connected. Sessions are preserved while a new authoritative
|
||
maze and game state are created.
|
||
- `leave`: `{}`. Revokes only the authenticated sending session. A player
|
||
leaving any non-waiting match phase, including a finished result, cancels
|
||
that match and returns remaining sessions to the waiting lobby; observer and
|
||
waiting-lobby departures release only that session.
|
||
- `heartbeat`: `{}` after a session has been joined or restored.
|
||
|
||
## Server messages
|
||
|
||
- `session`: the private role result containing `role`, `slot`, and temporary
|
||
`token`. The token is never included in a shared snapshot.
|
||
- `lobby`: the authoritative phase, revision, readiness, public player slots,
|
||
connected observer count, and limits.
|
||
- `countdown`: the single authoritative `[3,2,1]` event with common monotonic
|
||
`startedAtMs` and `activationAtMs` values. It is sent to both players.
|
||
- `active`: the exact authoritative activation instant.
|
||
- `view`: a bounded chunk of a role-specific authoritative game projection.
|
||
Observer chunks contain the complete maze and both player records, including
|
||
their connection state; player chunks retain the fog-of-war boundary. Each
|
||
projected cell carries compact Player 1 and Player 2 trail ownership masks
|
||
for its east and south edges only when both edge endpoints are authorized.
|
||
- `pause`: identifies the disconnected player slot and its monotonic reconnect
|
||
deadline.
|
||
- `resume`: reports that both players are attached and authoritative gameplay
|
||
has resumed.
|
||
- `match_result`: reports the terminal winner or draw.
|
||
- `reset`: reports the authoritative return from a finished match to the
|
||
waiting lobby.
|
||
- `ack`: successful heartbeat correlation. A heartbeat acknowledgement has
|
||
`payload.command` set to `heartbeat` and a bounded integer
|
||
`payload.handlingMs` measured only by the ESP monotonic clock while it
|
||
prepares that acknowledgement.
|
||
- `error`: a stable English `code` and Russian player-facing `message`.
|
||
|
||
An observer session can receive snapshots but cannot issue `start`, `move`, or
|
||
`drop_key`; attempts are rejected with `read_only` where applicable and logged
|
||
by the gateway. Player tokens reserve their original slot after disconnection
|
||
so a refresh can restore it. A player disconnect pauses the game for at most 60
|
||
seconds; restoration reattaches the same state, while expiry produces a draw.
|
||
A disconnected observer token may be restored until its bounded slot is reused
|
||
by a new observer, and observer disconnects never pause the match.
|
||
|
||
## Runtime diagnostics
|
||
|
||
`GET /diagnostics` returns bounded operational counters and internal-memory
|
||
samples without exposing session tokens, Wi-Fi credentials, or hidden maze
|
||
state. Counters cover connection and queue high-water marks, sent/dropped/
|
||
failed messages, malformed and rate-limited input, accepted game commands,
|
||
match cycles, maximum WebSocket handler/send duration, and current/minimum
|
||
internal free heap and largest block. The response also publishes the fixed
|
||
limits used by the Milestone 010 physical stress client.
|