package ws import ( "log" "net/http" "sync" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } type Hub struct { mu sync.RWMutex clients map[*websocket.Conn]bool } func NewHub() *Hub { return &Hub{ clients: make(map[*websocket.Conn]bool), } } func (h *Hub) Run() { // Hub is passive — broadcasts are push-based via Broadcast() select {} } func (h *Hub) Register(conn *websocket.Conn) { h.mu.Lock() h.clients[conn] = true h.mu.Unlock() } func (h *Hub) Unregister(conn *websocket.Conn) { h.mu.Lock() delete(h.clients, conn) h.mu.Unlock() conn.Close() } func (h *Hub) Broadcast(msg []byte) { h.mu.RLock() defer h.mu.RUnlock() for conn := range h.clients { if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil { log.Printf("ws write error: %v", err) conn.Close() delete(h.clients, conn) } } } func HandleWebSocket(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("ws upgrade error: %v", err) return } hub.Register(conn) defer hub.Unregister(conn) for { _, _, err := conn.ReadMessage() if err != nil { break } } }