- 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
3.4 KiB
3.4 KiB
Data Models
Configuration Model
classDiagram
class Config {
+Server ServerConfig
+Metrics MetricsConfig
}
class ServerConfig {
+int Port
+TLSConfig TLS
}
class TLSConfig {
+bool Enabled
+string CertFile
+string KeyFile
}
class MetricsConfig {
+bool Enabled
+int Port
}
Config --> ServerConfig
Config --> MetricsConfig
ServerConfig --> TLSConfig
Config Struct Definition
type Config struct {
Server struct {
Port int `yaml:"port"`
TLS struct {
Enabled bool `yaml:"enabled"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
} `yaml:"tls"`
} `yaml:"server"`
Metrics struct {
Enabled bool `yaml:"enabled"`
Port int `yaml:"port"`
} `yaml:"metrics"`
}
Default Configuration Values
| Field | Default | Notes |
|---|---|---|
server.port |
8443 | Standard alternate HTTPS port |
server.tls.enabled |
false (config.yaml) / true (example) | Toggle TLS |
server.tls.cert_file |
cert.pem |
Relative to working directory |
server.tls.key_file |
key.pem |
Relative to working directory |
metrics.enabled |
true | Prometheus metrics |
metrics.port |
9090 | Standard Prometheus port |
Hub State Model
classDiagram
class Hub {
-map~*websocket.Conn, bool~ clients
-chan []byte broadcast
-chan *websocket.Conn register
-chan *websocket.Conn unregister
-sync.RWMutex mu
+New() Hub
+Run()
+HandleWebSocket(w, r)
+ClientCount() int
}
Channel Types
| Channel | Direction | Payload | Buffer |
|---|---|---|---|
register |
Handler → Hub | *websocket.Conn |
Unbuffered |
unregister |
Reader → Hub | *websocket.Conn |
Unbuffered |
broadcast |
Reader → Hub | []byte |
Unbuffered |
Message Model
The relay server does not impose any message structure. Messages are raw []byte payloads passed through as WebSocket text frames.
graph LR
A[Client A sends bytes] --> B[Hub broadcast channel]
B --> C[Written as TextMessage to all clients]
The example HTML client uses an informal format:
{name}<br>{message_text}
But this is purely client-side convention — the server is format-agnostic.
Metrics Model
classDiagram
class PrometheusMetrics {
+Gauge ConnectedClients
+Gauge MessagesTotal
+Gauge ConnectionsTotal
+Gauge DisconnectionsTotal
}
| Metric | Update Trigger |
|---|---|
ConnectedClients |
Set on register/unregister (absolute count) |
MessagesTotal |
Incremented on each broadcast |
ConnectionsTotal |
Incremented on register |
DisconnectionsTotal |
Incremented on unregister |
Connection State Machine
stateDiagram-v2
[*] --> Connecting: HTTP request to /
Connecting --> Connected: WebSocket upgrade success
Connecting --> Failed: Upgrade error
Connected --> Active: Registered in Hub
Active --> Active: Sending/Receiving messages
Active --> Disconnecting: Read error or client close
Disconnecting --> Closed: Unregistered from Hub
Failed --> [*]
Closed --> [*]