package realtime import ( "log" "net/http" "sync" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { // TODO: Restrict origins in production return true }, } // Client represents a single WebSocket connection. type Client struct { hub *Hub conn *websocket.Conn send chan []byte } // Hub manages WebSocket connections and broadcasts. type Hub struct { clients map[*Client]bool broadcast chan []byte register chan *Client unregister chan *Client mu sync.RWMutex } // NewHub creates a new Hub instance. func NewHub() *Hub { return &Hub{ clients: make(map[*Client]bool), broadcast: make(chan []byte), register: make(chan *Client), unregister: make(chan *Client), } } // Run starts the hub event loop. func (h *Hub) Run() { for { select { case client := <-h.register: h.mu.Lock() h.clients[client] = true h.mu.Unlock() log.Printf("Client connected. Total: %d", len(h.clients)) case client := <-h.unregister: h.mu.Lock() if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } h.mu.Unlock() log.Printf("Client disconnected. Total: %d", len(h.clients)) case message := <-h.broadcast: h.mu.RLock() for client := range h.clients { select { case client.send <- message: default: close(client.send) delete(h.clients, client) } } h.mu.RUnlock() } } } // Broadcast sends a message to all connected clients. func (h *Hub) Broadcast(message []byte) { h.broadcast <- message } // HandleWebSocket upgrades an HTTP connection to WebSocket. func HandleWebSocket(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("WebSocket upgrade error: %v", err) return } client := &Client{ hub: hub, conn: conn, send: make(chan []byte, 256), } hub.register <- client go client.writePump() go client.readPump() } func (c *Client) readPump() { defer func() { c.hub.unregister <- c c.conn.Close() }() for { _, message, err := c.conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) { log.Printf("WebSocket read error: %v", err) } break } // TODO: Route messages to appropriate handlers log.Printf("Received message: %s", message) } } func (c *Client) writePump() { defer c.conn.Close() for message := range c.send { if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil { log.Printf("WebSocket write error: %v", err) return } } }