Files
zwitschi 33b6296c5e
CI / test (push) Successful in 2m50s
CI / docker (push) Successful in 5m12s
Refactor load testing scripts to support Bash and PowerShell
- Updated README.md to reflect changes in load testing commands and added usage examples for Bash scripts.
- Converted PowerShell load testing scripts to Bash equivalents for better cross-platform compatibility.
- Added new Bash scripts: run-loadtests.sh, summarize-artillery.sh, and summarize-k6.sh to mirror existing PowerShell functionality.
- Updated admin-api.js and ws-chat.yml for consistency and improved performance metrics reporting.
- Enhanced error handling and output formatting in summary scripts for better readability.
2026-09-02 19:47:34 +02:00

8.8 KiB

Linear Void API Reference

Base URLs: Public/admin app https://linearvoid.tv · WebSocket wss://linearvoid.tv/ws · Local fallback http://localhost / ws://localhost/ws

Authentication

Admin REST endpoints use a cookie session:

  • Cookie: linearvoid_admin_session — HttpOnly, SameSite=Strict, Secure when request is HTTPS (or X-Forwarded-Proto=https)
  • Session TTL: ADMIN_SESSION_TTL_HOURS (default 12h)

Chat WebSocket API

Connect: GET /ws?username={name}&room={room} — client/server exchange JSON messages.

Message (client→server) Field Notes
type public for room chat, private for DM routing; system for moderation/events
room main; private DMs use dm:userA-userB (usernames sorted)
username sender
text message body

Server→client envelope adds "timestamp" (ISO-8601, e.g. 2026-08-04T12:34:56Z).

{ "room": "main", "username": "viewer123", "text": "hello world", "type": "public" }

Admin Session API

Method & Path Auth Description
POST /api/admin/login none Authenticate
POST /api/admin/logout optional (clears cookie either way) Logout
GET /api/admin/session cookie required Session check; 401 if invalid

Login request:

{ "username": "admin", "password": "your-password" }

Login/logout/session success response (session returns 401 on failure):

{ "authenticated": true, "username": "admin" }

Logout response: { "authenticated": false }

Admin Data API (auth required)

Method & Path Returns
GET /api/admin/overview Aggregate counters + runtime/system snapshot
GET /api/admin/playlist Playlist
PUT /api/admin/playlist Set playlist (body: { "content": "file '/app/media/video1.mp4'\nfile '/app/media/video2.mp4'\n" })
GET /api/admin/schedule Parsed playlist entries + matched media metadata/runtime
GET /api/admin/moderation/logs?limit=50 Moderation logs
POST /api/admin/moderation/actions Perform moderation action
GET /api/admin/analytics Totals (messages, moderation actions, rooms) + top room summary
GET /api/admin/system Health snapshot (chat/playout/redis/database) + config metadata
GET /api/admin/users Presence users (room + username) when Redis available

Moderation action request:

{ "action": "mute", "target": "username-or-id", "moderator": "admin", "reason": "spam", "room": "main" }

Media Library API

Method & Path Description
GET /api/admin/media List media
POST /api/admin/media Multipart upload (legacy), form field name file
GET /api/admin/media/{id} Get item
PUT /api/admin/media/{id} Update item
DELETE /api/admin/media/{id} Delete item

PUT media body:

{ "status": "ready", "title": "My Clip", "tags": "music,live" }

Resumable Upload API

Max file size: 2GB · Default chunk size: 8MB

Method & Path Description
POST /api/admin/media/uploads Initialize or resume session
GET /api/admin/media/uploads/{uploadId} Check upload status
PUT /api/admin/media/uploads/{uploadId}/chunk?index={chunkIndex} Upload chunk (Content-Type: application/octet-stream)
POST /api/admin/media/uploads/{uploadId}/complete Complete upload → returns media listing (files + generatedAt)

Initialize request:

{
  "uploadId": "optional-existing-id",
  "fileName": "clip.mp4",
  "fileSize": 123456789,
  "mimeType": "video/mp4",
  "chunkSize": 8388608,
  "totalChunks": 15
}

Status envelope (returned by init, status check, and chunk upload):

{
  "uploadId": "hex-token",
  "fileName": "clip.mp4",
  "fileSize": 123456789,
  "chunkSize": 8388608,
  "totalChunks": 15,
  "uploadedChunks": 3,
  "progress": 20
}

Metrics & Health

  • GET /metrics (chat) — Prometheus: connected clients, stored messages, moderation actions, Redis indicators, active admin sessions, build info
  • GET /health — chat service, playout service, and nginx reverse proxy each expose it

HTTP Status Conventions

Code Meaning When
200 OK Successful GET, PUT, action
201 Created Successful POST (upload init, override created)
204 No Content Successful DELETE, CORS preflight
400 Bad Request Malformed JSON, missing required fields, invalid input
401 Unauthorized Missing/expired admin session
403 Forbidden Valid session, insufficient permissions
404 Not Found Resource doesn't exist
405 Method Not Allowed Wrong method for endpoint
409 Conflict Schedule override overlap, upload ID mismatch
413 Payload Too Large Upload exceeds 2 GB limit
422 Unprocessable File fails normalization check (codec, fps, resolution)
429 Too Many Requests Rate limit exceeded (chat, WS, login)
500 Internal Server Error Unexpected server failure
503 Service Unavailable Redis unavailable for user actions, playout health degraded

Rate Limiting

Per-IP (from X-Forwarded-For or RemoteAddr) unless noted.

Resource Limit Window Response
Chat messages CHAT_RATE_LIMIT_MAX (default 10) CHAT_RATE_LIMIT_WINDOW_S (default 10s) 429 + {"type":"system","text":"Rate limit exceeded"}
WebSocket connections 5 60s 429 + "too many connections from this IP"
Admin login 5 5min 429 + "too many login attempts, try again later"

Rate limit headers (applicable responses): X-RateLimit-Limit (max requests/window), Retry-After (seconds until reset). 413 = payload too large; 500 = internal server error.