savinmax 905c241daa
Some checks failed
CI / test (push) Successful in 54s
CI / lint (push) Failing after 3m16s
Improve reliability, testing, and documentation
- 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
2026-06-11 19:14:19 +02:00

148 lines
3.9 KiB
Markdown

# Components
## Component Overview
```mermaid
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:**
1. Parses CLI flags (`--config-file`)
2. Loads YAML configuration
3. Creates and starts the Hub
4. Optionally starts the metrics HTTP server on a separate port
5. 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
```mermaid
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`
```go
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.NewGauge` for 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 |