- Fix metrics: change MessagesTotal, ConnectionsTotal, DisconnectionsTotal from Gauge to Counter with proper _total naming convention - Fix broadcast write-error handling: failed clients now get properly removed with accurate metrics updates - Add graceful shutdown: SIGINT/SIGTERM handling with 10s timeout, CloseGoingAway frame sent to clients before disconnect - Add integration tests: 11 tests using real WebSocket connections covering connect, broadcast, disconnect, concurrency, and shutdown - Fix example client port: changed from 8000 to 8443 to match config - Rewrite README.md to reflect current features and usage - Add AGENTS.md and .agents/summary/ documentation for AI assistants
135 lines
3.5 KiB
Markdown
135 lines
3.5 KiB
Markdown
# Architecture
|
|
|
|
## System Architecture Overview
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph Clients
|
|
C1[WebSocket Client 1]
|
|
C2[WebSocket Client 2]
|
|
C3[WebSocket Client N]
|
|
end
|
|
|
|
subgraph "WebSocket Relay Server"
|
|
EP[HTTP/TLS Endpoint]
|
|
HUB[Hub - Connection Manager]
|
|
BC[Broadcast Channel]
|
|
MET[Prometheus Metrics]
|
|
end
|
|
|
|
subgraph Monitoring
|
|
PROM[Prometheus Scraper]
|
|
end
|
|
|
|
C1 -->|ws/wss| EP
|
|
C2 -->|ws/wss| EP
|
|
C3 -->|ws/wss| EP
|
|
EP --> HUB
|
|
HUB --> BC
|
|
BC -->|relay to all| C1
|
|
BC -->|relay to all| C2
|
|
BC -->|relay to all| C3
|
|
HUB --> MET
|
|
MET -->|:9090/metrics| PROM
|
|
```
|
|
|
|
## Design Pattern: Hub-and-Spoke
|
|
|
|
The application uses a **Hub-and-Spoke** (fan-out) pattern where:
|
|
|
|
1. **Hub** is the central coordinator managing all WebSocket connections
|
|
2. **Spokes** are individual WebSocket client connections
|
|
3. Every message received from any client is **broadcast to all connected clients**
|
|
|
|
```mermaid
|
|
graph LR
|
|
subgraph Hub
|
|
REG[Register Channel]
|
|
UNREG[Unregister Channel]
|
|
BCAST[Broadcast Channel]
|
|
CLIENTS[Client Map]
|
|
end
|
|
|
|
CONN[New Connection] --> REG
|
|
REG --> CLIENTS
|
|
DISC[Disconnection] --> UNREG
|
|
UNREG --> CLIENTS
|
|
MSG[Incoming Message] --> BCAST
|
|
BCAST --> CLIENTS
|
|
```
|
|
|
|
## Concurrency Model
|
|
|
|
The server uses Go's CSP (Communicating Sequential Processes) concurrency model:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Handler as HTTP Handler
|
|
participant Hub as Hub.Run() goroutine
|
|
participant Reader as ReadMessage goroutine
|
|
|
|
Client->>Handler: HTTP Upgrade Request
|
|
Handler->>Hub: register <- conn
|
|
Hub->>Hub: Add to clients map
|
|
Handler->>Reader: Start goroutine
|
|
|
|
loop Read Messages
|
|
Client->>Reader: WebSocket Frame
|
|
Reader->>Hub: broadcast <- message
|
|
Hub->>Hub: Iterate clients map
|
|
Hub->>Client: WriteMessage (fan-out)
|
|
end
|
|
|
|
Reader->>Hub: unregister <- conn (on error/close)
|
|
Hub->>Hub: Remove from clients map
|
|
```
|
|
|
|
### Goroutine Lifecycle
|
|
|
|
| Goroutine | Purpose | Lifetime |
|
|
|-----------|---------|----------|
|
|
| `main` | HTTP server, accepts connections | Application lifetime |
|
|
| `Hub.Run()` | Processes register/unregister/broadcast channels | Application lifetime |
|
|
| Per-client reader | Reads messages from a single client | Client connection lifetime |
|
|
| Metrics server | Serves `/metrics` endpoint | Application lifetime (if enabled) |
|
|
|
|
## Configuration Architecture
|
|
|
|
```mermaid
|
|
graph LR
|
|
CLI[CLI Flag: --config-file] --> LOAD[config.Load]
|
|
LOAD --> YAML[YAML Parser]
|
|
YAML --> CFG[Config Struct]
|
|
CFG --> SRV[Server Setup]
|
|
CFG --> TLS[TLS Config]
|
|
CFG --> MET[Metrics Setup]
|
|
```
|
|
|
|
## Security Model
|
|
|
|
- **TLS Support**: Optional TLS via cert/key PEM files
|
|
- **Origin Check**: `CheckOrigin` allows all origins (permissive for relay use case)
|
|
- **No Authentication**: The relay is designed as a transparent message forwarder
|
|
- **No Authorization**: All connected clients can send/receive all messages
|
|
|
|
## Deployment Architecture
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Build Pipeline"
|
|
SRC[Source Code] --> CI[Gitea CI]
|
|
CI --> TEST[go test]
|
|
CI --> LINT[golangci-lint]
|
|
TAG[Git Tag v*] --> REL[Release Pipeline]
|
|
REL --> BIN_L[Linux amd64 Binary]
|
|
REL --> BIN_M[macOS arm64 Binary]
|
|
end
|
|
|
|
subgraph "Runtime"
|
|
BIN[Binary] --> CFG[config.yaml]
|
|
CFG --> SERVER[WebSocket Server :8443]
|
|
CFG --> METRICS[Metrics Server :9090]
|
|
end
|
|
```
|