- Created README.md in docs folder outlining project structure and documentation links. - Added SECURITY.md detailing the security model, threat model, authentication, transport security, network isolation, and incident response procedures. - Introduced SETUP.md providing a detailed setup guide for local and production environments, including prerequisites, environment setup, and Gitea integration. - Added STREAMING.md outlining the streaming pipeline, including production flow, source-media contract, playout and HLS packaging, cache contract, player behavior, and monitoring. - Updated architecture documentation to include links to new SETUP.md and STREAMING.md files for better navigation.
308 lines
7.0 KiB
Markdown
308 lines
7.0 KiB
Markdown
# API Reference
|
|
|
|
This document describes the currently implemented API surfaces in Linear Void.
|
|
|
|
## Base URLs
|
|
|
|
- Public app and admin: <https://linearvoid.tv>
|
|
- WebSocket endpoint: <wss://linearvoid.tv/ws>
|
|
- Local fallback: <http://localhost> and <ws://localhost/ws>
|
|
|
|
## Authentication Model
|
|
|
|
Admin REST endpoints use a cookie session.
|
|
|
|
- Cookie name: linearvoid_admin_session
|
|
- Cookie attributes: HttpOnly, SameSite=Strict, Secure when request is HTTPS (or X-Forwarded-Proto=https)
|
|
- Session TTL: controlled by ADMIN_SESSION_TTL_HOURS (default 12h)
|
|
|
|
## Chat WebSocket API
|
|
|
|
### Connect
|
|
|
|
Endpoint:
|
|
|
|
- GET /ws?username={name}&room={room}
|
|
|
|
Client sends JSON messages over the socket.
|
|
|
|
### Message Envelope (client -> server)
|
|
|
|
```json
|
|
{
|
|
"room": "main",
|
|
"username": "viewer123",
|
|
"text": "hello world",
|
|
"type": "public"
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- type is usually public for room chat and private for DM room routing.
|
|
- Private room names are formatted like dm:userA-userB (sorted usernames).
|
|
- Moderation/system events are sent as type=system messages.
|
|
|
|
### Message Envelope (server -> client)
|
|
|
|
```json
|
|
{
|
|
"room": "main",
|
|
"username": "viewer123",
|
|
"text": "hello world",
|
|
"type": "public",
|
|
"timestamp": "2026-08-04T12:34:56Z"
|
|
}
|
|
```
|
|
|
|
## Admin Session API
|
|
|
|
### Login
|
|
|
|
- POST /api/admin/login
|
|
- Auth: none
|
|
|
|
Request:
|
|
|
|
```json
|
|
{
|
|
"username": "admin",
|
|
"password": "your-password"
|
|
}
|
|
```
|
|
|
|
Success response:
|
|
|
|
```json
|
|
{
|
|
"authenticated": true,
|
|
"username": "admin"
|
|
}
|
|
```
|
|
|
|
### Logout
|
|
|
|
- POST /api/admin/logout
|
|
- Auth: optional (clears cookie either way)
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"authenticated": false
|
|
}
|
|
```
|
|
|
|
### Session Check
|
|
|
|
- GET /api/admin/session
|
|
- Auth: cookie required
|
|
|
|
Success response:
|
|
|
|
```json
|
|
{
|
|
"authenticated": true,
|
|
"username": "admin"
|
|
}
|
|
```
|
|
|
|
Failure:
|
|
|
|
- 401 unauthorized
|
|
|
|
## Admin Data API
|
|
|
|
All endpoints below require admin authentication.
|
|
|
|
### Overview
|
|
|
|
- GET /api/admin/overview
|
|
|
|
Returns aggregate counters and runtime/system snapshot fields.
|
|
|
|
### Playlist
|
|
|
|
- GET /api/admin/playlist
|
|
- PUT /api/admin/playlist
|
|
|
|
PUT request:
|
|
|
|
```json
|
|
{
|
|
"content": "file '/app/media/video1.mp4'\nfile '/app/media/video2.mp4'\n"
|
|
}
|
|
```
|
|
|
|
### Schedule
|
|
|
|
- GET /api/admin/schedule
|
|
|
|
Returns parsed playlist entries plus matched media metadata/runtime.
|
|
|
|
### Moderation
|
|
|
|
- GET /api/admin/moderation/logs?limit=50
|
|
- POST /api/admin/moderation/actions
|
|
|
|
Action request:
|
|
|
|
```json
|
|
{
|
|
"action": "mute",
|
|
"target": "username-or-id",
|
|
"moderator": "admin",
|
|
"reason": "spam",
|
|
"room": "main"
|
|
}
|
|
```
|
|
|
|
### Analytics
|
|
|
|
- GET /api/admin/analytics
|
|
|
|
Returns totals (messages, moderation actions, rooms) and top room summary.
|
|
|
|
### System
|
|
|
|
- GET /api/admin/system
|
|
|
|
Returns service health snapshot for chat/playout/redis/database and config metadata.
|
|
|
|
### Active Users
|
|
|
|
- GET /api/admin/users
|
|
|
|
Returns currently discovered presence users (room + username) when Redis is available.
|
|
|
|
## Media Library API
|
|
|
|
### Media Collection
|
|
|
|
- GET /api/admin/media
|
|
- POST /api/admin/media (multipart upload, legacy path)
|
|
|
|
Multipart form field name: file
|
|
|
|
### Media Item
|
|
|
|
- GET /api/admin/media/{id}
|
|
- PUT /api/admin/media/{id}
|
|
- DELETE /api/admin/media/{id}
|
|
|
|
PUT request:
|
|
|
|
```json
|
|
{
|
|
"status": "ready",
|
|
"title": "My Clip",
|
|
"tags": "music,live"
|
|
}
|
|
```
|
|
|
|
## Resumable Upload API
|
|
|
|
Maximum file size: 2GB
|
|
|
|
Default chunk size: 8MB
|
|
|
|
### Initialize or Resume Session
|
|
|
|
- POST /api/admin/media/uploads
|
|
|
|
Request:
|
|
|
|
```json
|
|
{
|
|
"uploadId": "optional-existing-id",
|
|
"fileName": "clip.mp4",
|
|
"fileSize": 123456789,
|
|
"mimeType": "video/mp4",
|
|
"chunkSize": 8388608,
|
|
"totalChunks": 15
|
|
}
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"uploadId": "hex-token",
|
|
"fileName": "clip.mp4",
|
|
"fileSize": 123456789,
|
|
"chunkSize": 8388608,
|
|
"totalChunks": 15,
|
|
"uploadedChunks": 3,
|
|
"progress": 20
|
|
}
|
|
```
|
|
|
|
### Check Upload Status
|
|
|
|
- GET /api/admin/media/uploads/{uploadId}
|
|
|
|
Returns same status envelope as initialize.
|
|
|
|
### Upload Chunk
|
|
|
|
- PUT /api/admin/media/uploads/{uploadId}/chunk?index={chunkIndex}
|
|
- Content-Type: application/octet-stream
|
|
|
|
Response returns updated upload status envelope.
|
|
|
|
### Complete Upload
|
|
|
|
- POST /api/admin/media/uploads/{uploadId}/complete
|
|
|
|
On success returns admin media listing payload (files + generatedAt).
|
|
|
|
## Metrics and Health
|
|
|
|
### Chat metrics
|
|
|
|
- GET /metrics
|
|
|
|
Prometheus exposition includes connected clients, stored messages, moderation actions, Redis indicators, active admin sessions, and build info.
|
|
|
|
### Health
|
|
|
|
- GET /health on chat service
|
|
- GET /health on playout service
|
|
- GET /health on nginx reverse proxy
|
|
|
|
## HTTP Status Conventions
|
|
|
|
| Code | Meaning | When |
|
|
| ---- | --------------------- | ----------------------------------------------------------- |
|
|
| 200 | OK | Successful GET, PUT, or 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 or expired admin session |
|
|
| 403 | Forbidden | Valid session but insufficient permissions |
|
|
| 404 | Not Found | Resource doesn't exist |
|
|
| 405 | Method Not Allowed | Wrong HTTP 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 messages, WS connections, login) |
|
|
| 500 | Internal Server Error | Unexpected server failure |
|
|
| 503 | Service Unavailable | Redis unavailable for user actions, playout health degraded |
|
|
|
|
## Rate Limiting
|
|
|
|
All limits are 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 on applicable responses:
|
|
|
|
- `X-RateLimit-Limit`: maximum requests per window
|
|
- `Retry-After`: seconds until window resets
|
|
- 413: payload too large
|
|
- 500: internal server error
|