- 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
143 lines
3.4 KiB
Markdown
143 lines
3.4 KiB
Markdown
# Data Models
|
|
|
|
## Configuration Model
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```mermaid
|
|
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.
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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 --> [*]
|
|
```
|