commit 0e643ef37a342a8645eb1b9bdd4464e010afbc2f Author: Sebastian Mark Date: Sat Oct 19 00:39:29 2024 +0200 Genesis diff --git a/GoTomato.go b/GoTomato.go new file mode 100644 index 0000000..374f5c9 --- /dev/null +++ b/GoTomato.go @@ -0,0 +1,113 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" + "time" + + "github.com/gorilla/websocket" +) + +const ( + workDuration = 15 * 60 + shortBreakDuration = 5 * 60 + longBreakDuration = 10 * 60 + sessions = 4 +) + +type BroadcastMessage struct { + Mode string `json:"mode"` + Session int `json:"session"` + MaxSession int `json:"max_session"` + TimeLeft int `json:"time_left"` +} + +var clients = make(map[*websocket.Conn]bool) + +// broadcastMessage sends the remaining time to all connected clients. +func broadcastMessage(message BroadcastMessage) { + jsonMessage, _ := json.Marshal(message) + for client := range clients { + err := client.WriteMessage(websocket.TextMessage, jsonMessage) + if err != nil { + log.Printf("Error broadcasting to client: %v", err) + client.Close() + delete(clients, client) + } + } +} + +// 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) + } + } +} + +// upgrade HTTP requests to WebSocket connections. +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { return true }, +} + +func handleConnections(w http.ResponseWriter, r *http.Request) { + // Upgrade initial GET request to a WebSocket + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Printf("WebSocket upgrade error: %v", err) + return + } + defer ws.Close() + + // Register the new client + clients[ws] = true + + // Clean up when the client disconnects + for { + _, _, err := ws.ReadMessage() + if err != nil { + log.Printf("Client disconnected: %v", err) + delete(clients, ws) + break + } + } +} + +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 { + log.Fatalf("Error starting server: %v", err) + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce52779 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# GoTomato + +A pomodoro server + +## Testing + +``` +docker run --rm -d --name pomodoro-client -v $PWD:/usr/share/nginx/html/ -p 8081:80 nginx +go run . +``` + +open http://localhost:8081 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ca20fd0 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module GoTomato + +go 1.23.1 + +require github.com/gorilla/websocket v1.5.3 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..25a9fc4 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= diff --git a/index.html b/index.html new file mode 100644 index 0000000..a092d2f --- /dev/null +++ b/index.html @@ -0,0 +1,27 @@ + + + + + + + Pomodoro Timer + + + +

Pomodoro Timer

+
Connecting to server...
+ + + + +