milord 04833daaef
Build Test / checks (push) Successful in 2m30s
Build Test / image (push) Successful in 2m7s
Build Test / create-test-tag (push) Successful in 5s
chore: trigger
2026-07-12 22:03:31 +03:00
2026-07-12 22:02:20 +03:00
2026-07-11 01:18:53 +03:00
2026-07-11 01:18:53 +03:00
2026-07-11 01:18:53 +03:00
2026-06-14 02:04:25 +03:00
2026-07-12 22:03:31 +03:00
2026-07-11 01:18:53 +03:00
2026-06-14 02:04:25 +03:00
2026-06-14 02:04:25 +03:00
2026-07-11 01:18:53 +03:00
2026-06-14 02:04:25 +03:00
2026-07-11 01:18:53 +03:00
2026-07-11 01:18:53 +03:00
2026-07-11 01:18:53 +03:00

WebRTC Combine

Go backend for temporary multi-participant WebRTC calls backed by a LiveKit SFU.

Architecture

  • The Go service owns the public API, room ids, and short-lived LiveKit access tokens.
  • LiveKit is the SFU. It handles WebRTC transport, track forwarding, subscriptions, screen sharing, and data messages.
  • No registration is required.
  • The service stores temporary room metadata in Redis and removes rooms only after their minimum lifetime has elapsed and LiveKit reports no connected participants.
  • Chat uses LiveKit data messages. Messages are not persisted; uploaded chat files are retained temporarily by the API.
  • Recording is not configured. LiveKit Egress can be added later when recording is needed.

Local Run

Start the Go API and LiveKit SFU in one Docker network:

docker-compose up --build

The Go container talks to the SFU by service name: http://livekit:7880.

For local development without Docker, start LiveKit first and then run:

go run ./cmd/server

Defaults are configured for LiveKit dev mode:

  • LIVEKIT_API_URL=http://localhost:7880
  • LIVEKIT_PUBLIC_URL=ws://localhost:7880
  • LIVEKIT_API_KEY=devkey
  • LIVEKIT_API_SECRET=secret

Other environment variables:

  • ADDR: HTTP listen address, default :8080.
  • API_PUBLIC_URL: base URL used in generated API join links, default http://localhost:8080.
  • API_BASE_PATH: path prefix handled by the API itself, for example /api; empty by default.
  • DOCS_DIR: OpenAPI directory, default docs.
  • LIVEKIT_API_URL: backend URL for LiveKit server API, for example http://livekit:7880 in Docker.
  • LIVEKIT_PUBLIC_URL: URL returned to clients for LiveKit SDK connection, for example ws://localhost:7880.
  • MAX_PARTICIPANTS_PER_ROOM: LiveKit room participant limit, default 20.
  • ROOM_TTL: minimum room lifetime and occupied-room extension, default 2h.
  • ROOM_CLEANUP_INTERVAL: how often the background cleanup worker checks due rooms, default 1m.
  • ROOM_CLEANUP_BATCH_SIZE: maximum rooms inspected during one cleanup pass, default 100.
  • JOIN_TOKEN_TTL: validity period of a generated LiveKit join token, default 15m.
  • FILE_TTL: how long uploaded chat files remain downloadable, default 2h.
  • MAX_FILE_SIZE_MB: maximum uploaded file size in MiB, default 25.
  • FILE_STORAGE_TYPE: local or s3; defaults to local.
  • FILE_STORAGE_DIR: local backend directory, default is the operating system temporary directory.
  • S3_ENDPOINT: S3-compatible endpoint without a URL scheme, for example minio:9000.
  • S3_ACCESS_KEY / S3_SECRET_KEY: S3 credentials; keep the secret key in a Secret.
  • S3_BUCKET: file bucket, default meet-chat-files; it is created automatically when missing.
  • S3_REGION: S3 region, default us-east-1.
  • S3_USE_SSL: use TLS for the backend S3 connection, default false.
  • S3_UPLOAD_TEMP_DIR: temporary staging directory used while enforcing the upload limit.
  • ALLOWED_ORIGINS: comma-separated browser origins allowed by CORS.
  • REDIS_ADDR: Redis address, required in production, for example meet-redis:6379.
  • REDIS_USERNAME: optional Redis ACL username.
  • REDIS_PASSWORD: optional Redis password; keep it in a Secret.
  • REDIS_DB: Redis logical database, default 0.
  • REDIS_KEY_PREFIX: key prefix, default webrtc-combine.

Local development falls back to an in-memory room store when REDIS_ADDR is empty. Production refuses to start without Redis.

Use separate Redis instances for test and production. Room records are stored as:

<REDIS_KEY_PREFIX>:room:<public-room-id>

Room records do not use Redis key TTL. A sorted-set cleanup queue schedules the first check after ROOM_TTL. The worker deletes a due room only when LiveKit reports no connected participants. Occupied rooms are rescheduled for another ROOM_TTL, and join requests also extend the room lifetime.

Production

Create the secret environment file and replace the LiveKit credentials with an API key pair configured on the production LiveKit server:

cp .env.production.example .env.production
chmod 600 .env.production

Add the same dedicated API key pair from .env.production to the production LiveKit configuration:

keys:
  "<LIVEKIT_API_KEY>": "<LIVEKIT_API_SECRET>"

Restart LiveKit after changing its key configuration. Do not commit or send .env.production; it is ignored by Git.

Deploy the API behind the existing Traefik instance:

docker-compose --env-file .env.production -f docker-compose.production.yml up -d --build

The production route is handled natively by the application:

https://meet.apps.4vkamnyam.ru/api/* → Ingress → API:8080/api/*

Ingress must not rewrite or strip /api. Kubernetes probes can use /health without the prefix. The API calls LiveKit through https://livekit.4vkamnyam.ru; clients receive wss://livekit.4vkamnyam.ru.

HTTP API

Create a room:

curl -X POST http://localhost:8080/rooms

Join a room by nickname and receive LiveKit connection parameters:

curl -X POST http://localhost:8080/rooms/{roomId}/join \
  -H 'Content-Type: application/json' \
  -d '{"name":"alex"}'

Get room state:

curl http://localhost:8080/rooms/{roomId}

Upload a file for the room chat:

curl -X POST http://localhost:8080/rooms/{roomId}/files \
  -F 'file=@./document.pdf'

The response contains chatMessage. Publish that object as JSON through a reliable LiveKit data message. Recipients can render it as a file attachment and use chatMessage.file.url to download the file.

Open Swagger UI:

http://localhost:8080/swagger

Client Notes

The frontend should connect to LiveKit with the returned livekitUrl and token.

The token grants:

  • room join for the generated LiveKit room;
  • publish camera and microphone tracks;
  • publish screen-share and screen-share-audio tracks;
  • subscribe to other participants;
  • publish data messages for in-session chat.

Uploaded files are not sent through the LiveKit data channel. The API stores up to 25 MiB per file and the chat message contains only file metadata and a download URL. Local storage is suitable for development and a single API replica. The S3 backend supports multiple API replicas and works with MinIO or another S3-compatible object store.

The shareable link should contain the public roomId. The client can ask for a nickname, call POST /rooms/{roomId}/join, then connect to LiveKit.

S
Description
No description provided
Readme 94 KiB
Languages
Go 99.4%
Dockerfile 0.6%