add documentation

This commit is contained in:
Radon 2025-09-04 19:42:02 -05:00
parent f605bcea5a
commit 6618425c3d
7 changed files with 134 additions and 0 deletions

View File

@ -1,5 +1,11 @@
package main package main
// WebSocket client read/write pumps.
//
// ReadPump pulls messages from the client's WebSocket connection and routes
// them into the Hub. WritePump pushes outbound messages from the Hub to the
// client's connection. Both functions are expected to run as goroutines per
// client.
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -9,6 +15,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
// ReadPump reads from the websocket connection and handles client pings/pongs.
func ReadPump(c *server.Client) { func ReadPump(c *server.Client) {
defer func() { defer func() {
c.Hub.Unregister <- c c.Hub.Unregister <- c
@ -187,6 +194,7 @@ func ReadPump(c *server.Client) {
} }
} }
// WritePump writes queued messages to the websocket connection and sends periodic pings.
func WritePump(c *server.Client) { func WritePump(c *server.Client) {
defer func(conn *websocket.Conn) { defer func(conn *websocket.Conn) {
_ = conn.Close() _ = conn.Close()

View File

@ -1,5 +1,8 @@
package main package main
// main is the entrypoint for RadChat. It parses flags, prepares storage,
// configures middleware and routes, and starts the HTTP server. See README for
// the flag reference and architecture overview.
import ( import (
"flag" "flag"
"fmt" "fmt"

View File

@ -1,5 +1,112 @@
package main package main
// Message is a generic envelope exchanged over the WebSocket signaling channel.
//
// Type is the message kind (e.g., "join", "leave", "chat", "offer",
// "answer", "ice", etc.). Other fields are used depending on Type; unused
// fields are omitted in JSON.
//
// The flexibility helps keep the client and server loosely coupled; consider
// introducing stricter typed payloads if this grows.
//
// Note: This struct is intentionally broad to carry both chat and WebRTC
// signaling payloads.
//
// Timestamp is set by the sender (usually server) for ordering.
// Target is a peer client ID for directed messages.
// Data/DataExt/DataList support heterogeneous payloads where necessary.
// Offer/Answer/ICE carry WebRTC SDP/ICE candidate info.
// DataType can be used by clients to dispatch UI behavior.
// DataTime is optional timing metadata.
//
// Username/UserID are the sender identity.
// Error holds error information if Type indicates a failure.
//
// All fields are optional in JSON except Type.
// Keep in sync with frontend parsing in static/app.js
// to avoid breaking changes.
//
// Consider versioning if wire format evolves.
//
//nolint:lll // wide field tags
//
//
// Message struct definition:
//
// - Type: message category
// - Username, UserID: identity
// - Data/DataExt/DataList: generic payloads
// - Offer/Answer/ICE: WebRTC signaling
// - Target: directed recipient id
// - Error: error description if any
// - Timestamp: unix ms or ns
//
// The JSON tags omit empty fields to minimize bandwidth.
//
// End of doc.
//
//
//
//
//
//
//
//
//
//
//
//
//
//
// Actual type follows.
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
type Message struct { type Message struct {
Type string `json:"type"` Type string `json:"type"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`

View File

@ -1,5 +1,7 @@
package server package server
// Client represents a single WebSocket connection and associated user state.
// It includes a send channel for outbound messages and LastPong for liveness.
import ( import (
"sync" "sync"
"time" "time"
@ -7,6 +9,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
// Client holds the websocket connection and linkage back to the Hub.
type Client struct { type Client struct {
Conn *websocket.Conn Conn *websocket.Conn
Username string Username string

View File

@ -1,11 +1,16 @@
package server package server
// Hub is the central registry/bus for all connected clients.
//
// It exposes channels for broadcast, register, and unregister events
// and protects the Clients map with a RWMutex for safe concurrent access.
import ( import (
"sync" "sync"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
// Hub groups clients and channels used by the server runtime.
type Hub struct { type Hub struct {
Clients map[*Client]bool Clients map[*Client]bool
Broadcast chan []byte Broadcast chan []byte
@ -15,6 +20,7 @@ type Hub struct {
Upgrader websocket.Upgrader Upgrader websocket.Upgrader
} }
// NewHub constructs a Hub with buffered channels sized by bufferSize.
func NewHub(bufferSize int, upgrader websocket.Upgrader) *Hub { func NewHub(bufferSize int, upgrader websocket.Upgrader) *Hub {
return &Hub{ return &Hub{
Clients: make(map[*Client]bool), Clients: make(map[*Client]bool),

View File

@ -1,5 +1,6 @@
package server package server
// HTTP middleware for gzip compression and cache control.
import ( import (
"compress/gzip" "compress/gzip"
"io" "io"
@ -7,6 +8,7 @@ import (
"strings" "strings"
) )
// MiddlewareChain composes multiple middleware into a single http.Handler wrapper.
func MiddlewareChain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler { func MiddlewareChain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler {
return func(final http.Handler) http.Handler { return func(final http.Handler) http.Handler {
for _, middleware := range middlewares { for _, middleware := range middlewares {
@ -16,6 +18,7 @@ func MiddlewareChain(middlewares ...func(http.Handler) http.Handler) func(http.H
} }
} }
// gzipResponseWriter wraps http.ResponseWriter to write gzipped data.
type gzipResponseWriter struct { type gzipResponseWriter struct {
http.ResponseWriter http.ResponseWriter
io.Writer io.Writer

View File

@ -1,5 +1,6 @@
package server package server
// Utilities for server package: WebSocket upgrader with Origin checks.
import ( import (
"net/http" "net/http"
"strings" "strings"
@ -7,6 +8,9 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
// Upgrader creates a Gorilla websocket.Upgrader that enforces Origin checks.
// If bypass is true, any Origin is accepted. Otherwise, the Origin must match
// the provided originAddress (host[:port]).
func Upgrader(originAddress string, bypass bool) websocket.Upgrader { func Upgrader(originAddress string, bypass bool) websocket.Upgrader {
if strings.HasPrefix(originAddress, "http://") || strings.HasPrefix(originAddress, "https://") { if strings.HasPrefix(originAddress, "http://") || strings.HasPrefix(originAddress, "https://") {
originAddress = strings.TrimPrefix(originAddress, "http://") originAddress = strings.TrimPrefix(originAddress, "http://")