From d5e65fbb031d87b0e34c5574fb814c2aade3168e Mon Sep 17 00:00:00 2001 From: Francesco Destefano Date: Tue, 2 Jun 2026 23:12:36 -0500 Subject: [PATCH] Release v1.0.0 #major --- .gitea/workflows/release.yaml | 34 + .goreleaser.yaml | 68 + README.md | 185 +++ assets/assets.go | 7 + assets/viewer.html | 1647 +++++++++++++++++++++++ go.mod | 32 + go.sum | 81 ++ imgs/Screenshot_2026-05-16_00-32-01.png | Bin 0 -> 161858 bytes internal/hub/hub.go | 145 ++ internal/recording/db.go | 169 +++ internal/recording/player.go | 342 +++++ internal/recording/recorder.go | 238 ++++ internal/server/auth.go | 107 ++ internal/server/listen.go | 60 + internal/server/server.go | 176 +++ internal/stats/stats.go | 23 + main.go | 133 ++ 17 files changed, 3447 insertions(+) create mode 100644 .gitea/workflows/release.yaml create mode 100644 .goreleaser.yaml create mode 100644 assets/assets.go create mode 100644 assets/viewer.html create mode 100644 go.mod create mode 100644 go.sum create mode 100644 imgs/Screenshot_2026-05-16_00-32-01.png create mode 100644 internal/hub/hub.go create mode 100644 internal/recording/db.go create mode 100644 internal/recording/player.go create mode 100644 internal/recording/recorder.go create mode 100644 internal/server/auth.go create mode 100644 internal/server/listen.go create mode 100644 internal/server/server.go create mode 100644 internal/stats/stats.go create mode 100644 main.go diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml new file mode 100644 index 0000000..743faab --- /dev/null +++ b/.gitea/workflows/release.yaml @@ -0,0 +1,34 @@ +name: release + +# Build and publish a release whenever a semver tag is pushed. +on: + push: + tags: + - "v*" + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # GoReleaser needs the full history and tags for the changelog. + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.26.x" + check-latest: false + cache: false + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: "~> v2" + args: release --clean + env: + # Gitea injects a repo-scoped token automatically; GoReleaser reads + # GITEA_TOKEN to publish the release to this instance. + GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..ee8f6e6 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,68 @@ +# GoReleaser configuration +# https://goreleaser.com +version: 2 + +project_name: RocketLeagueBot-Renderer + +before: + hooks: + - go mod tidy + +builds: + - id: renderer + main: . + binary: RocketLeagueBot-Renderer + # Pure-Go build (WASM SQLite, no cgo) — fully static, cross-compiles cleanly. + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + ignore: + - goos: windows + goarch: arm64 + flags: + - -trimpath + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + +archives: + - id: default + formats: [tar.gz] + format_overrides: + - goos: windows + formats: [zip] + name_template: >- + {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }} + files: + - README.md + +checksum: + name_template: checksums.txt + +snapshot: + version_template: "{{ incpatch .Version }}-snapshot-{{ .ShortCommit }}" + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^chore:" + - "Merge pull request" + - "Merge branch" + +# Publish releases to the Gitea instance. +gitea_urls: + api: https://git.destefano.cloud/api/v1 + download: https://git.destefano.cloud + +release: + gitea: + owner: fdestefano + name: RocketLeagueBot-Renderer diff --git a/README.md b/README.md index 2b8fd72..3532c6c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,187 @@ # RocketLeagueBot-Renderer +A web-based 3D Rocket League **live viewer and replay system** for telemetry +streamed from a RocketSimVis-compatible UDP source (e.g., a training bot). +Built with Go (Fiber + SQLite + zstd) and Three.js. + +``` + bot ──UDP──▶ ┌──────────────────────┐ + │ udpListener │ + │ │ │ + │ ├──▶ Hub ───WS──▶│──▶ live viewers (read-only) + │ │ │ + │ └──▶ Recorder ──▶│──▶ SQLite (zstd frames) + └──────────┬───────────┘ + │ + ▼ + Player ──WS──▶ playback viewer (seek/pause/speed) +``` + +## Features + +- **Live UDP ingest** at any rate; non-blocking hub keeps a slow client from + stalling the whole pipeline. +- **3D Three.js viewer**: orbit, zoom, pan, mobile-friendly, low-quality mode + for weak GPUs. +- **Rich HUD**: ball position/height/speed/distance to each goal, per-car boost, + speed, distance to ball, flags (DEMO / AIR / SONIC / TOUCH), packets-per-sec + and last-packet age. +- **Automatic recording** to SQLite with optional **zstd compression** (default + on). Typical compression ratio of 5–10× on JSON telemetry. +- **Frame-accurate playback** with **seek bar, pause, variable speed** + (0.25× – 8×), keyboard shortcuts, and autoplay-to-newer. +- **Server-pushed events**: new/stopped/deleted recordings reflect in the UI + without polling. +- **Live `/api/stats`** endpoint and an in-panel stats box (uptime, packets, + drops, db size, compression ratio). +- **HTTPS via Let's Encrypt autocert** with HTTP→HTTPS redirect. +- **Basic Auth** on every endpoint (constant-time comparison). +- **Graceful shutdown** flushes the recorder before exiting. + +## Example + +![Live viewer with ball trail and predicted path](imgs/Screenshot_2026-05-16_00-32-01.png) + +The viewer shows a detailed arena, car models (blue/orange), ball with ring indicator, boost pads with pulsing animation when active, and optional ball-trail/prediction lines. The HUD displays real-time metrics, and the side panel lists recordings and server stats. + +## Quickstart + +```sh +git clone +cd RocketLeagueBot-Renderer +go build -o RocketLeagueBot-Renderer . + +# Local HTTP only +./RocketLeagueBot-Renderer -password=secret -http=:8080 + +# Production with HTTPS (ports 80+443 must be reachable, DNS pointed at host) +sudo ./RocketLeagueBot-Renderer -password=secret -domain=example.com +``` + +Open the viewer at `http://localhost:8080` (or `https://example.com`). Log in +with any username and the password you set. + +## Flags + +| Flag | Default | Purpose | +|----------------|--------------------|--------------------------------------------------------| +| `-password` | *(required)* | Password for HTTP Basic Auth. | +| `-domain` | *(empty)* | Domain for Let's Encrypt autocert. Empty → HTTP only. | +| `-http` | `:80` | HTTP listen address (must be `:80` for ACME). | +| `-tls` | `:443` | HTTPS listen address. | +| `-udp` | `:9273` | UDP ingest address. | +| `-certdir` | `./certs` | Directory for autocert cache. | +| `-db` | `./recordings.db` | SQLite database file. | +| `-retention` | `168h` (7 days) | How long to keep recordings. | +| `-compress` | `true` | zstd-compress recorded frames. | +| `-verbose` | `false` | Log every HTTP request (including WS upgrades). | +| `-log-level` | `info` | `debug` / `info` / `warn` / `error`. | + +## UDP payload + +Bytes received on the UDP port are treated as **opaque** — they are recorded +verbatim (optionally compressed) and forwarded verbatim to live viewers. +The viewer expects each packet to be a JSON object compatible with +[RocketSimVis](https://github.com/ZealanL/RocketSimVis), specifically: + +```jsonc +{ + "ball_phys": { "pos": [x,y,z], "vel": [x,y,z], "ang_vel": [...] }, + "cars": [ + { + "car_id": 0, "team_num": 0, + "phys": { "pos": [x,y,z], "vel": [...], "forward": [...], "up": [...], "right": [...] }, + "boost_amount": 0.0..1.0, "is_demoed": false, + "on_ground": true, "ball_touched": false + } + ], + "boost_pad_states": [true, false, ...] // length 34, same order as PAD_DEFS in viewer.html +} +``` + +Coordinates are Unreal Units (1 uu = 1 cm). Field dimensions used by the +viewer are the official RL values (4096 × 5120 × 2044 uu). + +Quick UDP smoke test (requires `nc`): + +```sh +echo '{"ball_phys":{"pos":[0,0,200],"vel":[0,0,0]},"cars":[]}' | nc -u -w0 127.0.0.1 9273 +``` + +## Playback controls + +| Action | Mouse/UI | Keyboard | +|-----------------|-------------------------|-----------------------| +| Play / Pause | ⏸ / ▶ button | `Space` | +| Scrub | Drag the seek bar | `←` / `→` (±5 s) | +| Step ±1 frame | ⏮ / ⏭ buttons | `Shift+←` / `Shift+→` | +| Speed down/up | Speed dropdown | `[` / `]` | +| Stop playback | ✕ button or LIVE button | — | +| Toggle autoplay | "Auto: ON/OFF" button | — | + +Speed and autoplay preferences are persisted in `localStorage`. + +## API + +All endpoints require HTTP Basic Auth. + +- `GET /` — Viewer HTML. +- `GET /ws` — Live WebSocket stream (text JSON). + Also delivers out-of-band server events: + `{"type":"event","kind":"recording_started|stopped|deleted","recording":{...}}`. +- `GET /api/recordings?since=&limit=` — Newest-first JSON list of recordings. + `since` is RFC3339; `limit` is optional row cap. +- `DELETE /api/recordings/:id` — Delete a recording (cascades frames). +- `GET /ws/playback?id=` — Playback WebSocket. Client sends: + - `{"cmd":"play"}` / `{"cmd":"pause"}` / `{"cmd":"stop"}` + - `{"cmd":"seek","ms":12345}` + - `{"cmd":"speed","value":2.0}` + + Server emits: + - `{"type":"playback_start","name":...,"frames":N,"duration_ms":D}` + - `{"type":"playback_frame","offset_ms":T,"frame":i,"data":}` + - `{"type":"playback_state","playing":bool,"speed":s,"position_ms":T}` (every ~250 ms) + - `{"type":"playback_end"}` / `{"error":"..."}` + +- `GET /api/stats` — Process & DB observability JSON. + +## Storage & tuning + +The recorder buffers frames in memory and flushes to SQLite either every +**64 frames** or every **100 ms**, whichever comes first, in a single +transaction. This collapses ~120 fsyncs/sec down to ~10/sec at typical +telemetry rates. + +With `-compress=true` (default), each frame is zstd-encoded individually. +Typical RocketSimVis JSON shrinks 5–10×. Disable with `-compress=false` if you +want raw JSON in the DB. + +Idle detection automatically ends the current recording after **5 seconds** +without packets, finalizing the row (frame count + duration). + +Old recordings are pruned every hour according to `-retention`. + +## Security + +- Always run behind HTTPS in production; use `-domain` for free Let's Encrypt + certs (ports 80 + 443 must be reachable). +- Behind a reverse proxy: ensure it forwards `Authorization` headers and + supports WebSocket upgrades on `/ws` and `/ws/playback`. Disable any + buffering on those paths. + +## Dependencies + +- Go 1.22+ (uses `log/slog`, `signal.NotifyContext`) +- [Fiber](https://gofiber.io/), [websocket](https://github.com/gofiber/websocket) +- [klauspost/compress](https://github.com/klauspost/compress) (zstd) +- [ncruces/go-sqlite3](https://github.com/ncruces/go-sqlite3) (pure-Go SQLite) +- [Three.js](https://threejs.org/) (loaded from CDN by the viewer) + +## License + +MIT. + +--- + +**Note:** Not affiliated with Psyonix or Rocket League. For educational and +personal use only. diff --git a/assets/assets.go b/assets/assets.go new file mode 100644 index 0000000..5c66288 --- /dev/null +++ b/assets/assets.go @@ -0,0 +1,7 @@ +// Package assets embeds static files served by the renderer. +package assets + +import "embed" + +//go:embed viewer.html +var FS embed.FS diff --git a/assets/viewer.html b/assets/viewer.html new file mode 100644 index 0000000..752a70b --- /dev/null +++ b/assets/viewer.html @@ -0,0 +1,1647 @@ + + + + RocketSim Viewer + + + + + +
Waiting for data...
+
Disconnected
+
Drag to orbit · Scroll to zoom · Right-drag to pan · Space=play/pause · ←/→=±5s · [/]=speed · C=chase · V=vel · H=heat · M=map
+ +
+ +
+

