CodeQL Dependabot Updates Dependency Graph Go Format Check (format.yml) Lint Go Code (lint.yml)
A lightweight WebSocket gateway for delivering real-time messages to players, with server-side publishing, offline queueing, rate limiting, and Prometheus metrics.
- WebSocket connections per player (multiple connections supported)
- Token-based authentication (players & servers)
- Offline message queue with TTL
- Per-server-token rate limiting
- Broadcast and targeted messaging
- Automatic token revalidation
- Prometheus metrics endpoint
- Graceful shutdown
- Players connect via WebSocket (
/ws) using player tokens - Servers publish messages via HTTP (
/publish,/broadcast) using server tokens - Tokens are validated against a SQL database
- Messages are delivered immediately or queued if the player is offline
GET /ws?token=PLAYER_TOKEN
POST /publish- Header:
Authorization: Bearer SERVER_TOKEN - Body:
{
"player_id": "1",
"event": "event_name",
"payload": { "any": "json" }
}POST /broadcast- Header:
Authorization: Bearer SERVER_TOKEN - Body (all players):
{
"event": "event_name",
"payload": { "any": "json" }
}- Body (single player):
{
"player_id": "1",
"event": "event_name",
"payload": { "any": "json" }
}GET /metrics(Prometheus format)
-addr– Server address (default:8080)-db– Database driver (defaultsqlite)-dsn– Database DSN (defaultfile:ws_tokens.db?cache=shared)-origins– Comma-separated allowed WS origins-log-file– Path to log file-log-level– Log level (defaultinfo)-pid-file– Path to PID file-max-conns– Max WS connections per player (default10)-max-queued– Max offline queued messages per player (default100)-offline-ttl– Offline message TTL (default10s)-rate-limit– Messages per rate period per server token (default200)-rate-period– Rate limit window (default1s)-revalidate-period– Token revalidation interval (default1m)-daemon– Run process as a daemon
Required table:
CREATE TABLE IF NOT EXISTS ws_token ( token VARBINARY(32) NOT NULL PRIMARY KEY, player_id INTEGER(10) UNSIGNED DEFAULT NULL, subject_id VARBINARY(32) NOT NULL, is_server BOOLEAN NOT NULL, expires_at DATETIME(6) NOT NULL ); CREATE INDEX idx_ws_token_server_exp ON ws_token (is_server, expires_at);
player_idis used for player tokenssubject_idis used for server tokens
ws_active_connectionsws_messages_published_totalws_messages_delivered_total
go build ./ws-server \ -db sqlite \ -dsn file:ws_tokens.db?cache=shared # or ./ws-server \ -db mysql \ -dsn "root@/echoCTF"
- Designed to be stateless except for in-memory queues
- Offline messages are best-effort (not persisted)
- Suitable for game backends, notification systems, and real-time apps