From ebb58a44893fb09ab57189461f13804c28534eb4 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 30 Oct 2024 09:57:09 +0100 Subject: [PATCH 01/33] feat: rename `Client` model to `WebsocketClient` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 --- internal/websocket/client_commands.go | 2 +- internal/websocket/handle_connection.go | 4 ++-- pkg/models/client.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 4ea7e7d..59e603a 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -10,7 +10,7 @@ import ( ) // Listens for commands from a client and handles them -func handleClientCommands(c models.Client) { +func handleClientCommands(c models.WebsocketClient) { ws := c.Conn for { var clientCommand models.ClientCommand diff --git a/internal/websocket/handle_connection.go b/internal/websocket/handle_connection.go index 37160d8..dc5ad1c 100644 --- a/internal/websocket/handle_connection.go +++ b/internal/websocket/handle_connection.go @@ -10,7 +10,7 @@ import ( ) // 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 Clients = make(map[*websocket.Conn]*models.WebsocketClient) var mu sync.Mutex // Mutex to protect access to the Clients map // Upgrade HTTP requests to WebSocket connections @@ -31,7 +31,7 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { log.Info("Client connected", "host", ws.NetConn().RemoteAddr(), "clients", len(Clients)+1) // Register the new client - client := models.Client{ + client := models.WebsocketClient{ Conn: ws, } mu.Lock() diff --git a/pkg/models/client.go b/pkg/models/client.go index f9eb116..c0998f8 100644 --- a/pkg/models/client.go +++ b/pkg/models/client.go @@ -13,13 +13,13 @@ type ClientCommand struct { } // Represents a single client -type Client struct { +type WebsocketClient struct { Conn *websocket.Conn } // Sends a message to the websocket. // Automatically locks and unlocks the client mutex, to ensure that only one goroutine can write at a time. -func (c *Client) SendMessage(messageType int, data []byte) error { +func (c *WebsocketClient) SendMessage(messageType int, data []byte) error { err := c.Conn.WriteMessage(messageType, data) if err != nil { log.Error("Error writing to WebSocket:", "msg", err) From 0ee955189c7cdb4156ced500d9d582022708857d Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 30 Oct 2024 10:17:24 +0100 Subject: [PATCH 02/33] feat: update client management to use local address as identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - change Clients map to use net.Addr as the key type - update `HandleConnection()` to store clients using LocalAddr - modify `handleClientCommands()` to delete clients by LocalAddr 🤖 --- internal/websocket/client_commands.go | 2 +- internal/websocket/handle_connection.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 59e603a..b38e55b 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -18,7 +18,7 @@ func handleClientCommands(c models.WebsocketClient) { _, message, err := ws.ReadMessage() if err != nil { log.Info("Client disconnected:", "msg", err, "host", ws.NetConn().RemoteAddr(), "clients", len(Clients)-1) - delete(Clients, ws) + delete(Clients, ws.LocalAddr()) break } diff --git a/internal/websocket/handle_connection.go b/internal/websocket/handle_connection.go index dc5ad1c..b7b240f 100644 --- a/internal/websocket/handle_connection.go +++ b/internal/websocket/handle_connection.go @@ -3,14 +3,15 @@ package websocket import ( "github.com/charmbracelet/log" "github.com/gorilla/websocket" + "net" "net/http" "sync" "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) -// Clients is a map of connected WebSocket clients, where each client is represented by the Client struct -var Clients = make(map[*websocket.Conn]*models.WebsocketClient) +// Clients is a map of connected WebSocket clients, where each client is represented by the WebsocketClient struct +var Clients = make(map[net.Addr]*models.WebsocketClient) var mu sync.Mutex // Mutex to protect access to the Clients map // Upgrade HTTP requests to WebSocket connections @@ -35,7 +36,7 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { Conn: ws, } mu.Lock() - Clients[ws] = &client + Clients[ws.LocalAddr()] = &client mu.Unlock() // Listen for commands from the connected client From f4fd37c55165a80876f4d29bae2a82c83c42c1fd Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 30 Oct 2024 10:19:07 +0100 Subject: [PATCH 03/33] feat: update logging for client connect and disconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - update logging to use ws.RemoteAddr() 🤖 --- internal/websocket/client_commands.go | 2 +- internal/websocket/handle_connection.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index b38e55b..60158f2 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -17,7 +17,7 @@ func handleClientCommands(c models.WebsocketClient) { _, message, err := ws.ReadMessage() if err != nil { - log.Info("Client disconnected:", "msg", err, "host", ws.NetConn().RemoteAddr(), "clients", len(Clients)-1) + log.Info("Client disconnected:", "msg", err, "host", ws.RemoteAddr(), "clients", len(Clients)-1) delete(Clients, ws.LocalAddr()) break } diff --git a/internal/websocket/handle_connection.go b/internal/websocket/handle_connection.go index b7b240f..6abb339 100644 --- a/internal/websocket/handle_connection.go +++ b/internal/websocket/handle_connection.go @@ -29,7 +29,7 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { } defer ws.Close() - log.Info("Client connected", "host", ws.NetConn().RemoteAddr(), "clients", len(Clients)+1) + log.Info("Client connected", "host", ws.RemoteAddr(), "clients", len(Clients)+1) // Register the new client client := models.WebsocketClient{ From e7618b19ef8367c3942d7e4570c6538261439909 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 30 Oct 2024 11:28:42 +0100 Subject: [PATCH 04/33] feat: validate client settings and improve logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add a function to check if Pomodoro settings are valid - log a warning for invalid client configurations - log an info message for valid client configurations - implement Stringer interface for PomodoroConfig model 🤖 --- internal/websocket/client_commands.go | 9 +++++++++ pkg/models/config.go | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 60158f2..2fba584 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -9,6 +9,10 @@ import ( "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) +func checkSettings(settings models.PomodoroConfig) bool { + return settings.Work > 0 && settings.ShortBreak > 0 && settings.LongBreak > 0 && settings.Sessions > 0 +} + // Listens for commands from a client and handles them func handleClientCommands(c models.WebsocketClient) { ws := c.Conn @@ -50,6 +54,11 @@ func handleClientCommands(c models.WebsocketClient) { } case "updateSettings": if !pomodoro.IsPomodoroOngoing() { + if !checkSettings(clientCommand.Settings) { + log.Warn("Ignoring invalid config:", "msg", clientCommand.Settings, "host", c.Conn.RemoteAddr()) + break + } + log.Info("Client send config", "config", clientCommand.Settings, "host", c.Conn.RemoteAddr()) pomodoro.UpdateSettings(clientCommand.Settings) } } diff --git a/pkg/models/config.go b/pkg/models/config.go index 36b9dbb..1852165 100644 --- a/pkg/models/config.go +++ b/pkg/models/config.go @@ -1,5 +1,7 @@ package models +import "fmt" + // Represents the configuration of a pomodoro type PomodoroConfig struct { Work int `json:"work"` // Length of work sessions in seconds @@ -8,6 +10,11 @@ type PomodoroConfig struct { Sessions int `json:"sessions"` // Number of total sessions } +// Stringer interface for the PomodocoConfig model +func (c PomodoroConfig) String() string { + return fmt.Sprintf("{work: %d, short: %d, long: %d, sessions: %d}", c.Work, c.ShortBreak, c.LongBreak, c.Sessions) +} + // Represents the server configuration type ServerConfig struct { ListenAddress string `json:"listenAddress"` // Server listen address From dd9490bb3b8e80b0b4b272ac67ecce896b8cdb9b Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 30 Oct 2024 11:29:47 +0100 Subject: [PATCH 05/33] feat: bump version to v0.0.6 --- internal/metadata/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index e31bfed..2ab12fa 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "v0.0.5" // The GoTomato version +const GoTomatoVersion = "v0.0.6" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From 44a64bfce4bc7435ad476071f8e0fe96e0e43d69 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sun, 3 Nov 2024 10:00:14 +0100 Subject: [PATCH 06/33] feat: handle X-Forward-For for log output - add Gorilla handlers package for enhanced HTTP handling - refactor HTTP server to use a new ServeMux for routing - update ListenAndServe to utilize ProxyHeaders for better proxy support - add RealIP field to client model - use RealIP fild for connect/disconnect log output --- cmd/server/main.go | 6 ++++-- go.mod | 2 ++ go.sum | 4 ++++ internal/websocket/client_commands.go | 2 +- internal/websocket/handle_connection.go | 7 ++++--- pkg/models/client.go | 3 ++- 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 126ec2f..c30f3e4 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -4,6 +4,7 @@ import ( "flag" "fmt" "github.com/charmbracelet/log" + "github.com/gorilla/handlers" "net/http" "os" @@ -43,14 +44,15 @@ func Start() { listen := fmt.Sprintf("%s:%d", serverConfig.ListenAddress, serverConfig.ListenPort) // start connection handler and broadcast - http.HandleFunc("/ws", websocket.HandleConnection) + r := http.NewServeMux() + r.HandleFunc("/ws", websocket.HandleConnection) go websocket.SendPermanentBroadCastMessage() log.Info("GoTomato started", "version", metadata.GoTomatoVersion) log.Info("Websocket listening", "address", listen) // start the listener - err := http.ListenAndServe(listen, nil) + err := http.ListenAndServe(listen, handlers.ProxyHeaders(r)) if err != nil { log.Fatal("Error starting server:", "msg", err) } diff --git a/go.mod b/go.mod index 148683e..e78b89d 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,14 @@ go 1.23 require ( github.com/charmbracelet/log v0.4.0 + github.com/gorilla/handlers v1.5.2 github.com/gorilla/websocket v1.5.3 ) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/lipgloss v0.10.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.18 // indirect diff --git a/go.sum b/go.sum index 9437970..77f660c 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,12 @@ github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8 github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 2fba584..1a66198 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -21,8 +21,8 @@ func handleClientCommands(c models.WebsocketClient) { _, message, err := ws.ReadMessage() if err != nil { - log.Info("Client disconnected:", "msg", err, "host", ws.RemoteAddr(), "clients", len(Clients)-1) delete(Clients, ws.LocalAddr()) + log.Info("Client disconnected:", "msg", err, "host", c.RealIP, "clients", len(Clients)) break } diff --git a/internal/websocket/handle_connection.go b/internal/websocket/handle_connection.go index 6abb339..6ee22bc 100644 --- a/internal/websocket/handle_connection.go +++ b/internal/websocket/handle_connection.go @@ -29,16 +29,17 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { } defer ws.Close() - log.Info("Client connected", "host", ws.RemoteAddr(), "clients", len(Clients)+1) - // Register the new client client := models.WebsocketClient{ - Conn: ws, + Conn: ws, + RealIP: r.RemoteAddr, } mu.Lock() Clients[ws.LocalAddr()] = &client mu.Unlock() + log.Info("Client connected", "host", client.RealIP, "clients", len(Clients)) + // Listen for commands from the connected client handleClientCommands(client) } diff --git a/pkg/models/client.go b/pkg/models/client.go index c0998f8..aec2f3c 100644 --- a/pkg/models/client.go +++ b/pkg/models/client.go @@ -14,7 +14,8 @@ type ClientCommand struct { // Represents a single client type WebsocketClient struct { - Conn *websocket.Conn + Conn *websocket.Conn + RealIP string } // Sends a message to the websocket. From 76f395429978bc46340dd081746b7065df0577ca Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sun, 3 Nov 2024 11:19:03 +0100 Subject: [PATCH 07/33] feat: bump version to v0.0.7 --- internal/metadata/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index 2ab12fa..84b8dd7 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "v0.0.6" // The GoTomato version +const GoTomatoVersion = "v0.0.7" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From 600d2ed2ffffc69d5832648fbfaf544dc1774a4e Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Mon, 4 Nov 2024 20:33:25 +0100 Subject: [PATCH 08/33] feat: implement centralized logging helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - remove direct log usage - create a new logging helper - update all log calls to use the new Logger instance - set timestamp to ISO8601 🤖 --- cmd/server/main.go | 8 ++++---- internal/helper/logging.go | 12 ++++++++++++ internal/websocket/broadcast.go | 6 +++--- internal/websocket/client_commands.go | 10 +++++----- internal/websocket/handle_connection.go | 6 +++--- pkg/models/client.go | 5 +++-- 6 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 internal/helper/logging.go diff --git a/cmd/server/main.go b/cmd/server/main.go index c30f3e4..a109f38 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -3,11 +3,11 @@ package server import ( "flag" "fmt" - "github.com/charmbracelet/log" "github.com/gorilla/handlers" "net/http" "os" + "git.smsvc.net/pomodoro/GoTomato/internal/helper" "git.smsvc.net/pomodoro/GoTomato/internal/metadata" "git.smsvc.net/pomodoro/GoTomato/internal/shared" "git.smsvc.net/pomodoro/GoTomato/internal/websocket" @@ -48,12 +48,12 @@ func Start() { r.HandleFunc("/ws", websocket.HandleConnection) go websocket.SendPermanentBroadCastMessage() - log.Info("GoTomato started", "version", metadata.GoTomatoVersion) - log.Info("Websocket listening", "address", listen) + helper.Logger.Info("GoTomato started", "version", metadata.GoTomatoVersion) + helper.Logger.Info("Websocket listening", "address", listen) // start the listener err := http.ListenAndServe(listen, handlers.ProxyHeaders(r)) if err != nil { - log.Fatal("Error starting server:", "msg", err) + helper.Logger.Fatal("Error starting server:", "msg", err) } } diff --git a/internal/helper/logging.go b/internal/helper/logging.go new file mode 100644 index 0000000..ecb7371 --- /dev/null +++ b/internal/helper/logging.go @@ -0,0 +1,12 @@ +package helper + +import ( + "github.com/charmbracelet/log" + "os" + "time" +) + +var Logger = log.NewWithOptions(os.Stdout, log.Options{ + ReportTimestamp: true, + TimeFormat: time.RFC3339, +}) diff --git a/internal/websocket/broadcast.go b/internal/websocket/broadcast.go index 14254c0..def8309 100644 --- a/internal/websocket/broadcast.go +++ b/internal/websocket/broadcast.go @@ -2,10 +2,10 @@ package websocket import ( "encoding/json" - "github.com/charmbracelet/log" "github.com/gorilla/websocket" "time" + "git.smsvc.net/pomodoro/GoTomato/internal/helper" "git.smsvc.net/pomodoro/GoTomato/internal/shared" ) @@ -16,14 +16,14 @@ func SendPermanentBroadCastMessage() { // Marshal the message into JSON format jsonMessage, err := json.Marshal(shared.State) if err != nil { - log.Error("Error marshalling message:", "msg", err) + helper.Logger.Error("Error marshalling message:", "msg", err) return } // Iterate over all connected clients and broadcast the message for _, client := range Clients { err := client.SendMessage(websocket.TextMessage, jsonMessage) if err != nil { - log.Error("Error broadcasting to client:", "msg", err) + helper.Logger.Error("Error broadcasting to client:", "msg", err) // The client is responsible for closing itself on error } } diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index 1a66198..bdb6e7a 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -2,8 +2,8 @@ package websocket import ( "encoding/json" - "github.com/charmbracelet/log" + "git.smsvc.net/pomodoro/GoTomato/internal/helper" "git.smsvc.net/pomodoro/GoTomato/internal/pomodoro" "git.smsvc.net/pomodoro/GoTomato/internal/shared" "git.smsvc.net/pomodoro/GoTomato/pkg/models" @@ -22,14 +22,14 @@ func handleClientCommands(c models.WebsocketClient) { _, message, err := ws.ReadMessage() if err != nil { delete(Clients, ws.LocalAddr()) - log.Info("Client disconnected:", "msg", err, "host", c.RealIP, "clients", len(Clients)) + helper.Logger.Info("Client disconnected:", "msg", err, "host", c.RealIP, "clients", len(Clients)) break } // Handle incoming commands err = json.Unmarshal(message, &clientCommand) if err != nil { - log.Error("Error unmarshalling command:", "msg", err) + helper.Logger.Error("Error unmarshalling command:", "msg", err) continue } @@ -55,10 +55,10 @@ func handleClientCommands(c models.WebsocketClient) { case "updateSettings": if !pomodoro.IsPomodoroOngoing() { if !checkSettings(clientCommand.Settings) { - log.Warn("Ignoring invalid config:", "msg", clientCommand.Settings, "host", c.Conn.RemoteAddr()) + helper.Logger.Warn("Ignoring invalid config:", "msg", clientCommand.Settings, "host", c.Conn.RemoteAddr()) break } - log.Info("Client send config", "config", clientCommand.Settings, "host", c.Conn.RemoteAddr()) + helper.Logger.Info("Client send config", "config", clientCommand.Settings, "host", c.Conn.RemoteAddr()) pomodoro.UpdateSettings(clientCommand.Settings) } } diff --git a/internal/websocket/handle_connection.go b/internal/websocket/handle_connection.go index 6ee22bc..9c4b43f 100644 --- a/internal/websocket/handle_connection.go +++ b/internal/websocket/handle_connection.go @@ -1,12 +1,12 @@ package websocket import ( - "github.com/charmbracelet/log" "github.com/gorilla/websocket" "net" "net/http" "sync" + "git.smsvc.net/pomodoro/GoTomato/internal/helper" "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) @@ -24,7 +24,7 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { // Upgrade initial GET request to a WebSocket ws, err := upgrader.Upgrade(w, r, nil) if err != nil { - log.Error("WebSocket upgrade error:", "msg", err) + helper.Logger.Error("WebSocket upgrade error:", "msg", err) return } defer ws.Close() @@ -38,7 +38,7 @@ func HandleConnection(w http.ResponseWriter, r *http.Request) { Clients[ws.LocalAddr()] = &client mu.Unlock() - log.Info("Client connected", "host", client.RealIP, "clients", len(Clients)) + helper.Logger.Info("Client connected", "host", client.RealIP, "clients", len(Clients)) // Listen for commands from the connected client handleClientCommands(client) diff --git a/pkg/models/client.go b/pkg/models/client.go index aec2f3c..eef9663 100644 --- a/pkg/models/client.go +++ b/pkg/models/client.go @@ -1,8 +1,9 @@ package models import ( - "github.com/charmbracelet/log" "github.com/gorilla/websocket" + + "git.smsvc.net/pomodoro/GoTomato/internal/helper" ) // Represents a command from the client (start/stop) @@ -23,7 +24,7 @@ type WebsocketClient struct { func (c *WebsocketClient) SendMessage(messageType int, data []byte) error { err := c.Conn.WriteMessage(messageType, data) if err != nil { - log.Error("Error writing to WebSocket:", "msg", err) + helper.Logger.Error("Error writing to WebSocket:", "msg", err) c.Conn.Close() // Close the connection on error } return err From d7b77890512385b8c17df8838eaa8f5b9f201ffd Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Mon, 4 Nov 2024 20:35:01 +0100 Subject: [PATCH 09/33] feat: bump version to v0.0.8 --- internal/metadata/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index 84b8dd7..8968337 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "v0.0.7" // The GoTomato version +const GoTomatoVersion = "v0.0.8" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From cbe2e007de082c23293d4e37ab9bd07f0ebf5758 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Tue, 5 Nov 2024 23:29:24 +0100 Subject: [PATCH 10/33] break: drop "v" from version string const - removes "v" from the ProtocolVersion in the ServerMessage - remove "v" prefix from GoTomatoVersion constant - re-add "v" for for human readable output (`-version`) - update README --- README.md | 10 +++++----- cmd/server/main.go | 4 ++-- internal/metadata/version.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 15e4f08..c2d9e51 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,11 @@ The server periodically (every second) sends JSON-encoded messages to all connec | Message Type | Example | | --- | --- | -| Welcome Message | {"mode":"Idle", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":1500, "ongoing":false, "paused":false, "version":"v0"} | -| Session Running | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":1, "time_left":900, "ongoing":true, "paused":false, "version":"v0"} | -| Session Running | {"mode":"ShortBreak", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":50, "ongoing":true, "paused":false, "version":"v0"} | -| Session Paused | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":456, "ongoing":true, "paused":true, "version":"v0"} | -| Session End/Reset | {"mode":"End", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":0, "ongoing":false, "paused":false, "version":"v0"} | +| Welcome Message | {"mode":"Idle", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":1500, "ongoing":false, "paused":false, "version":"0"} | +| Session Running | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":1, "time_left":900, "ongoing":true, "paused":false, "version":"0"} | +| Session Running | {"mode":"ShortBreak", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":50, "ongoing":true, "paused":false, "version":"0"} | +| Session Paused | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":456, "ongoing":true, "paused":true, "version":"0"} | +| Session End/Reset | {"mode":"End", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":0, "ongoing":false, "paused":false, "version":"0"} | ## Testing diff --git a/cmd/server/main.go b/cmd/server/main.go index a109f38..29241f0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -28,8 +28,8 @@ func Start() { // show server and protocl version and exit if *showVersionFlag { - fmt.Println("Server-Version:", metadata.GoTomatoVersion) - fmt.Println("Protocol-Version:", metadata.ProtocolVersion) + fmt.Printf("Server-Version: v%s\n", metadata.GoTomatoVersion) + fmt.Printf("Protocol-Version: v%s\n", metadata.ProtocolVersion) os.Exit(0) } diff --git a/internal/metadata/version.go b/internal/metadata/version.go index 8968337..f05a892 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "v0.0.8" // The GoTomato version +const GoTomatoVersion = "0.0.8" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From b15324f6f8ca32c3ee196e23f7792d3724f22db7 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 6 Nov 2024 08:27:12 +0100 Subject: [PATCH 11/33] feat: bump version to v0.1.0 --- internal/metadata/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index f05a892..9b7f4f7 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "0.0.8" // The GoTomato version +const GoTomatoVersion = "0.1.0" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From f346cbbcaa78a69979c413cadcf98f19b421d32e Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 6 Nov 2024 18:11:37 +0100 Subject: [PATCH 12/33] feat: add initial configuration for GoReleaser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 --- .gitignore | 2 ++ .goreleaser.yaml | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 .goreleaser.yaml diff --git a/.gitignore b/.gitignore index 2201ae4..5ee2497 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ GoTomato + +dist/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..aa2e879 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,41 @@ +# vim: set ts=2 sw=2 tw=0 fo=cnqoj + +version: 2 + +before: + hooks: + - rm -fr ./dist + - go mod tidy + +builds: + - goos: + - linux + goarch: + - amd64 + - arm64 + env: + - CGO_ENABLED=0 + +upx: + - enabled: true + compress: best + lzma: true + +changelog: + sort: desc + filters: + exclude: + - "bump version to" + +archives: + - format: binary + +release: + gitea: + owner: pomodoro + name: GoTomato + mode: replace + +gitea_urls: + download: http://git.smsvc.net + api: http://git.smsvc.net/api/v1 From 783d158e9231a4e95276c50decb17ecb427a4234 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Wed, 6 Nov 2024 20:44:44 +0100 Subject: [PATCH 13/33] feat: bump version to 0.1.1 --- internal/metadata/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index 9b7f4f7..22e394e 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,5 @@ package metadata import "strings" -const GoTomatoVersion = "0.1.0" // The GoTomato version +const GoTomatoVersion = "0.1.1" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From 93f39507c1477cd7b8853be0d40d7b441b60ccfd Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Thu, 7 Nov 2024 11:38:45 +0100 Subject: [PATCH 14/33] feat(gorleaser): set version from git tag on build - make `GoTomatoVersion` a variable and default it to "devel" - add ldflags to `.goreleaser.yaml` for version tagging - remove "v" from output of `-version` --- .goreleaser.yaml | 2 ++ cmd/server/main.go | 4 ++-- internal/metadata/version.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index aa2e879..4b315c5 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,6 +15,8 @@ builds: - arm64 env: - CGO_ENABLED=0 + ldflags: + - -s -w -X git.smsvc.net/pomodoro/GoTomato/internal/metadata.GoTomatoVersion={{.Version}} upx: - enabled: true diff --git a/cmd/server/main.go b/cmd/server/main.go index 29241f0..a109f38 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -28,8 +28,8 @@ func Start() { // show server and protocl version and exit if *showVersionFlag { - fmt.Printf("Server-Version: v%s\n", metadata.GoTomatoVersion) - fmt.Printf("Protocol-Version: v%s\n", metadata.ProtocolVersion) + fmt.Println("Server-Version:", metadata.GoTomatoVersion) + fmt.Println("Protocol-Version:", metadata.ProtocolVersion) os.Exit(0) } diff --git a/internal/metadata/version.go b/internal/metadata/version.go index 22e394e..ecac17b 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -2,5 +2,6 @@ package metadata import "strings" -const GoTomatoVersion = "0.1.1" // The GoTomato version +// This will be overwritten by goreleaser on build +var GoTomatoVersion = "devel" // The GoTomato version var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version From 467d90065c43d9384da3ba3da63d98435171b01b Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Thu, 7 Nov 2024 19:29:48 +0100 Subject: [PATCH 15/33] feat(goreleaser): update changelog configuration - uses the compare Gitea API - drop `sort` setting - remove the filter that excludes version bump entries --- .goreleaser.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 4b315c5..a3190f6 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -24,10 +24,7 @@ upx: lzma: true changelog: - sort: desc - filters: - exclude: - - "bump version to" + use: gitea archives: - format: binary From 9852f80461172d23230000420272c48f0cce0c89 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Fri, 8 Nov 2024 14:23:54 +0100 Subject: [PATCH 16/33] fix: restore filter that excludes version bump entries --- .goreleaser.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index a3190f6..48ad016 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -25,6 +25,9 @@ upx: changelog: use: gitea + filters: + exclude: + - "chore: bump version to" archives: - format: binary From 2032688c1f9ce981d1f8675a33339783ad472cf3 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sat, 9 Nov 2024 15:59:30 +0100 Subject: [PATCH 17/33] feat!: always retrieve version from `runtime/debug.Main.Version` or latest git tag - set version from runtime/debug.Main.Version - use latest git tag as fallback - allow GoTomatoVersion to be overwritten via ldflags - this will break `go build .` and `go install .` --- internal/metadata/version.go | 38 ++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/internal/metadata/version.go b/internal/metadata/version.go index ecac17b..1d76b3e 100644 --- a/internal/metadata/version.go +++ b/internal/metadata/version.go @@ -1,7 +1,37 @@ package metadata -import "strings" +import ( + "os/exec" + "runtime/debug" + "strings" +) -// This will be overwritten by goreleaser on build -var GoTomatoVersion = "devel" // The GoTomato version -var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version +var ( + GoTomatoVersion = "" // The GoTomato version + ProtocolVersion = "" // The protocol version +) + +func stripVersionPrefix(version string) string { + return strings.TrimLeft(version, "v") +} + +func getLatestTag() string { + bytes, _ := exec.Command("git", "describe", "--tags").Output() + output := strings.TrimSpace(string(bytes)) + return stripVersionPrefix(output) +} + +// set GoTomatoVersion from runtime/debug.Main.Version +// use latest git tag as fallback +// can be overwritten via ldflags (e,g. by goreleaser) +func init() { + if GoTomatoVersion == "" { + info, _ := debug.ReadBuildInfo() + if info.Main.Version != "(devel)" { + GoTomatoVersion = stripVersionPrefix(info.Main.Version) + } else { + GoTomatoVersion = getLatestTag() + } + } + ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] +} From 05a8701a263e063a6d4fa134638b91952c2f99a8 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Fri, 8 Nov 2024 14:22:54 +0100 Subject: [PATCH 18/33] feat: update `-version` output --- cmd/server/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index a109f38..2024fa2 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -28,8 +28,8 @@ func Start() { // show server and protocl version and exit if *showVersionFlag { - fmt.Println("Server-Version:", metadata.GoTomatoVersion) - fmt.Println("Protocol-Version:", metadata.ProtocolVersion) + fmt.Printf("GoTomato v%s\n", metadata.GoTomatoVersion) + fmt.Printf("Protocol-Version: %s\n", metadata.ProtocolVersion) os.Exit(0) } From 2f337bb9d69842c92f2af2c3525758b4c8943d88 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Fri, 8 Nov 2024 15:13:46 +0100 Subject: [PATCH 19/33] feat: add release management via `Task` - create `Taskfile.yml` - initial tasks - add new version tag - push to remote and run goreleaser - create snapshot via goreleaser --- Taskfile.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Taskfile.yml diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..77dfff5 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,32 @@ +# github.com/go-task/task/v3/cmd/task@latest +# Requirements: +# github.com/caarlos0/svu@latest +# github.com/goreleaser/goreleaser/v2@latest + +version: '3' + +tasks: + + release: + desc: Create and publish an new release + vars: + RELEASE: + sh: svu next + BRANCH: + sh: git branch --show-current + COMMIT: + sh: git rev-parse --short --verify {{.BRANCH}} + preconditions: + - sh: test "{{.BRANCH}}" == "main" + msg: "You must be on the main branch to release" + prompt: Create new release {{.RELEASE}} from {{.COMMIT}}@{{.BRANCH}}? + cmds: + - git tag {{.RELEASE}} + - git push + - git push origin tag {{.RELEASE}} + - goreleaser release --clean + + snapshot: + desc: Create a local snapshot release + cmds: + - goreleaser release --clean --snapshot From 13e2c2d0e406eb2fbb37b4d72a8643ac304c62d8 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sat, 9 Nov 2024 09:51:07 +0100 Subject: [PATCH 20/33] fix(goreleaser): don't force-remove `./dist` --- .goreleaser.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 48ad016..22dc0d9 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -4,7 +4,6 @@ version: 2 before: hooks: - - rm -fr ./dist - go mod tidy builds: From 8683cb2a6b21d4d82b217453f18988b684243675 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sat, 9 Nov 2024 10:42:26 +0100 Subject: [PATCH 21/33] chore: add yaml schemas to `Taskfile.yml` and `.goreleaser.yaml` --- .goreleaser.yaml | 1 + Taskfile.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 22dc0d9..9bdad83 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,4 +1,5 @@ # vim: set ts=2 sw=2 tw=0 fo=cnqoj +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json version: 2 diff --git a/Taskfile.yml b/Taskfile.yml index 77dfff5..8efbf3a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=https://taskfile.dev/schema.json +# # github.com/go-task/task/v3/cmd/task@latest # Requirements: # github.com/caarlos0/svu@latest From 64f790bf90cb31b74d2fa9f2636e6af829236f4d Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sat, 9 Nov 2024 22:37:52 +0100 Subject: [PATCH 22/33] feat(goreleaser): update build command to use `.ModulePath` variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - change hardcoded module path to dynamic reference 🤖 --- .goreleaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 9bdad83..77a3e60 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -16,7 +16,7 @@ builds: env: - CGO_ENABLED=0 ldflags: - - -s -w -X git.smsvc.net/pomodoro/GoTomato/internal/metadata.GoTomatoVersion={{.Version}} + - -s -w -X {{.ModulePath}}/internal/metadata.GoTomatoVersion={{.Version}} upx: - enabled: true From b3f403cf1afc2ee4c68866731bbfd18b1df8cded Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Sun, 10 Nov 2024 16:47:57 +0100 Subject: [PATCH 23/33] fix(renovate): make Go deps always a "chore" - add package rules to set semantic commit type for gomod --- .renovaterc.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.renovaterc.json b/.renovaterc.json index ff27ef5..aceb001 100644 --- a/.renovaterc.json +++ b/.renovaterc.json @@ -2,5 +2,11 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "local>infrastructure/renovate-config" + ], + "packageRules": [ + { + "matchManagers": ["gomod"], + "semanticCommitType": "chore" + } ] } From 31179d4af4fbfe0b7a8f0c41460b489224091609 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Mon, 18 Nov 2024 08:11:39 +0100 Subject: [PATCH 24/33] break: update terminology from "Work" to "Focus" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - change mode from "Work" to "Focus" in server messages - modify pomodoro configuration to use "Focus" instead of "Work" - adjust default settings to reflect new terminology - ensure all references to work duration are updated to focus duration - update variable names in HTML and JavaScript for clarity 🤖 --- README.md | 26 +++++++++++++------------- cmd/server/main.go | 10 +++++----- index.html | 8 ++++---- internal/pomodoro/pomodoro.go | 12 ++++++------ internal/shared/configDefaults.go | 2 +- internal/shared/state.go | 2 +- internal/websocket/client_commands.go | 2 +- pkg/models/config.go | 4 ++-- pkg/models/server.go | 2 +- 9 files changed, 34 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index c2d9e51..596cb46 100644 --- a/README.md +++ b/README.md @@ -34,17 +34,17 @@ Here are the available commands: | `pause` | Pauses the current session | `{"command": "pause", "password": ""}` | | `resume` | Resumes a paused session | `{"command": "resume", "password": ""}` | | `reset` | Stops and resets the current session | `{"command": "reset", "password": ""}` | -| `updateSettings` | Update Pomodoro settings | `{"command": "updateSettings", "password": "", "settings": {"work": 600, "shortBreak": 60, "longBreak": 300, "sessions": 2}}` | +| `updateSettings` | Update Pomodoro settings | `{"command": "updateSettings", "password": "", "settings": {"focus": 600, "shortBreak": 60, "longBreak": 300, "sessions": 2}}` | #### Update Settings Command (`updateSettings`) -The `updateSettings` command allows clients to modify the Pomodoro timer configuration, including the length of work sessions, short breaks, long breaks, and the total number of sessions in a cycle. This command must include a valid password to be accepted by the server. The updateSettings command can be used when the timer is stopped. +The `updateSettings` command allows clients to modify the Pomodoro timer configuration, including the length of focus sessions, short breaks, long breaks, and the total number of sessions in a cycle. This command must include a valid password to be accepted by the server. The updateSettings command can be used when the timer is stopped. - Fields in the `settings` Object: - - `work`: Length of the work session (in seconds). + - `focus`: Length of the focus session (in seconds). - `shortBreak`: Length of the short break (in seconds). - `longBreak`: Length of the long break (in seconds). - - `sessions`: Total number of work/break sessions in the Pomodoro cycle. + - `sessions`: Total number of focus/break sessions in the Pomodoro cycle. All fields are mandatory and may not be ommitted. @@ -52,14 +52,14 @@ All fields are mandatory and may not be ommitted. The server periodically (every second) sends JSON-encoded messages to all connected clients to update them on the current state of the Pomodoro session. These messages contain the following fields: -- mode: Indicates the current phase of the Pomodoro session ("Work", "ShortBreak", "LongBreak", "End" or "Idle"). +- mode: Indicates the current phase of the Pomodoro session ("Focus", "ShortBreak", "LongBreak", "End" or "Idle"). - "End" is send only once, after all sessions are finished - settings: Contains the current Pomodoro settings: - - work: Length of the work session in seconds (e.g., 1500 for 25 minutes). + - focus: Length of the focus session in seconds (e.g., 1500 for 25 minutes). - shortBreak: Length of the short break in seconds (e.g., 300 for 5 minutes). - longBreak: Length of the long break in seconds (e.g., 900 for 15 minutes). - - sessions: The total number of work/break sessions (e.g., 4). -- session: The current session number (e.g., 1 for the first work session). + - sessions: The total number of focus/break sessions (e.g., 4). +- session: The current session number (e.g., 1 for the first focus session). - time_left: The remaining time for the current mode, in seconds (e.g., 900 for 15 minutes). - ongoing: Whether a Pomodoro session is currently ongoing. - paused: Whether the timer is paused. @@ -67,11 +67,11 @@ The server periodically (every second) sends JSON-encoded messages to all connec | Message Type | Example | | --- | --- | -| Welcome Message | {"mode":"Idle", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":1500, "ongoing":false, "paused":false, "version":"0"} | -| Session Running | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":1, "time_left":900, "ongoing":true, "paused":false, "version":"0"} | -| Session Running | {"mode":"ShortBreak", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":50, "ongoing":true, "paused":false, "version":"0"} | -| Session Paused | {"mode":"Work", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":456, "ongoing":true, "paused":true, "version":"0"} | -| Session End/Reset | {"mode":"End", "settings":{"work":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":0, "ongoing":false, "paused":false, "version":"0"} | +| Welcome Message | {"mode":"Idle", "settings":{"focus":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":1500, "ongoing":false, "paused":false, "version":"0"} | +| Session Running | {"mode":"Focus", "settings":{"focus":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":1, "time_left":900, "ongoing":true, "paused":false, "version":"0"} | +| Session Running | {"mode":"ShortBreak", "settings":{"focus":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":50, "ongoing":true, "paused":false, "version":"0"} | +| Session Paused | {"mode":"Focus", "settings":{"focus":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":2, "time_left":456, "ongoing":true, "paused":true, "version":"0"} | +| Session End/Reset | {"mode":"End", "settings":{"focus":1500, "shortBreak":300, "longBreak":900, "sessions":4}, "session":0, "time_left":0, "ongoing":false, "paused":false, "version":"0"} | ## Testing diff --git a/cmd/server/main.go b/cmd/server/main.go index 2024fa2..330afec 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -16,10 +16,10 @@ import ( var ( // define CLI flags - listenAddress = flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on") - listenPort = flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on") - password = flag.String("password", "", "Control password for pomodoro session (optional)") - showVersionFlag = flag.Bool("version", false, "Output version") + listenAddress = flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on") + listenPort = flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on") + password = flag.String("password", "", "Control password for pomodoro session (optional)") + showVersion = flag.Bool("version", false, "Output version") ) // Start the pomodoro server @@ -27,7 +27,7 @@ func Start() { flag.Parse() // show server and protocl version and exit - if *showVersionFlag { + if *showVersion { fmt.Printf("GoTomato v%s\n", metadata.GoTomatoVersion) fmt.Printf("Protocol-Version: %s\n", metadata.ProtocolVersion) os.Exit(0) diff --git a/index.html b/index.html index f04bf34..a75e885 100644 --- a/index.html +++ b/index.html @@ -40,8 +40,8 @@

