diff --git a/GoTomato.go b/GoTomato.go index 374f5c9..28a0917 100644 --- a/GoTomato.go +++ b/GoTomato.go @@ -4,6 +4,7 @@ import ( "encoding/json" "log" "net/http" + "sync" "time" "github.com/gorilla/websocket" @@ -23,7 +24,14 @@ type BroadcastMessage struct { TimeLeft int `json:"time_left"` } +type ClientCommand struct { + Command string `json:"command"` +} + var clients = make(map[*websocket.Conn]bool) +var timerRunning bool +var timerStopChannel = make(chan bool, 1) +var mu sync.Mutex // to synchronize access to shared state // broadcastMessage sends the remaining time to all connected clients. func broadcastMessage(message BroadcastMessage) { @@ -38,37 +46,54 @@ func broadcastMessage(message BroadcastMessage) { } } -// start a countdown and broadcast ever second -func startTimer(remaining_seconds int, mode string, session int) { - for remaining_seconds > 0 { - broadcastMessage(BroadcastMessage{ - Mode: mode, - Session: session, - MaxSession: sessions, - TimeLeft: remaining_seconds, - }) - time.Sleep(time.Second) - remaining_seconds-- - } - // send final 0 timer - broadcastMessage(BroadcastMessage{ - Mode: mode, - Session: 1, - MaxSession: 4, - TimeLeft: 0, - }) -} - -// iterate the Pomodoro work/break sessions -func runPomodoroTimer() { - for session := 1; session <= sessions; session++ { - startTimer(workDuration, "Work", session) - if session == sessions { - startTimer(longBreakDuration, "LongBreak", session) - } else { - startTimer(shortBreakDuration, "ShortBreak", session) +// startTimer runs the countdown and broadcasts every second. +func startTimer(remainingSeconds int, mode string, session int) bool { + for remainingSeconds > 0 { + select { + case <-timerStopChannel: + return false // Stop the timer if a stop command is received + default: + broadcastMessage(BroadcastMessage{ + Mode: mode, + Session: session, + MaxSession: sessions, + TimeLeft: remainingSeconds, + }) + time.Sleep(time.Second) + remainingSeconds-- } } + broadcastMessage(BroadcastMessage{ + Mode: mode, + Session: session, + MaxSession: sessions, + TimeLeft: 0, + }) + return true +} + +// runPomodoroTimer iterates the Pomodoro work/break sessions. +func runPomodoroTimer() { + mu.Lock() + timerRunning = true + + for session := 1; session <= sessions; session++ { + if !startTimer(workDuration, "Work", session) { + break + } + if session == sessions { + if !startTimer(longBreakDuration, "LongBreak", session) { + break + } + } else { + if !startTimer(shortBreakDuration, "ShortBreak", session) { + break + } + } + } + + timerRunning = false + mu.Unlock() } // upgrade HTTP requests to WebSocket connections. @@ -88,23 +113,40 @@ func handleConnections(w http.ResponseWriter, r *http.Request) { // Register the new client clients[ws] = true - // Clean up when the client disconnects + // Listen for commands from this client for { - _, _, err := ws.ReadMessage() + _, message, err := ws.ReadMessage() if err != nil { log.Printf("Client disconnected: %v", err) delete(clients, ws) break } + + // Handle incoming commands + var command ClientCommand + err = json.Unmarshal(message, &command) + if err != nil { + log.Printf("Error unmarshalling command: %v", err) + continue + } + + // Process the commands + switch command.Command { + case "start": + if !timerRunning { + go runPomodoroTimer() + } + case "stop": + if timerRunning { + timerStopChannel <- true + } + } } } func main() { http.HandleFunc("/ws", handleConnections) - // Start a goroutine that runs the Pomodoro timer and broadcasts updates. - go runPomodoroTimer() - log.Println("Pomodoro WebSocket server started on :8080") err := http.ListenAndServe(":8080", nil) if err != nil { diff --git a/index.html b/index.html index a092d2f..58fa15c 100644 --- a/index.html +++ b/index.html @@ -5,22 +5,67 @@ Pomodoro Timer +

Pomodoro Timer

Connecting to server...
+ + + +