Files
Showdown/backend/README.md
T
2026-06-12 21:55:03 +07:00

47 lines
1.8 KiB
Markdown

# Showdown backend
Rust (axum + tokio). Implements `../PROTOCOL.md`: WebSocket rooms that live
entirely in memory and a static file server for the built frontend — the whole
app is one binary plus a `dist/` folder.
## Run it
```sh
# build the frontend first so there is something to serve
cd ../frontend && npm run build && cd ../backend
cargo run # http://localhost:8080
```
- `PORT` — listen port (default `8080`)
- `STATIC_DIR` — built frontend location (default `../frontend/dist`)
During frontend development you can instead run `npm run dev` with
`VITE_WS=1` and Vite proxies `/ws` here.
## How it stays small
- **No database, by design.** A `Room` is a deck, a `revealed` flag, a round
counter and a `Vec` of players — a few hundred bytes. All rooms sit in one
`Mutex<HashMap>`. When the last socket of a room closes, the room is
removed; restart the server and everything is gone, which is the point.
- **One task per socket, nothing else.** Each connection is a single
`tokio::select!` loop (snapshots out, messages in, a 30s keepalive ping).
No per-room goroutine-style actors, no background jobs, no timers per room.
- **Snapshots are serialized once per change** (borrowed data, no clones) and
fanned out through a per-room `broadcast` channel with a small buffer.
## Files
```
src/main.rs routes + static serving with SPA fallback (~40 lines)
src/room.rs room state and the game rules (vote/reveal/reset/deck)
src/ws.rs socket lifecycle: hello → select loop → disconnect cleanup
```
Rules enforced here (mirroring PROTOCOL.md): votes are hidden until reveal
and rejected after it; reveal needs at least one vote; reset/deck-change
start a fresh round; a refresh re-claims the same seat without losing the
vote; watchers (`watch` handshake — the TV view) receive everything and may
send nothing.