diff --git a/internal/broadcast/broadcast.go b/internal/broadcast/broadcast.go index 229ae67..deb3010 100644 --- a/internal/broadcast/broadcast.go +++ b/internal/broadcast/broadcast.go @@ -8,7 +8,7 @@ import ( ) // BroadcastMessage sends a message to all connected WebSocket clients. -func BroadcastMessage(clients map[*websocket.Conn]*models.Client, message models.BroadcastMessage) { +func BroadcastMessage(clients map[*websocket.Conn]bool, message models.BroadcastMessage) { // Marshal the message into JSON format jsonMessage, err := json.Marshal(message) if err != nil { @@ -17,11 +17,12 @@ func BroadcastMessage(clients map[*websocket.Conn]*models.Client, message models } // Iterate over all connected clients and broadcast the message - for _, client := range clients { - err := client.SendMessage(websocket.TextMessage, jsonMessage) + for client := range clients { + err := client.WriteMessage(websocket.TextMessage, jsonMessage) if err != nil { log.Printf("Error broadcasting to client: %v", err) - // The client is responsible for closing itself on error + client.Close() + delete(clients, client) // Remove the client if an error occurs } } } diff --git a/internal/pomodoro/pomodoro.go b/internal/pomodoro/pomodoro.go index c8a3b03..6297d45 100644 --- a/internal/pomodoro/pomodoro.go +++ b/internal/pomodoro/pomodoro.go @@ -24,7 +24,7 @@ var pomodoroResumeChannel = make(chan bool, 1) var mu sync.Mutex // to synchronize access to shared state // RunPomodoroTimer iterates the Pomodoro work/break sessions. -func RunPomodoroTimer(clients map[*websocket.Conn]*models.Client) { +func RunPomodoroTimer(clients map[*websocket.Conn]bool) { mu.Lock() pomodoroRunning = true pomodoroPaused = false @@ -51,7 +51,7 @@ func RunPomodoroTimer(clients map[*websocket.Conn]*models.Client) { } // ResetPomodoro resets the running Pomodoro timer. -func ResetPomodoro(clients map[*websocket.Conn]*models.Client) { +func ResetPomodoro(clients map[*websocket.Conn]bool) { mu.Lock() pomodoroRunning = false // Reset the running state pomodoroPaused = false // Reset the paused state @@ -70,17 +70,10 @@ func ResetPomodoro(clients map[*websocket.Conn]*models.Client) { } func PausePomodoro() { - mu.Lock() - pomodoroPaused = true - mu.Unlock() - pomodoroPauseChannel <- true } func ResumePomodoro() { - mu.Lock() - pomodoroPaused = false - mu.Unlock() pomodoroResumeChannel <- true } diff --git a/internal/pomodoro/timer.go b/internal/pomodoro/timer.go index 96595b3..6a8e39b 100644 --- a/internal/pomodoro/timer.go +++ b/internal/pomodoro/timer.go @@ -8,18 +8,22 @@ import ( ) // startTimer runs the countdown and broadcasts every second. -func startTimer(clients map[*websocket.Conn]*models.Client, remainingSeconds int, mode string, session int) bool { +func startTimer(clients map[*websocket.Conn]bool, remainingSeconds int, mode string, session int) bool { for remainingSeconds > 0 { select { case <-pomodoroResetChannel: return false case <-pomodoroPauseChannel: - // Nothing to set here, just waiting for the signal + mu.Lock() + pomodoroPaused = true + mu.Unlock() case <-pomodoroResumeChannel: - // Nothing to set here, just waiting for the signal + mu.Lock() + pomodoroPaused = false + mu.Unlock() default: // Broadcast the current state to all clients - if !IsPomodoroPaused() { + if !pomodoroPaused { broadcast.BroadcastMessage(clients, models.BroadcastMessage{ Mode: mode, Session: session, diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 91ee750..50fab15 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -6,22 +6,10 @@ import ( "git.smsvc.net/pomodoro/GoTomato/pkg/models" "github.com/gorilla/websocket" "log" - "sync" ) -// Clients is a map of connected WebSocket clients, where each client is represented by the Client struct -var Clients = make(map[*websocket.Conn]*models.Client) -var mu sync.Mutex // Mutex to protect access to the Clients map - // handleClientCommands listens for commands from WebSocket clients and dispatches to the timer. func handleClientCommands(ws *websocket.Conn) { - // Create a new Client and add it to the Clients map - mu.Lock() - Clients[ws] = &models.Client{ - Conn: ws, - } - mu.Unlock() - for { _, message, err := ws.ReadMessage() if err != nil { diff --git a/internal/websocket/handle_connections.go b/internal/websocket/handle_connections.go index 0b8f63e..a7d6cfc 100644 --- a/internal/websocket/handle_connections.go +++ b/internal/websocket/handle_connections.go @@ -1,12 +1,14 @@ package websocket import ( - "git.smsvc.net/pomodoro/GoTomato/pkg/models" "github.com/gorilla/websocket" "log" "net/http" ) +// Map to track connected clients +var Clients = make(map[*websocket.Conn]bool) + // Upgrader to upgrade HTTP requests to WebSocket connections var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, @@ -23,9 +25,7 @@ func HandleConnections(w http.ResponseWriter, r *http.Request) { defer ws.Close() // Register the new client - Clients[ws] = &models.Client{ - Conn: ws, // Store the WebSocket connection - } + Clients[ws] = true // Listen for commands from the connected client handleClientCommands(ws) diff --git a/pkg/models/client.go b/pkg/models/client.go deleted file mode 100644 index 8d5c3e9..0000000 --- a/pkg/models/client.go +++ /dev/null @@ -1,30 +0,0 @@ -package models - -import ( - "github.com/gorilla/websocket" - "log" - "sync" -) - -// ClientCommand represents a command from the client (start/stop). -type ClientCommand struct { - Command string `json:"command"` -} - -type Client struct { - Conn *websocket.Conn - Mutex sync.Mutex -} - -// It automatically locks and unlocks the mutex to ensure that only one goroutine can write at a time. -func (c *Client) SendMessage(messageType int, data []byte) error { - c.Mutex.Lock() - defer c.Mutex.Unlock() - - err := c.Conn.WriteMessage(messageType, data) - if err != nil { - log.Printf("Error writing to WebSocket: %v", err) - c.Conn.Close() // Close the connection on error - } - return err -} diff --git a/pkg/models/broadcast.go b/pkg/models/types.go similarity index 75% rename from pkg/models/broadcast.go rename to pkg/models/types.go index 78463b9..ea04e21 100644 --- a/pkg/models/broadcast.go +++ b/pkg/models/types.go @@ -7,3 +7,8 @@ type BroadcastMessage struct { MaxSession int `json:"max_session"` // Total number of sessions TimeLeft int `json:"time_left"` // Remaining time in seconds } + +// ClientCommand represents a command from the client (start/stop). +type ClientCommand struct { + Command string `json:"command"` +}