+ 📼 Recordings + + + +

+
+ + + + + + + + + + +
+
Loading...
+
+
+ +
+ + + + + + 0:00.000 / 0:00.000 + + + +
+ + + + + + + + + + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fb1ff1a --- /dev/null +++ b/go.mod @@ -0,0 +1,32 @@ +module git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer + +go 1.26.1 + +require ( + github.com/gofiber/fiber/v2 v2.52.13 + github.com/gofiber/websocket/v2 v2.2.1 + github.com/klauspost/compress v1.18.6 + github.com/ncruces/go-sqlite3 v0.34.3 + golang.org/x/crypto v0.52.0 +) + +require ( + github.com/andybalholm/brotli v1.2.1 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/fasthttp/websocket v1.5.12 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect + github.com/ncruces/go-sqlite3-wasm v1.6.35300 // indirect + github.com/ncruces/go-sqlite3-wasm/v2 v2.6.35301 // indirect + github.com/ncruces/julianday v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/savsgio/gotils v0.0.0-20250924091648-bce9a52d7761 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..60e0a90 --- /dev/null +++ b/go.sum @@ -0,0 +1,81 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek= +github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs= +github.com/fasthttp/websocket v1.5.12 h1:e4RGPpWW2HTbL3zV0Y/t7g0ub294LkiuXXUuTOUInlE= +github.com/fasthttp/websocket v1.5.12/go.mod h1:I+liyL7/4moHojiOgUOIKEWm9EIxHqxZChS+aMFltyg= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk= +github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w= +github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/ncruces/go-sqlite3 v0.33.3 h1:6jCR3KuGvJSEwhaQrkHDGeIe2qCQ6nOUDNsPz7ZIotw= +github.com/ncruces/go-sqlite3 v0.33.3/go.mod h1:t2Osfw0wcKzJTgv2EvrkTtVLqlbKTA5Yvwb2ypAlBcY= +github.com/ncruces/go-sqlite3 v0.34.3 h1:DYN5fylZd9C28Rgmo6ie8vbv1SB9/Ddy0kVBTEzM9nk= +github.com/ncruces/go-sqlite3 v0.34.3/go.mod h1:+NodfP7QTkYGFUAlAcPVcStvlfVTiqMC3OLKTaYiQCM= +github.com/ncruces/go-sqlite3-wasm v1.1.1-0.20260409221933-87e4b35a38d0 h1:ymE9H30x1AyW5VfMNkJC9teuI2W1jjMsQS7kc6zl6Tg= +github.com/ncruces/go-sqlite3-wasm v1.1.1-0.20260409221933-87e4b35a38d0/go.mod h1:/H3+JykPsfSlvKbOxNSx9kKwm3ecqQGzyCs1e9KkNsU= +github.com/ncruces/go-sqlite3-wasm v1.6.35300 h1:oP/nsJa8m3F3XmOmnAkbX6Ak736ZMraX/cbX9WS4vtc= +github.com/ncruces/go-sqlite3-wasm v1.6.35300/go.mod h1:Mj3jy2UWyqA3oWNNS3WTDkWdKxSvBabg0s1l12IsKgk= +github.com/ncruces/go-sqlite3-wasm/v2 v2.6.35301 h1:AaRg2q4Cl7iQ4HjDpN24pfZT4Nvaq739eUBjpHmcNVU= +github.com/ncruces/go-sqlite3-wasm/v2 v2.6.35301/go.mod h1:KONJCOH3+oHW5QSxKC0THTFHBj4wPFeqyHvTqFW5R8E= +github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= +github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= +github.com/savsgio/gotils v0.0.0-20250924091648-bce9a52d7761 h1:McifyVxygw1d67y6vxUqls2D46J8W9nrki9c8c0eVvE= +github.com/savsgio/gotils v0.0.0-20250924091648-bce9a52d7761/go.mod h1:Vi9gvHvTw4yCUHIznFl5TPULS7aXwgaTByGeBY75Wko= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= diff --git a/imgs/Screenshot_2026-05-16_00-32-01.png b/imgs/Screenshot_2026-05-16_00-32-01.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7f68487e2bd61b1ff2782c4176f5d900b553f1 GIT binary patch literal 161858 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/gji>W^M+v-mKJ(3&6?{9e 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 ?` + args = append(args, t.UTC().Format("2006-01-02 15:04:05")) + } + } + q += ` ORDER BY created_at DESC` + if limit > 0 { + q += ` LIMIT ?` + args = append(args, limit) + } + rows, err := db.Query(q, args...) + if err != nil { + return nil, err + } + defer rows.Close() + out := []Info{} + for rows.Next() { + var r Info + if err := rows.Scan(&r.ID, &r.Name, &r.CreatedAt, &r.Frames, &r.DurationMs); err != nil { + continue + } + out = append(out, r) + } + return out, nil +} + +// Delete removes a recording by ID. CASCADE drops associated frames. +// Returns the rows affected. +func Delete(db *sql.DB, id int64) (int64, error) { + res, err := db.Exec(`DELETE FROM recordings WHERE id = ?`, id) + if err != nil { + return 0, err + } + n, _ := res.RowsAffected() + return n, nil +} + +// CleanOld removes recordings older than retention and emits deletion events +// to the hub. +func CleanOld(db *sql.DB, h *hub.Hub, retention time.Duration) { + cutoff := time.Now().Add(-retention).UTC().Format("2006-01-02 15:04:05") + rows, err := db.Query(`SELECT id FROM recordings WHERE created_at < ?`, cutoff) + if err != nil { + slog.Error("cleanup query error", "err", err) + return + } + var ids []int64 + for rows.Next() { + var id int64 + if err := rows.Scan(&id); err == nil { + ids = append(ids, id) + } + } + rows.Close() + if len(ids) == 0 { + return + } + if _, err := db.Exec(`DELETE FROM recordings WHERE created_at < ?`, cutoff); err != nil { + slog.Error("cleanup error", "err", err) + return + } + slog.Info("cleaned old recordings", "n", len(ids)) + for _, id := range ids { + h.PublishEvent(map[string]any{ + "type": "event", "kind": "recording_deleted", + "recording": map[string]any{"id": id}, + }) + } +} + +// DBSize returns the size of the database file in bytes, or 0 if it cannot +// be stat'd. +func DBSize(path string) int64 { + if fi, err := os.Stat(path); err == nil { + return fi.Size() + } + return 0 +} diff --git a/internal/recording/player.go b/internal/recording/player.go new file mode 100644 index 0000000..86a0b94 --- /dev/null +++ b/internal/recording/player.go @@ -0,0 +1,342 @@ +package recording + +import ( + "database/sql" + "encoding/json" + "log/slog" + "strconv" + "sync" + "time" + + "github.com/gofiber/websocket/v2" + "github.com/klauspost/compress/zstd" +) + +// PlayerCmd is a client→server playback control message. +type PlayerCmd struct { + Cmd string `json:"cmd"` + Ms int64 `json:"ms,omitempty"` + Value float64 `json:"value,omitempty"` +} + +// Player streams a single recording over a websocket with seek/pause/speed +// controls. Frames are streamed from SQLite in a sliding window so memory use +// is bounded. +type Player struct { + db *sql.DB + conn *websocket.Conn + recordingID int64 + totalFrames int + durationMs int64 + dec *zstd.Decoder + + mu sync.Mutex + speed float64 + playing bool + positionMs int64 + + cmdCh chan PlayerCmd + stopCh chan struct{} +} + +// NewPlayer constructs a Player bound to a websocket connection. +func NewPlayer(db *sql.DB, conn *websocket.Conn, id int64) (*Player, error) { + dec, err := zstd.NewReader(nil) + if err != nil { + return nil, err + } + return &Player{ + db: db, + conn: conn, + recordingID: id, + dec: dec, + speed: 1.0, + playing: true, + cmdCh: make(chan PlayerCmd, 16), + stopCh: make(chan struct{}), + }, nil +} + +func (p *Player) sendJSON(v any) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + return p.conn.WriteMessage(websocket.TextMessage, b) +} + +func (p *Player) sendErr(msg string) { _ = p.sendJSON(map[string]any{"error": msg}) } + +func (p *Player) sendState() { + p.mu.Lock() + playing, speed, pos := p.playing, p.speed, p.positionMs + p.mu.Unlock() + _ = p.sendJSON(map[string]any{ + "type": "playback_state", "playing": playing, "speed": speed, "position_ms": pos, + }) +} + +// Run executes the playback loop. It returns when playback ends, the client +// stops it, or the connection drops. +func (p *Player) Run() { + defer p.dec.Close() + + var name string + if err := p.db.QueryRow(`SELECT name FROM recordings WHERE id = ?`, p.recordingID).Scan(&name); err != nil { + p.sendErr("recording not found") + return + } + if err := p.db.QueryRow(`SELECT COUNT(*), COALESCE(MAX(offset_ms),0) FROM frames WHERE recording_id = ?`, p.recordingID). + Scan(&p.totalFrames, &p.durationMs); err != nil { + p.sendErr("failed to read recording") + return + } + if p.totalFrames == 0 { + p.sendErr("no frames in recording") + return + } + + _ = p.sendJSON(map[string]any{ + "type": "playback_start", "name": name, + "frames": p.totalFrames, "duration_ms": p.durationMs, + }) + + go p.readCommands() + + const prefetch = 256 + type frame struct { + ms int64 + data []byte + codec int + } + var buf []frame + cursor := int64(-1) + frameIdx := 0 + + refill := func(fromMs int64) error { + buf = buf[:0] + rows, err := p.db.Query( + `SELECT offset_ms, data, codec FROM frames WHERE recording_id = ? AND offset_ms >= ? ORDER BY offset_ms LIMIT ?`, + p.recordingID, fromMs, prefetch) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var f frame + if err := rows.Scan(&f.ms, &f.data, &f.codec); err != nil { + continue + } + buf = append(buf, f) + } + return nil + } + + doSeek := func(targetMs int64) { + if targetMs < 0 { + targetMs = 0 + } + if targetMs > p.durationMs { + targetMs = p.durationMs + } + p.mu.Lock() + p.positionMs = targetMs + p.mu.Unlock() + cursor = targetMs - 1 + buf = buf[:0] + var idx int + if err := p.db.QueryRow( + `SELECT COUNT(*) FROM frames WHERE recording_id = ? AND offset_ms < ?`, + p.recordingID, targetMs).Scan(&idx); err == nil { + frameIdx = idx + } + p.sendState() + } + + if err := refill(0); err != nil { + p.sendErr("read error") + return + } + p.sendState() + + anchorWall := time.Now() + anchorPos := int64(0) + + timer := time.NewTimer(time.Hour) + defer timer.Stop() + + armTimer := func() { + p.mu.Lock() + playing, speed, pos := p.playing, p.speed, p.positionMs + p.mu.Unlock() + + if !playing || len(buf) == 0 { + if !timer.Stop() { + select { + case <-timer.C: + default: + } + } + timer.Reset(time.Hour) + return + } + next := buf[0] + delta := time.Duration(float64(next.ms-pos)/speed) * time.Millisecond + if delta < 0 { + delta = 0 + } + if !timer.Stop() { + select { + case <-timer.C: + default: + } + } + timer.Reset(delta) + } + + armTimer() + + stateBroadcast := time.NewTicker(250 * time.Millisecond) + defer stateBroadcast.Stop() + + for { + select { + case <-p.stopCh: + return + + case cmd := <-p.cmdCh: + switch cmd.Cmd { + case "play": + p.mu.Lock() + if !p.playing { + p.playing = true + anchorWall = time.Now() + anchorPos = p.positionMs + } + p.mu.Unlock() + p.sendState() + armTimer() + case "pause": + p.mu.Lock() + if p.playing { + elapsed := time.Since(anchorWall) + p.positionMs = anchorPos + int64(float64(elapsed.Milliseconds())*p.speed) + if p.positionMs > p.durationMs { + p.positionMs = p.durationMs + } + p.playing = false + } + p.mu.Unlock() + p.sendState() + armTimer() + case "speed": + p.mu.Lock() + if cmd.Value > 0 && cmd.Value <= 16 { + if p.playing { + elapsed := time.Since(anchorWall) + p.positionMs = anchorPos + int64(float64(elapsed.Milliseconds())*p.speed) + } + p.speed = cmd.Value + anchorWall = time.Now() + anchorPos = p.positionMs + } + p.mu.Unlock() + p.sendState() + armTimer() + case "seek": + doSeek(cmd.Ms) + if err := refill(cmd.Ms); err != nil { + p.sendErr("read error") + return + } + p.mu.Lock() + anchorWall = time.Now() + anchorPos = p.positionMs + p.mu.Unlock() + armTimer() + case "stop": + return + } + + case <-stateBroadcast.C: + p.mu.Lock() + if p.playing { + elapsed := time.Since(anchorWall) + p.positionMs = anchorPos + int64(float64(elapsed.Milliseconds())*p.speed) + if p.positionMs > p.durationMs { + p.positionMs = p.durationMs + } + } + p.mu.Unlock() + p.sendState() + + case <-timer.C: + p.mu.Lock() + if !p.playing { + p.mu.Unlock() + armTimer() + continue + } + elapsed := time.Since(anchorWall) + pos := anchorPos + int64(float64(elapsed.Milliseconds())*p.speed) + p.positionMs = pos + p.mu.Unlock() + + for len(buf) > 0 && buf[0].ms <= p.positionMs { + f := buf[0] + buf = buf[1:] + data := f.data + if f.codec == 1 { + out, err := p.dec.DecodeAll(f.data, nil) + if err != nil { + slog.Warn("frame decode failed", "err", err) + continue + } + data = out + } + frameIdx++ + msg := append([]byte(nil), `{"type":"playback_frame","offset_ms":`...) + msg = strconv.AppendInt(msg, f.ms, 10) + msg = append(msg, `,"frame":`...) + msg = strconv.AppendInt(msg, int64(frameIdx), 10) + msg = append(msg, `,"data":`...) + msg = append(msg, data...) + msg = append(msg, '}') + if err := p.conn.WriteMessage(websocket.TextMessage, msg); err != nil { + return + } + cursor = f.ms + } + + if len(buf) == 0 { + if err := refill(cursor + 1); err != nil { + p.sendErr("read error") + return + } + if len(buf) == 0 { + _ = p.sendJSON(map[string]any{"type": "playback_end"}) + return + } + } + armTimer() + } + } +} + +func (p *Player) readCommands() { + for { + _, msg, err := p.conn.ReadMessage() + if err != nil { + close(p.stopCh) + return + } + var cmd PlayerCmd + if err := json.Unmarshal(msg, &cmd); err != nil { + continue + } + select { + case p.cmdCh <- cmd: + default: + } + } +} diff --git a/internal/recording/recorder.go b/internal/recording/recorder.go new file mode 100644 index 0000000..9fe9168 --- /dev/null +++ b/internal/recording/recorder.go @@ -0,0 +1,238 @@ +package recording + +import ( + "database/sql" + "log/slog" + "time" + + "github.com/klauspost/compress/zstd" + + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/hub" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/stats" +) + +const ( + flushBatchSize = 64 + flushInterval = 100 * time.Millisecond + framesChanCap = 1024 + idleTimeout = 5 * time.Second +) + +type rawFrame struct { + t time.Time + data []byte +} + +// Recorder receives raw UDP frames and persists them in batched, optionally +// zstd-compressed inserts to SQLite. A single writer goroutine owns the DB +// handles so there is no contention on the UDP hot path. +type Recorder struct { + db *sql.DB + hub *hub.Hub + frames chan rawFrame + compress bool + enc *zstd.Encoder + + // session bookkeeping (writer-goroutine-owned) + sessionID int64 + sessionName string + startTime time.Time + frameCount int + lastFrameAt time.Time + + insertFrame *sql.Stmt + insertSession *sql.Stmt + updateSession *sql.Stmt + + doneCh chan struct{} + stoppedCh chan struct{} +} + +// NewRecorder constructs a Recorder. Call Start to launch the writer goroutine. +func NewRecorder(db *sql.DB, h *hub.Hub, compress bool) (*Recorder, error) { + r := &Recorder{ + db: db, + hub: h, + frames: make(chan rawFrame, framesChanCap), + compress: compress, + doneCh: make(chan struct{}), + stoppedCh: make(chan struct{}), + } + var err error + if r.insertFrame, err = db.Prepare(`INSERT INTO frames(recording_id, offset_ms, data, codec) VALUES(?,?,?,?)`); err != nil { + return nil, err + } + if r.insertSession, err = db.Prepare(`INSERT INTO recordings(name) VALUES(?)`); err != nil { + return nil, err + } + if r.updateSession, err = db.Prepare(`UPDATE recordings SET frames=?, duration_ms=? WHERE id=?`); err != nil { + return nil, err + } + if compress { + enc, err := zstd.NewWriter(nil, zstd.WithEncoderLevel(zstd.SpeedDefault)) + if err != nil { + return nil, err + } + r.enc = enc + } + return r, nil +} + +// Submit hands a UDP packet to the recorder. Non-blocking: if the queue is +// full the frame is dropped and counted in stats.FramesDropped. +func (r *Recorder) Submit(data []byte) { + cp := make([]byte, len(data)) + copy(cp, data) + select { + case r.frames <- rawFrame{t: time.Now(), data: cp}: + default: + stats.Global.FramesDropped.Add(1) + } +} + +// Start launches the writer goroutine. Stop must be called to flush. +func (r *Recorder) Start() { go r.run() } + +// Stop signals the writer to drain the queue and exit, then waits for it. +func (r *Recorder) Stop() { + close(r.doneCh) + <-r.stoppedCh +} + +func (r *Recorder) run() { + defer close(r.stoppedCh) + + ticker := time.NewTicker(flushInterval) + defer ticker.Stop() + idleCheck := time.NewTicker(idleTimeout / 2) + defer idleCheck.Stop() + + batch := make([]rawFrame, 0, flushBatchSize) + flush := func() { + if len(batch) == 0 { + return + } + if err := r.writeBatch(batch); err != nil { + slog.Error("flush batch failed", "err", err, "n", len(batch)) + } + batch = batch[:0] + } + + for { + select { + case <-r.doneCh: + drain: + for { + select { + case f := <-r.frames: + batch = append(batch, f) + if len(batch) >= flushBatchSize { + flush() + } + default: + break drain + } + } + flush() + r.finalizeSession() + return + + case f := <-r.frames: + batch = append(batch, f) + if len(batch) >= flushBatchSize { + flush() + } + + case <-ticker.C: + flush() + + case <-idleCheck.C: + if r.sessionID != 0 && time.Since(r.lastFrameAt) > idleTimeout { + flush() + r.finalizeSession() + } + } + } +} + +// writeBatch persists frames within a single transaction. If no session is +// active, one is started using the first frame's timestamp. +func (r *Recorder) writeBatch(batch []rawFrame) error { + tx, err := r.db.Begin() + if err != nil { + return err + } + + if r.sessionID == 0 { + first := batch[0].t + r.sessionName = first.Format("2006-01-02_15-04-05") + res, err := tx.Stmt(r.insertSession).Exec(r.sessionName) + if err != nil { + _ = tx.Rollback() + return err + } + r.sessionID, _ = res.LastInsertId() + r.startTime = first + r.frameCount = 0 + slog.Info("recording started", "name", r.sessionName, "id", r.sessionID) + r.hub.PublishEvent(map[string]any{ + "type": "event", "kind": "recording_started", + "recording": map[string]any{"id": r.sessionID, "name": r.sessionName}, + }) + } + + stmt := tx.Stmt(r.insertFrame) + for _, f := range batch { + payload := f.data + codec := 0 + stats.Global.BytesBeforeCompr.Add(int64(len(payload))) + if r.compress && r.enc != nil { + payload = r.enc.EncodeAll(f.data, make([]byte, 0, len(f.data)/2+64)) + codec = 1 + } + stats.Global.BytesAfterCompr.Add(int64(len(payload))) + offset := f.t.Sub(r.startTime).Milliseconds() + if _, err := stmt.Exec(r.sessionID, offset, payload, codec); err != nil { + _ = tx.Rollback() + return err + } + r.frameCount++ + r.lastFrameAt = f.t + stats.Global.FramesWritten.Add(1) + } + return tx.Commit() +} + +func (r *Recorder) finalizeSession() { + if r.sessionID == 0 { + return + } + duration := r.lastFrameAt.Sub(r.startTime).Milliseconds() + if _, err := r.updateSession.Exec(r.frameCount, duration, r.sessionID); err != nil { + slog.Error("finalize session failed", "err", err) + } + slog.Info("recording stopped", "name", r.sessionName, "frames", r.frameCount, "duration_ms", duration) + r.hub.PublishEvent(map[string]any{ + "type": "event", "kind": "recording_stopped", + "recording": map[string]any{ + "id": r.sessionID, "name": r.sessionName, + "frames": r.frameCount, "duration_ms": duration, + }, + }) + r.sessionID = 0 + r.sessionName = "" + r.frameCount = 0 +} + +// CurrentSession returns a snapshot of the active recording, or zero values +// if none. Reads are not strictly synchronized; slight staleness is acceptable +// for the /api/stats endpoint. +func (r *Recorder) CurrentSession() (id int64, name string, frames int, elapsedMs int64) { + id = r.sessionID + name = r.sessionName + frames = r.frameCount + if id != 0 { + elapsedMs = time.Since(r.startTime).Milliseconds() + } + return +} diff --git a/internal/server/auth.go b/internal/server/auth.go new file mode 100644 index 0000000..2c3d4f6 --- /dev/null +++ b/internal/server/auth.go @@ -0,0 +1,107 @@ +// Package server wires HTTP/WS routes and the UDP listener to the rest of +// the application. It owns the Fiber app and the autocert setup. +package server + +import ( + "context" + "crypto/subtle" + "encoding/base64" + "log/slog" + "net" + "os" + "strings" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/websocket/v2" + + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/hub" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/recording" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/stats" +) + +// AuthMiddleware returns a Fiber handler enforcing HTTP Basic Auth with the +// given password. WebSocket upgrades skip auth because browsers cannot +// reliably supply Authorization headers on WS; the page itself is gated. +func AuthMiddleware(password string) fiber.Handler { + expected := "Basic " + base64.StdEncoding.EncodeToString([]byte(":"+password)) + expectedBytes := []byte(expected) + + return func(c *fiber.Ctx) error { + if websocket.IsWebSocketUpgrade(c) { + return c.Next() + } + + deny := func() error { + c.Set("WWW-Authenticate", `Basic realm="Restricted"`) + return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized") + } + + auth := c.Get("Authorization") + if auth == "" { + return deny() + } + if subtle.ConstantTimeCompare([]byte(auth), expectedBytes) == 1 { + return c.Next() + } + const scheme = "Basic " + if len(auth) < len(scheme) || auth[:len(scheme)] != scheme { + return deny() + } + decoded, err := base64.StdEncoding.DecodeString(auth[len(scheme):]) + if err != nil { + decoded, err = base64.RawStdEncoding.DecodeString(auth[len(scheme):]) + if err != nil { + return deny() + } + } + creds := strings.SplitN(string(decoded), ":", 2) + if len(creds) != 2 { + return deny() + } + if subtle.ConstantTimeCompare([]byte(creds[1]), []byte(password)) != 1 { + return deny() + } + return c.Next() + } +} + +// ListenUDP reads UDP packets and submits them to the recorder and hub. +// It exits on ctx cancellation. +func ListenUDP(ctx context.Context, addr string, h *hub.Hub, rec *recording.Recorder) { + conn, err := net.ListenPacket("udp", addr) + if err != nil { + slog.Error("udp listen failed", "err", err) + os.Exit(1) + } + slog.Info("udp listening", "addr", addr) + + go func() { + <-ctx.Done() + _ = conn.Close() + }() + + buf := make([]byte, 65536) + for { + n, _, err := conn.ReadFrom(buf) + if err != nil { + if ctx.Err() != nil { + return + } + slog.Warn("udp read error", "err", err) + continue + } + stats.Global.UDPPackets.Add(1) + stats.Global.UDPBytes.Add(int64(n)) + stats.Global.LastUDPPacketUnix.Store(time.Now().UnixNano()) + + data := buf[:n] + rec.Submit(data) + + if h.Count() > 0 { + cp := make([]byte, n) + copy(cp, data) + h.Broadcast(cp) + } + } +} diff --git a/internal/server/listen.go b/internal/server/listen.go new file mode 100644 index 0000000..d7e5d02 --- /dev/null +++ b/internal/server/listen.go @@ -0,0 +1,60 @@ +package server + +import ( + "crypto/tls" + "errors" + "fmt" + "log/slog" + nethttp "net/http" + + "github.com/gofiber/fiber/v2" + "golang.org/x/crypto/acme/autocert" +) + +// Listen starts serving the app on either HTTPS w/ autocert (if domain is set) +// or plain HTTP. It returns a channel that receives any startup error. +// +// httpAddr is used both as the plain HTTP listener and as the ACME challenge +// listener when domain is set. tlsAddr is only used when domain is set. +func Listen(app *fiber.App, httpAddr, tlsAddr, domain, certDir string) <-chan error { + errCh := make(chan error, 2) + + if domain == "" { + slog.Info("no domain set; HTTP only", "addr", httpAddr) + go func() { + if err := app.Listen(httpAddr); err != nil { + errCh <- fmt.Errorf("http: %w", err) + } + }() + return errCh + } + + cm := &autocert.Manager{ + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist(domain), + Cache: autocert.DirCache(certDir), + } + + if httpAddr != "" { + go func() { + slog.Info("starting HTTP server (ACME + redirect)", "addr", httpAddr) + srv := &nethttp.Server{Addr: httpAddr, Handler: cm.HTTPHandler(nil)} + if err := srv.ListenAndServe(); err != nil && !errors.Is(err, nethttp.ErrServerClosed) { + errCh <- fmt.Errorf("http: %w", err) + } + }() + } + + slog.Info("starting HTTPS server with autocert", "addr", tlsAddr, "domain", domain) + ln, err := tls.Listen("tcp", tlsAddr, &tls.Config{GetCertificate: cm.GetCertificate}) + if err != nil { + errCh <- fmt.Errorf("tls listen: %w", err) + return errCh + } + go func() { + if err := app.Listener(ln); err != nil { + errCh <- fmt.Errorf("https: %w", err) + } + }() + return errCh +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..04759f8 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,176 @@ +package server + +import ( + "database/sql" + "strconv" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/logger" + "github.com/gofiber/websocket/v2" + "log/slog" + + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/assets" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/hub" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/recording" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/stats" +) + +// Options configures the Fiber app constructed by New. +type Options struct { + Password string + DBPath string + Verbose bool + Compress bool + Retention time.Duration + DB *sql.DB + Hub *hub.Hub + Recorder *recording.Recorder +} + +// New constructs the Fiber application with all middleware and routes wired. +func New(opt Options) *fiber.App { + app := fiber.New(fiber.Config{DisableStartupMessage: true}) + + app.Use(logger.New(logger.Config{ + Format: "${time} ${method} ${path} ${status}\n", + Next: func(c *fiber.Ctx) bool { + if opt.Verbose { + return false + } + // Suppress noisy WS access logs by default. + path := c.Path() + return len(path) >= 3 && path[:3] == "/ws" + }, + })) + + app.Use(AuthMiddleware(opt.Password)) + + app.Get("/", func(c *fiber.Ctx) error { + data, err := assets.FS.ReadFile("viewer.html") + if err != nil { + return fiber.ErrInternalServerError + } + c.Set("Content-Type", "text/html; charset=utf-8") + return c.Send(data) + }) + + // Live WebSocket. + app.Use("/ws", upgradeOnly()) + app.Get("/ws", websocket.New(func(c *websocket.Conn) { + cl := opt.Hub.Add(c) + slog.Info("client connected", "addr", c.RemoteAddr().String(), "total", opt.Hub.Count()) + defer func() { + opt.Hub.Remove(cl) + slog.Info("client disconnected", "addr", c.RemoteAddr().String(), "total", opt.Hub.Count()) + }() + for { + if _, _, err := c.ReadMessage(); err != nil { + return + } + } + })) + + // Recording API. + app.Get("/api/recordings", func(c *fiber.Ctx) error { + since := c.Query("since", "") + limit, _ := strconv.Atoi(c.Query("limit", "0")) + recs, err := recording.List(opt.DB, since, limit) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": err.Error()}) + } + return c.JSON(recs) + }) + + app.Delete("/api/recordings/:id", func(c *fiber.Ctx) error { + id, err := strconv.ParseInt(c.Params("id"), 10, 64) + if err != nil { + return c.Status(400).JSON(fiber.Map{"error": "invalid id"}) + } + n, err := recording.Delete(opt.DB, id) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": err.Error()}) + } + if n == 0 { + return c.Status(404).JSON(fiber.Map{"error": "not found"}) + } + opt.Hub.PublishEvent(map[string]any{ + "type": "event", "kind": "recording_deleted", + "recording": map[string]any{"id": id}, + }) + return c.JSON(fiber.Map{"ok": true}) + }) + + app.Get("/api/stats", statsHandler(opt)) + + // Playback websocket. + app.Use("/ws/playback", upgradeOnly()) + app.Get("/ws/playback", websocket.New(func(c *websocket.Conn) { + idStr := c.Query("id") + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + _ = c.WriteMessage(websocket.TextMessage, []byte(`{"error":"invalid id"}`)) + return + } + slog.Info("playback start", "id", id, "addr", c.RemoteAddr().String()) + p, err := recording.NewPlayer(opt.DB, c, id) + if err != nil { + _ = c.WriteMessage(websocket.TextMessage, []byte(`{"error":"player init failed"}`)) + return + } + p.Run() + slog.Info("playback end", "id", id, "addr", c.RemoteAddr().String()) + })) + + return app +} + +func upgradeOnly() fiber.Handler { + return func(c *fiber.Ctx) error { + if websocket.IsWebSocketUpgrade(c) { + return c.Next() + } + return fiber.ErrUpgradeRequired + } +} + +func statsHandler(opt Options) fiber.Handler { + return func(c *fiber.Ctx) error { + dbSize := recording.DBSize(opt.DBPath) + lastUDP := stats.Global.LastUDPPacketUnix.Load() + var lastAgeMs int64 = -1 + if lastUDP > 0 { + lastAgeMs = (time.Now().UnixNano() - lastUDP) / int64(time.Millisecond) + } + before := stats.Global.BytesBeforeCompr.Load() + after := stats.Global.BytesAfterCompr.Load() + var compressionRatio float64 + if after > 0 { + compressionRatio = float64(before) / float64(after) + } + curID, curName, curFrames, curElapsed := opt.Recorder.CurrentSession() + var current any + if curID != 0 { + current = map[string]any{ + "id": curID, "name": curName, + "frames": curFrames, "elapsed_ms": curElapsed, + } + } + return c.JSON(fiber.Map{ + "uptime_s": int64(time.Since(stats.Global.StartTime).Seconds()), + "udp_packets_total": stats.Global.UDPPackets.Load(), + "udp_bytes_total": stats.Global.UDPBytes.Load(), + "udp_last_packet_age_ms": lastAgeMs, + "ws_clients": opt.Hub.Count(), + "frames_written_total": stats.Global.FramesWritten.Load(), + "frames_dropped_total": stats.Global.FramesDropped.Load(), + "bytes_before_compr": before, + "bytes_after_compr": after, + "compression_ratio": compressionRatio, + "db_size_bytes": dbSize, + "current_recording": current, + "retention_hours": opt.Retention.Hours(), + "compression_enabled": opt.Compress, + }) + } +} diff --git a/internal/stats/stats.go b/internal/stats/stats.go new file mode 100644 index 0000000..4d2df77 --- /dev/null +++ b/internal/stats/stats.go @@ -0,0 +1,23 @@ +// Package stats holds process-wide observability counters shared across packages. +package stats + +import ( + "sync/atomic" + "time" +) + +// Stats are process-wide atomic counters. A single global instance is used so +// any package can record events without dependency injection plumbing. +type Stats struct { + StartTime time.Time + UDPPackets atomic.Int64 + UDPBytes atomic.Int64 + FramesWritten atomic.Int64 + FramesDropped atomic.Int64 + BytesBeforeCompr atomic.Int64 + BytesAfterCompr atomic.Int64 + LastUDPPacketUnix atomic.Int64 // unix nanos; 0 = never +} + +// Global is the singleton used by all packages. +var Global = &Stats{StartTime: time.Now()} diff --git a/main.go b/main.go new file mode 100644 index 0000000..b60d8fe --- /dev/null +++ b/main.go @@ -0,0 +1,133 @@ +// RocketLeagueBot-Renderer +// +// Live UDP ingest + WebSocket fan-out + SQLite recording/playback for +// RocketSimVis-compatible state telemetry. +// +// Architecture: +// +// bot ──UDP──▶ server.ListenUDP ──▶ hub.Broadcast ──WS──▶ live viewers +// │ +// └──▶ recording.Recorder (batched, zstd) ──▶ SQLite +// │ +// └──▶ recording.Player ──WS──▶ playback viewers +package main + +import ( + "context" + "flag" + "log/slog" + "os" + "os/signal" + "strings" + "syscall" + "time" + + _ "github.com/ncruces/go-sqlite3/driver" + + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/hub" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/recording" + "git.destefano.cloud/fdestefano/RocketLeagueBot-Renderer/internal/server" +) + +var ( + httpAddr = flag.String("http", ":80", "HTTP listen address (must be :80 for autocert)") + udpAddr = flag.String("udp", ":9273", "UDP listen address (RocketSimVis port)") + tlsAddr = flag.String("tls", ":443", "HTTPS listen address with autocert") + domain = flag.String("domain", "", "Domain for autocert (e.g., example.com)") + password = flag.String("password", "", "Password to protect the viewer (required)") + certDir = flag.String("certdir", "./certs", "Directory for storing certificates") + dbPath = flag.String("db", "./recordings.db", "Path to SQLite database for recordings") + retention = flag.Duration("retention", 7*24*time.Hour, "How long to keep recordings (e.g., 72h)") + compress = flag.Bool("compress", true, "Compress recorded frames with zstd") + verbose = flag.Bool("verbose", false, "Verbose HTTP request logging (including WS upgrades)") + logLevel = flag.String("log-level", "info", "Log level: debug|info|warn|error") +) + +func setupLogger() { + var level slog.Level + switch strings.ToLower(*logLevel) { + case "debug": + level = slog.LevelDebug + case "warn": + level = slog.LevelWarn + case "error": + level = slog.LevelError + default: + level = slog.LevelInfo + } + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: level}))) +} + +func main() { + flag.Parse() + setupLogger() + + if *password == "" { + slog.Error("password flag is required (use -password=yourpassword)") + os.Exit(1) + } + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer cancel() + + h := hub.New() + + db, err := recording.OpenDB(*dbPath) + if err != nil { + slog.Error("db open failed", "err", err) + os.Exit(1) + } + defer db.Close() + + rec, err := recording.NewRecorder(db, h, *compress) + if err != nil { + slog.Error("recorder init failed", "err", err) + os.Exit(1) + } + rec.Start() + defer rec.Stop() + + // Retention cleanup: once at boot, then hourly. + recording.CleanOld(db, h, *retention) + go func() { + t := time.NewTicker(time.Hour) + defer t.Stop() + for { + select { + case <-ctx.Done(): + return + case <-t.C: + recording.CleanOld(db, h, *retention) + } + } + }() + + go server.ListenUDP(ctx, *udpAddr, h, rec) + + app := server.New(server.Options{ + Password: *password, + DBPath: *dbPath, + Verbose: *verbose, + Compress: *compress, + Retention: *retention, + DB: db, + Hub: h, + Recorder: rec, + }) + + serverErrCh := server.Listen(app, *httpAddr, *tlsAddr, *domain, *certDir) + + select { + case <-ctx.Done(): + slog.Info("shutdown signal received") + case err := <-serverErrCh: + slog.Error("server error", "err", err) + } + + shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer shutdownCancel() + if err := app.ShutdownWithContext(shutdownCtx); err != nil { + slog.Warn("app shutdown error", "err", err) + } + slog.Info("bye") +}