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

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 --> [*]