From 2ac1aecba14c6e636cf4e25f4680f56aefb24427 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sun, 20 Oct 2024 23:09:30 +0200 Subject: [PATCH] feat: allow clients to send pomodoro config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - allow clients to send custom configuration for pomodoro sessions - update RunPomodoro to accept a configuration parameter - modify startTimer to handle session count from config - add default pomodoro configuration in client command handling 🤖 --- README.md | 17 +++++++++++++++++ index.html | 3 ++- internal/pomodoro/pomodoro.go | 19 ++++++------------- internal/pomodoro/timer.go | 6 +++--- internal/websocket/client_commands.go | 20 ++++++++++++++++---- pkg/models/client.go | 3 ++- 6 files changed, 46 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 39aee92..ef506d7 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,23 @@ Clients communicate with the server by sending JSON-encoded commands. Each comma | `resume` | Resumes a paused session | `{"command": "resume"}` | | `reset` | Stops and resets the current session| `{"command": "reset"}` | +#### Optional Start Parameters + +The Start-Command may contain an optional Pomodoro-Config, which allows you to customize the length of the work session, short break, long break, and the number of sessions. If no configuration is provided, the server will use default values. + +Example: +```json +{ + command: "start", + config: { + "work": 10, // Length of the work session in seconds + "shortBreak": 5, // Length of the short break in seconds + "longBreak": 10, // Length of the long break in seconds + "sessions": 2 // Number of total sessions + } +} +``` + ### Server Messages The server sends JSON-encoded messages to all connected clients to update them on the current state of the Pomodoro session. diff --git a/index.html b/index.html index 248ca61..972e480 100644 --- a/index.html +++ b/index.html @@ -61,7 +61,8 @@ // Start Button Click Event document.getElementById("startButton").addEventListener("click", function () { - ws.send(JSON.stringify({command: "start"})); + // ws.send(JSON.stringify({command: "start"})); + ws.send(JSON.stringify({command: "start", config: {work: 10, shortBreak: 5, longBreak: 10, sessions: 2}})); // Hide start button and show pause/resume and stop buttons document.getElementById("startButton").style.display = "none"; diff --git a/internal/pomodoro/pomodoro.go b/internal/pomodoro/pomodoro.go index 9b4ee5f..f15f87c 100644 --- a/internal/pomodoro/pomodoro.go +++ b/internal/pomodoro/pomodoro.go @@ -7,13 +7,6 @@ import ( "sync" ) -var PomodoroConfig = models.GoTomatoPomodoroConfig{ - Work: 15 * 60, - ShortBreak: 5 * 60, - LongBreak: 10 * 60, - Sessions: 4, -} - var pomodoroOngoing bool var pomodoroPaused bool @@ -24,22 +17,22 @@ var pomodoroResumeChannel = make(chan bool, 1) var mu sync.Mutex // to synchronize access to shared state // RunPomodoro iterates the Pomodoro work/break sessions. -func RunPomodoro(clients map[*websocket.Conn]*models.Client) { +func RunPomodoro(clients map[*websocket.Conn]*models.Client, config models.GoTomatoPomodoroConfig) { mu.Lock() pomodoroOngoing = true pomodoroPaused = false mu.Unlock() - for session := 1; session <= PomodoroConfig.Sessions; session++ { - if !startTimer(clients, PomodoroConfig.Work, "Work", session) { + for session := 1; session <= config.Sessions; session++ { + if !startTimer(clients, config.Work, "Work", session, config.Sessions) { break } - if session == PomodoroConfig.Sessions { - if !startTimer(clients, PomodoroConfig.LongBreak, "LongBreak", session) { + if session == config.Sessions { + if !startTimer(clients, config.LongBreak, "LongBreak", session, config.Sessions) { break } } else { - if !startTimer(clients, PomodoroConfig.ShortBreak, "ShortBreak", session) { + if !startTimer(clients, config.ShortBreak, "ShortBreak", session, config.Sessions) { break } } diff --git a/internal/pomodoro/timer.go b/internal/pomodoro/timer.go index bca8116..b9b0a70 100644 --- a/internal/pomodoro/timer.go +++ b/internal/pomodoro/timer.go @@ -8,7 +8,7 @@ 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]*models.Client, remainingSeconds int, mode string, session int, sessions int) bool { for remainingSeconds > 0 { select { case <-pomodoroResetChannel: @@ -23,7 +23,7 @@ func startTimer(clients map[*websocket.Conn]*models.Client, remainingSeconds int broadcast.BroadcastMessage(clients, models.ServerMessage{ Mode: mode, Session: session, - MaxSession: PomodoroConfig.Sessions, + MaxSession: sessions, TimeLeft: remainingSeconds, }) time.Sleep(time.Second) @@ -36,7 +36,7 @@ func startTimer(clients map[*websocket.Conn]*models.Client, remainingSeconds int broadcast.BroadcastMessage(clients, models.ServerMessage{ Mode: mode, Session: session, - MaxSession: PomodoroConfig.Sessions, + MaxSession: sessions, TimeLeft: 0, }) diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 2938a6b..1005006 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -8,9 +8,19 @@ import ( "log" ) +var unsetPomodoroConfig models.GoTomatoPomodoroConfig // used to check if client passed a config json + // handleClientCommands listens for commands from WebSocket clients and dispatches to the timer. func handleClientCommands(ws *websocket.Conn) { for { + var clientCommand models.ClientCommand + var pomodoroConfig = models.GoTomatoPomodoroConfig{ + Work: 25 * 60, + ShortBreak: 5 * 60, + LongBreak: 15 * 60, + Sessions: 4, + } + _, message, err := ws.ReadMessage() if err != nil { log.Printf("Client disconnected: %v", err) @@ -19,18 +29,20 @@ func handleClientCommands(ws *websocket.Conn) { } // Handle incoming commands - var command models.ClientCommand - err = json.Unmarshal(message, &command) + err = json.Unmarshal(message, &clientCommand) if err != nil { log.Printf("Error unmarshalling command: %v", err) continue } // Process the command - switch command.Command { + switch clientCommand.Command { case "start": if !pomodoro.IsPomodoroOngoing() { - go pomodoro.RunPomodoro(Clients) // Start the timer with the list of clients + if clientCommand.Config != unsetPomodoroConfig { + pomodoroConfig = clientCommand.Config + } + go pomodoro.RunPomodoro(Clients, pomodoroConfig) // Start the timer with the list of clients } case "stop": if pomodoro.IsPomodoroOngoing() { diff --git a/pkg/models/client.go b/pkg/models/client.go index 8d5c3e9..5c3c9cc 100644 --- a/pkg/models/client.go +++ b/pkg/models/client.go @@ -8,7 +8,8 @@ import ( // ClientCommand represents a command from the client (start/stop). type ClientCommand struct { - Command string `json:"command"` + Command string `json:"command"` + Config GoTomatoPomodoroConfig `json:"config"` } type Client struct {