- - + +
@@ -98,7 +98,7 @@ document.getElementById("saveButton").addEventListener("click", function () { // Get the values from the input fields var password = document.getElementById("password").value; - var work = parseInt(document.getElementById("workDuration").value); + var focus = parseInt(document.getElementById("focusDuration").value); var shortBreak = parseInt(document.getElementById("shortBreakDuration").value); var longBreak = parseInt(document.getElementById("longBreakDuration").value); var sessions = parseInt(document.getElementById("sessions").value); @@ -108,7 +108,7 @@ command: "updateSettings", password: password, settings: { - work: work, + focus: focus, shortBreak: shortBreak, longBreak: longBreak, sessions: sessions diff --git a/internal/pomodoro/pomodoro.go b/internal/pomodoro/pomodoro.go index a7bcc00..1dc0e46 100644 --- a/internal/pomodoro/pomodoro.go +++ b/internal/pomodoro/pomodoro.go @@ -26,7 +26,7 @@ func waitForTimer(t Timer) bool { } } -// RunPomodoro iterates the Pomodoro work/break sessions +// RunPomodoro iterates the Pomodoro focus/break sessions func RunPomodoro() { mu.Lock() shared.State.Ongoing = true @@ -40,9 +40,9 @@ func RunPomodoro() { shared.State.Session = session - // Work - shared.State.Mode = "Work" - timer.StartAsync(pomodoroConfig.Work) + // Focus + shared.State.Mode = "Focus" + timer.StartAsync(pomodoroConfig.Focus) if !waitForTimer(timer) { break } @@ -74,7 +74,7 @@ func RunPomodoro() { shared.State.Mode = "Idle" shared.State.Session = 0 - shared.State.TimeLeft = shared.State.Settings.Work + shared.State.TimeLeft = shared.State.Settings.Focus } func ResetPomodoro() { @@ -111,6 +111,6 @@ func IsPomodoroPaused() bool { func UpdateSettings(settings models.PomodoroConfig) { if settings != (models.PomodoroConfig{}) { shared.State.Settings = settings - shared.State.TimeLeft = settings.Work + shared.State.TimeLeft = settings.Focus } } diff --git a/internal/shared/configDefaults.go b/internal/shared/configDefaults.go index e125da8..5b668cc 100644 --- a/internal/shared/configDefaults.go +++ b/internal/shared/configDefaults.go @@ -10,7 +10,7 @@ var DefaultServerConfig = models.ServerConfig{ // The default pomodoro config if nothing else is set var DefaultPomodoroConfig = models.PomodoroConfig{ - Work: 25 * 60, + Focus: 25 * 60, ShortBreak: 5 * 60, LongBreak: 15 * 60, Sessions: 4, diff --git a/internal/shared/state.go b/internal/shared/state.go index e21d4d3..00934f5 100644 --- a/internal/shared/state.go +++ b/internal/shared/state.go @@ -10,7 +10,7 @@ var State = models.ServerMessage{ Mode: "Idle", Settings: DefaultPomodoroConfig, Session: 0, - TimeLeft: DefaultPomodoroConfig.Work, + TimeLeft: DefaultPomodoroConfig.Focus, Ongoing: false, Paused: false, ProtocolVersion: metadata.ProtocolVersion, diff --git a/internal/websocket/client_commands.go b/internal/websocket/client_commands.go index bdb6e7a..7149faa 100644 --- a/internal/websocket/client_commands.go +++ b/internal/websocket/client_commands.go @@ -10,7 +10,7 @@ import ( ) func checkSettings(settings models.PomodoroConfig) bool { - return settings.Work > 0 && settings.ShortBreak > 0 && settings.LongBreak > 0 && settings.Sessions > 0 + return settings.Focus > 0 && settings.ShortBreak > 0 && settings.LongBreak > 0 && settings.Sessions > 0 } // Listens for commands from a client and handles them diff --git a/pkg/models/config.go b/pkg/models/config.go index 1852165..b1a41ac 100644 --- a/pkg/models/config.go +++ b/pkg/models/config.go @@ -4,7 +4,7 @@ import "fmt" // Represents the configuration of a pomodoro type PomodoroConfig struct { - Work int `json:"work"` // Length of work sessions in seconds + Focus int `json:"focus"` // Length of focus sessions in seconds ShortBreak int `json:"shortBreak"` // Length of short break in seconds LongBreak int `json:"longBreak"` // Length of long break in seconds Sessions int `json:"sessions"` // Number of total sessions @@ -12,7 +12,7 @@ type PomodoroConfig struct { // Stringer interface for the PomodocoConfig model func (c PomodoroConfig) String() string { - return fmt.Sprintf("{work: %d, short: %d, long: %d, sessions: %d}", c.Work, c.ShortBreak, c.LongBreak, c.Sessions) + return fmt.Sprintf("{focus: %d, short: %d, long: %d, sessions: %d}", c.Focus, c.ShortBreak, c.LongBreak, c.Sessions) } // Represents the server configuration diff --git a/pkg/models/server.go b/pkg/models/server.go index 6aa914a..f495505 100644 --- a/pkg/models/server.go +++ b/pkg/models/server.go @@ -2,7 +2,7 @@ package models // Represents the data sent to the client via WebSocket type ServerMessage struct { - Mode string `json:"mode"` // "Idle", "Work", "ShortBreak", "LongBreak" or "End" + Mode string `json:"mode"` // "Idle", "Focus", "ShortBreak", "LongBreak" or "End" Settings PomodoroConfig `json:"settings"` // The currrent pomodoro settings Session int `json:"session"` // Current session number TimeLeft int `json:"time_left"` // Remaining time in seconds From 256837c1302032516e2d4eed1ca210a7062932bd Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Mon, 18 Nov 2024 08:57:32 +0100 Subject: [PATCH 25/33] feat: add client instructions to usage output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add custom usage message - include instructions for WebSocket client connection 🤖 --- cmd/server/main.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/server/main.go b/cmd/server/main.go index 330afec..25fc443 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -24,6 +24,13 @@ var ( // Start the pomodoro server func Start() { + // Update usage output + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", "GoTomato") + flag.PrintDefaults() + fmt.Println("\nPoint your client to 'ws://:/ws'") + } + flag.Parse() // show server and protocl version and exit From e8e65c4f3a036c1aaf2d744190fb79ae72db6569 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Mon, 18 Nov 2024 17:43:49 +0100 Subject: [PATCH 26/33] break: remove `/ws` from websocket path --- cmd/server/main.go | 4 ++-- index.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 25fc443..d8eb8f6 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -28,7 +28,7 @@ func Start() { flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", "GoTomato") flag.PrintDefaults() - fmt.Println("\nPoint your client to 'ws://:/ws'") + fmt.Println("\nPoint your client to 'ws://:'") } flag.Parse() @@ -52,7 +52,7 @@ func Start() { // start connection handler and broadcast r := http.NewServeMux() - r.HandleFunc("/ws", websocket.HandleConnection) + r.HandleFunc("/", websocket.HandleConnection) go websocket.SendPermanentBroadCastMessage() helper.Logger.Info("GoTomato started", "version", metadata.GoTomatoVersion) diff --git a/index.html b/index.html index a75e885..1de404b 100644 --- a/index.html +++ b/index.html @@ -64,7 +64,7 @@