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.
84 lines
8.1 KiB
Markdown
84 lines
8.1 KiB
Markdown
# xTeVe improvement checklist
|
|
|
|
Detailed rationale, file references and effort estimates: `tasks/improvement-plan.md`.
|
|
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`
|
|
- [x] `agent.md` / `skill.md` git-ignored and docker-ignored (left in place)
|
|
- [x] Version drift fixed (`xteve.go` now 0201) and Drone drift check added
|
|
- [x] Auto-updater deleted (`BinaryUpdate`, `internal/up2date`, `GitHub`/`Update` structs, `xteveAutoUpdate` + `update.url` settings, UI rows, `en.json`); migrations kept in `migrate.go`; `kardianos/osext` gone
|
|
- [x] `go 1.27.1`; Dockerfile and Drone golang images pinned to 1.27.1
|
|
- [x] Four `go vet` unreachable-code warnings fixed (vet clean)
|
|
- [x] staticcheck baseline via `go run honnef.co/go/tools/cmd/staticcheck@latest ./...`: 408 findings (S1002 113, SA5008 79, S1039 67, S1038 40, S1023 35, ST1005 20, SA1019 14, SA4006 9, misc 11). Mostly style; SA5008/SA4006/SA1019 worth a pass in Phase 3 cleanup
|
|
|
|
## Phase 1: Security
|
|
- [x] `textContent` for provider-controlled strings (cells, client info, in-place edits, logs, popup descriptions with an explicit static-HTML flag)
|
|
- [x] Websocket uses gorilla's same-origin check; token read from the HttpOnly cookie (query param kept for legacy clients); payload/token console logging removed. Tests in `src/websocket_test.go`
|
|
- [x] Cookie `HttpOnly`, `SameSite=Strict`, `Path=/`, cleared on logout
|
|
- [x] Wizard GET no longer mutates `AuthenticationWEB`; the wizard page just bypasses login while active
|
|
- [x] `uploadLogo` filename sanitised (base name, image extensions only)
|
|
- [x] Zip-slip guard in `extractZIP` (also no more defer-in-loop there)
|
|
- [x] `ffmpeg.path`/`vlc.path` must be a regular file named ffmpeg/vlc/cvlc; stream URLs handed to the external buffer must use a network scheme
|
|
- [x] `/download/` requires the web session when web auth is on
|
|
- [~] Host-header-derived URLs kept by design (LAN, many interfaces; URLs must match how the client reached the server)
|
|
- [x] bcrypt for new passwords and credential changes; legacy SHA256 records verified in constant time and upgraded on first login; username compare constant-time
|
|
- [x] Expired tokens evicted on every new session; URL/Basic auth no longer mint tokens at all (`AuthenticateUser`)
|
|
- [~] Not applicable: xTeVe has no roles, every web user is an administrator by design (documented in README security notes)
|
|
- [x] `settings.json` written 0600; Plex token masked in every payload to the UI, mask round-trips as "unchanged" on save
|
|
- [x] Decide default for web auth on fresh installs (keep off; LAN only, decided 2026-09-25)
|
|
|
|
## Phase 2: Streaming stability
|
|
- [x] Race tests in `src/buffer_test.go`: restream shares one provider connection, tuner limit atomic under 6 concurrent tunes, acquire/release contention, cleanup on last client; run with `-race`
|
|
- [x] New `src/buffer_state.go`: one `bufferMu`, playlists by pointer, one `bufferStream` per stream (status, client count, error, cancel hook); downloaders keep a private working copy and publish through helpers. `BufferInformation`/`BufferClients`/`Lock` removed
|
|
- [x] Tuner check and registration under one lock (`bufferAcquireStream`); last client out removes the stream, cancels its process and deletes its folder
|
|
- [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`
|
|
- [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
|
|
- [x] i18n dropped: 254 placeholders inlined, `en.json` deleted, only HTML pages templated (`authenticationErr`)
|
|
- [x] `package.json` + `ts/tsconfig.json` (tsc 5.9.3, ES2020, single outFile `html/js/app.js`, committed, CI-verified); 10 dead JS files deleted; 6 tsc errors fixed incl. a real ASI bug in the search shortcut
|
|
- [x] CI: vet, gofmt check, staticcheck v0.8.1 (config in `staticcheck.conf`), bundle freshness check. `go test -race` still to add once tests exist
|
|
- [ ] Version-tagged images (amd64 only)
|
|
- [x] PUID/PGID via su-exec at runtime; static-ffmpeg pinned to 7.1.1; `VOLUME /xteve/config`; `/xteve` removed from `LEGACY_CONFIG_DIRS`; compose files pull from the registry and document SSDP/host networking
|
|
- [x] `/healthz` endpoint; Dockerfile healthcheck uses it
|
|
- [x] `README-DEV.md` and fork-specific `README.md` (about, container usage, env vars, security notes)
|
|
- [x] staticcheck 399 -> 0; dead code and duplicates removed; `ioutil`/`rand.Seed` gone. Real bugs fixed on the way: leaked file handle per ffmpeg segment, unchecked `http.NewRequest`, migration writing `null` xepg.json, silent user-write failures, unwritable config/temp dir now fatal at start
|
|
- [ ] Resolve missing `docs/design-system/` referenced by `agent.md` (user decision: agent.md is a personal, git-ignored file)
|
|
|
|
## Phase 4: Data model and performance
|
|
Not planned (lineup is ~170 channels, decided 2026-09-25). See plan for the reference list.
|
|
|
|
## Phase 5: Frontend architecture
|
|
- [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
|
|
- [ ] Accessibility follow-ups; light theme via `prefers-color-scheme`
|
|
- [ ] Consolidate CSS layers
|
|
|
|
## Phase 6: Optional features
|
|
- [ ] Regex filters
|
|
- [ ] Per-playlist tuner limit and buffer choice
|
|
- [ ] Bulk channel edit
|
|
- [ ] Versioned backup/restore
|
|
- [ ] Dummy EPG durations
|
|
|
|
## Review
|
|
|
|
### Phase 0 (2026-09-26, branch `improvements`)
|
|
- `go build`, `go vet`, `go test ./...` all clean. `src/webUI.go` regenerated.
|
|
- Smoke run against an empty config dir on port 34499: `/web/`, `/lineup_status.json`, `/discover.json` all 200, no errors logged.
|
|
- Not verified locally: Docker image build (no daemon on this machine); Drone will cover it.
|
|
- Compiled JS in `html/js/` was hand-edited to mirror the TS change because a current `tsc` does not reproduce the committed output (different shim, 5 type errors in `menu_ts.ts`). Phase 3 replaces this with a pinned toolchain.
|
|
- `html/js/menu.js` still mentions `xteveAutoUpdate`; it is one of the ten dead legacy files scheduled for deletion in Phase 3.
|
|
- `Settings.Branch` (`git.branch`) was kept: it still drives whether the build number is shown in the UI and XMLTV header.
|