Phase 5a: persistent websocket with request ids and reconnect
continuous-integration/drone/push Build encountered an error

Client (ts/network_ts.ts): one WebSocket per page. Commands queue and go
out one at a time with a client-chosen id; the response is matched on the
echoed id (or to the in-flight request for older servers). 12 s timeout
per request, exponential-backoff reconnect (0.5 s to 10 s), the in-flight
request is retried after a reconnect, and log polls are de-duplicated so
they cannot pile up behind a stalled connection. The old global flag that
silently dropped any request made while another was in flight is gone.

Server (src/webserver.go): the /data/ handler now serves any number of
commands on one connection (it used to break out of its loop after the
first reply without closing the socket, leaving it open and deaf; the old
client papered over that by opening a new socket per request). Connection
closed on exit, request id echoed in the response.

Test: TestWSServesMultipleCommandsPerConnection.
This commit is contained in:
2026-09-26 13:19:38 +10:00
parent cbc5bc5da2
commit 3a3ba861dc
8 changed files with 475 additions and 242 deletions
+8 -8
View File
@@ -1,7 +1,7 @@
# xTeVe improvement checklist
Detailed rationale, file references and effort estimates: `tasks/improvement-plan.md`.
Status: Phase 0 committed on branch `improvements` 2026-09-26.
Status: Phases 0, 1, 2, 3 done on branch `improvements` (2026-09-26); Phase 5 in progress.
## Phase 0: Hygiene
- [x] `.gitignore` (`.gocache/`), deleted `.gocache/`, extended `.dockerignore`
@@ -35,12 +35,12 @@ Status: Phase 0 committed on branch `improvements` 2026-09-26.
- [x] `streamingURLsMu` around `Data.Cache.StreamingURLS`; persisted from a snapshot
- [x] No more `defer` inside the buffer read/redirect loops (compression done in Phase 1; imgcache in 2b)
- [x] `thirdPartyBuffer` rewritten: `exec.CommandContext` cancelled when the last client leaves or the 20 s startup watchdog fires; `buildFFmpegArgs`/`buildVLCArgs` tested; no panic, `cmd.Start` checked, one file handle per segment. Client loop uses `r.Context()` instead of `CloseNotifier`
- [ ] Real mutex for screen log
- [ ] `http.Server` with timeouts; timeouts on all outbound clients
- [ ] imgcache: download outside the lock
- [ ] Atomic write helper (temp + fsync + rename)
- [x] Buffer: headers set before `WriteHeader`, bogus `Content-Length:` header gone, segments flushed to the client as they arrive. Others in 2b
- [ ] Error hygiene: no-op closures, `os.Exit`/`panic` outside main, ignored results
- [x] `logMu` guards `WebScreenLog` and notifications; accessors `logAppend`/`webScreenLogSnapshot`/`notificationsSnapshot`; ring buffer keeps the newest N (was dropping them)
- [x] `http.Server` with `ReadHeaderTimeout` 15 s and `IdleTimeout` 120 s (no write timeout, streams are long-lived); `providerHTTPClient` 5 min, `apiHTTPClient` 30 s, imgcache client 30 s, stream client with dial/TLS/header timeouts
- [x] imgcache downloads outside the lock; cache URL bug fixed (was a filesystem path); query-string URLs no longer produce unservable file names
- [x] `writeFileAtomic` (temp + fsync + rename) behind `writeByteToFile`, `saveMapToJSONFile`, `writePrivateFile` and the auth database
- [x] Buffer: headers set before `WriteHeader`, bogus `Content-Length:` header gone, segments flushed as they arrive. xepg file-removal bug, dead range mutation, API double write, WS struct reuse, unchecked assertions in data/backup/provider/screen, notification eviction by age: all fixed with tests
- [x] Error hygiene: no `panic`/`os.Exit`/`log.Fatal` outside `main`; SIGINT/SIGTERM handled in main via `src.Shutdown()`; fatal start-up errors exit 1
## Phase 3: Build, embed, CI, Docker
- [x] `//go:embed` via `html/embed.go`; deleted `webUI.go`, `html-build.go`, `cmd/webui-gen`; ETag + Cache-Control on static assets
@@ -58,7 +58,7 @@ Status: Phase 0 committed on branch `improvements` 2026-09-26.
Not planned (lineup is ~170 channels, decided 2026-09-25). See plan for the reference list.
## Phase 5: Frontend architecture
- [ ] Persistent websocket with request IDs, queue, backoff reconnect
- [x] Persistent websocket: one socket per page, queued requests with ids echoed by the server, 12 s per-request timeout, exponential-backoff reconnect, log-poll dedupe. Server keeps serving on one connection and closes it on exit (upstream leaked one open socket per request). Test: `TestWSServesMultipleCommandsPerConnection`
- [ ] Section-level re-render instead of full `createLayout()`
- [ ] Virtualised mapping table
- [ ] Split `menu_ts.ts`; `addEventListener`; data-driven settings rows