package handlers import ( "fmt" "html/template" "net/http" "sync" "github.com/gorilla/websocket" "github.com/markbates/goth/gothic" ) type Handler struct { Template template.Template } type Message struct { Id string Action string Message string } type PageData struct { Username string } type hub struct { clients map[*websocket.Conn]bool Broadcast chan []byte register chan *websocket.Conn unregister chan *websocket.Conn mutex sync.RWMutex } var Hub = &hub{ clients: make(map[*websocket.Conn]bool), Broadcast: make(chan []byte), register: make(chan *websocket.Conn), unregister: make(chan *websocket.Conn), } var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true // this should change }, } func (h *hub) Run() { for { select { case conn := <-h.register: h.mutex.Lock() h.clients[conn] = true h.mutex.Unlock() fmt.Printf("Client connected. Total clients: %d\n", len(h.clients)) case conn := <-h.unregister: h.mutex.Lock() if _, ok := h.clients[conn]; ok { delete(h.clients, conn) conn.Close() } h.mutex.Unlock() fmt.Printf("Client disconnected. Total clients: %d\n", len(h.clients)) case message := <-h.Broadcast: h.mutex.RLock() for conn := range h.clients { if err := conn.WriteMessage(websocket.TextMessage, message); err != nil { fmt.Printf("Error sending message to client: %v\n", err) // Remove failed connection delete(h.clients, conn) conn.Close() } } h.mutex.RUnlock() } } } func (h *Handler) Home(w http.ResponseWriter, r *http.Request) { session, err := gothic.Store.Get(r, "user-session") if err != nil { http.Error(w, "Error retrieving session for welcome page", http.StatusInternalServerError) } username, ok := session.Values["user_name"].(string) var pagedata PageData if ok { pagedata.Username = username } else { pagedata.Username = "" } err = h.Template.ExecuteTemplate(w, "index.html", &pagedata) if err != nil { http.Error(w, "Template rendering error", http.StatusInternalServerError) } } func (h *Handler) WsHandler(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { fmt.Println("upgrade error:", err) return } Hub.register <- conn defer conn.Close() for { _, messageBytes, err := conn.ReadMessage() if err != nil && !websocket.IsCloseError( err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived, ) { fmt.Printf("error reading message: %v", err) } Hub.Broadcast <- messageBytes } }