- 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.9 KiB
3.9 KiB
Components
Component Overview
graph TB
subgraph "main (Entry Point)"
MAIN[main.go]
end
subgraph "internal/config"
CFG[Config Loader]
end
subgraph "internal/hub"
HUB[Hub Manager]
WS[WebSocket Handler]
end
subgraph "internal/metrics"
MET[Prometheus Metrics]
end
MAIN --> CFG
MAIN --> HUB
MAIN --> MET
HUB --> WS
HUB --> MET
Package: main
File: main.go
Responsibility: Application entry point and server initialization.
Behavior:
- Parses CLI flags (
--config-file) - Loads YAML configuration
- Creates and starts the Hub
- Optionally starts the metrics HTTP server on a separate port
- Starts the WebSocket HTTP/TLS server
Dependencies: internal/config, internal/hub, prometheus/client_golang
Package: internal/hub
File: internal/hub/hub.go
Responsibility: WebSocket connection lifecycle management and message broadcasting.
Struct: Hub
| Field | Type | Purpose |
|---|---|---|
clients |
map[*websocket.Conn]bool |
Set of active connections |
broadcast |
chan []byte |
Channel for messages to relay |
register |
chan *websocket.Conn |
Channel for new connections |
unregister |
chan *websocket.Conn |
Channel for disconnections |
mu |
sync.RWMutex |
Protects the clients map |
Methods
| Method | Signature | Description |
|---|---|---|
New |
func New() *Hub |
Constructor, initializes all channels and map |
Run |
func (h *Hub) Run() |
Main event loop processing channels (blocking) |
HandleWebSocket |
func (h *Hub) HandleWebSocket(w, r) |
HTTP handler — upgrades connection and starts reader |
ClientCount |
func (h *Hub) ClientCount() int |
Returns current connected client count (thread-safe) |
Connection Flow
stateDiagram-v2
[*] --> HTTPRequest: Client connects
HTTPRequest --> Upgraded: WebSocket upgrade
Upgraded --> Registered: register channel
Registered --> Reading: goroutine loop
Reading --> Broadcasting: message received
Broadcasting --> Reading: continue
Reading --> Unregistered: error/close
Unregistered --> [*]: connection cleaned up
Package: internal/config
File: internal/config/config.go
Responsibility: YAML configuration file loading and parsing.
Struct: Config
type Config struct {
Server struct {
Port int
TLS struct {
Enabled bool
CertFile string
KeyFile string
}
}
Metrics struct {
Enabled bool
Port int
}
}
Functions
| Function | Signature | Description |
|---|---|---|
Load |
func Load(filename string) (*Config, error) |
Reads and parses YAML config file |
Package: internal/metrics
File: internal/metrics/metrics.go
Responsibility: Prometheus metrics registration and exposure.
Metrics Defined
| Variable | Prometheus Type | Metric Name | Description |
|---|---|---|---|
ConnectedClients |
Gauge | websocket_connected_clients |
Current number of connected clients |
MessagesTotal |
Gauge | websocket_message |
Total messages processed |
ConnectionsTotal |
Gauge | websocket_connection |
Total connections established |
DisconnectionsTotal |
Gauge | websocket_disconnection |
Total disconnections |
Note: All metrics use
promauto.NewGaugefor auto-registration. The "total" metrics use Gauge instead of Counter, which means they track cumulative counts but will reset on restart.
Test Coverage
| Package | Test File | Tests |
|---|---|---|
internal/hub |
hub_test.go |
TestNew, TestClientCount, TestBroadcastChannel |
internal/config |
config_test.go |
TestLoad, TestLoadFileNotFound |
internal/metrics |
— | No dedicated tests |