diff --git a/cmd/client/main.go b/cmd/client/main.go index 80f3c5b..11243f1 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -4,42 +4,75 @@ import ( "atomicgo.dev/cursor" "flag" - "git.smsvc.net/pomodoro/ChronoTomato/internal/frontend" "git.smsvc.net/pomodoro/ChronoTomato/internal/helper" + "git.smsvc.net/pomodoro/ChronoTomato/internal/shared" "git.smsvc.net/pomodoro/ChronoTomato/internal/websocket" - ChronoTomato "git.smsvc.net/pomodoro/ChronoTomato/pkg/models" - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" -) - -var ( - config ChronoTomato.Config - - parameter_url = flag.String("url", "", "GoTomato Server URL (eg ws://localhost:8080/ws)") - parameter_password = flag.String("password", "", "Control password for pomodoro session") - configfile = flag.String("config", "", "Path to config file") + "atomicgo.dev/keyboard" + "atomicgo.dev/keyboard/keys" + "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) func Start() { - flag.Parse() - cursor.Hide() defer cursor.Show() - // read cli parameters if no config file passed - if *configfile == "" { - config.URL = *parameter_url - config.Password = *parameter_password - } else { - // otherwise read config - config = helper.ParseConfig(*configfile) + parameter_url := flag.String("url", "", "GoTomato Server URL (eg ws://localhost:8080/ws)") + parameter_password := flag.String("password", "", "Control password for pomodoro session (optional)") + configfile := flag.String("config", "~/.config/ChronoTomato.yml", "path to config file (optional)") + flag.Parse() + + config := helper.ParseConfig(*configfile) + + url := *parameter_url + if url == "" { + url = config.URL } - conn := websocket.Connect(config.URL) + password := *parameter_password + if password == "" { + password = config.Password + } - channel := make(chan GoTomato.ServerMessage, 2) - go websocket.ProcessServerMessages(conn, channel) - frontend.Handler(conn, config, channel) + conn := websocket.Connect(url) + + go websocket.ProcessServerMessages(conn) + + pomodoro := &shared.ServerMessage + keyboard.Listen(func(key keys.Key) (stop bool, err error) { + select { + case <-websocket.Done: + return true, nil + default: + switch key.String() { + case "space": + if !pomodoro.Ongoing { + websocket.SendCmd(conn, password, "start") + return false, nil + } + if pomodoro.Paused { + websocket.SendCmd(conn, password, "resume") + return false, nil + } else { + websocket.SendCmd(conn, password, "pause") + return false, nil + } + case "s": + websocket.SendCmd(conn, password, "stop") + return false, nil + case "r": + + if config.PomodoroConfig != (models.GoTomatoPomodoroConfig{}) { + websocket.Send_updateSettings(conn, password, config.PomodoroConfig) + } + return false, nil + case "q": + return true, nil + } + } + + return false, nil + }) websocket.Disconnect(conn) } diff --git a/internal/frontend/keyhandler.go b/internal/frontend/keyhandler.go deleted file mode 100644 index 0c0ed45..0000000 --- a/internal/frontend/keyhandler.go +++ /dev/null @@ -1,50 +0,0 @@ -package frontend - -import ( - "atomicgo.dev/keyboard" - "atomicgo.dev/keyboard/keys" - ws "github.com/gorilla/websocket" - - "git.smsvc.net/pomodoro/ChronoTomato/internal/websocket" - - ChronoTomato "git.smsvc.net/pomodoro/ChronoTomato/pkg/models" - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" -) - -func start_pause_resume(message *GoTomato.ServerMessage) string { - if !message.Ongoing { - return "start" - } - if message.Paused { - return "resume" - } else { - return "pause" - } -} - -func keyhandler(conn *ws.Conn, config ChronoTomato.Config, message *GoTomato.ServerMessage, quit chan bool) { - keyboard.Listen(func(key keys.Key) (stop bool, err error) { - select { - case <-websocket.Done: - quit <- true - return true, nil - default: - switch key.String() { - case "space": - cmd := start_pause_resume(message) - websocket.SendCmd(conn, config.Password, cmd) - case "s": - websocket.SendCmd(conn, config.Password, "stop") - case "r": - if config.PomodoroConfig != (GoTomato.GoTomatoPomodoroConfig{}) { - websocket.Send_updateSettings(conn, config.Password, config.PomodoroConfig) - } - case "q": - quit <- true - return true, nil - } - } - - return false, nil - }) -} diff --git a/internal/frontend/main.go b/internal/frontend/main.go deleted file mode 100644 index c876bd5..0000000 --- a/internal/frontend/main.go +++ /dev/null @@ -1,25 +0,0 @@ -package frontend - -import ( - "github.com/gorilla/websocket" - - ChronoTomato "git.smsvc.net/pomodoro/ChronoTomato/pkg/models" - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" -) - -func Handler(conn *websocket.Conn, config ChronoTomato.Config, channel <-chan GoTomato.ServerMessage) { - var message GoTomato.ServerMessage - - keyhandler_quit := make(chan bool, 1) - go keyhandler(conn, config, &message, keyhandler_quit) - - for { - select { - case message = <-channel: - desktopNotifications(message) - terminalOutput(message) - case <-keyhandler_quit: - return - } - } -} diff --git a/internal/helper/config.go b/internal/helper/config.go index 4cd2f7a..bdeed92 100644 --- a/internal/helper/config.go +++ b/internal/helper/config.go @@ -1,32 +1,32 @@ package helper import ( + "git.smsvc.net/pomodoro/ChronoTomato/pkg/models" "github.com/charmbracelet/log" "gopkg.in/yaml.v3" "os" "path/filepath" "strings" - - ChronoTomato "git.smsvc.net/pomodoro/ChronoTomato/pkg/models" ) -func ParseConfig(filename string) ChronoTomato.Config { - var config ChronoTomato.Config - +func ParseConfig(filename string) models.ConfigFile { + var config models.ConfigFile if strings.HasPrefix(filename, "~/") { dirname, _ := os.UserHomeDir() filename = filepath.Join(dirname, filename[2:]) } - yamlFile, err := os.ReadFile(filename) if err != nil { - log.Fatal("Error opening config file!", "reason", err) + log.Warn("Error opening config file!", "reason", err) + log.Warn("Using defaults") + return models.ConfigFile{ + URL: "ws://localhost:8080/ws", + } } - err = yaml.Unmarshal(yamlFile, &config) if err != nil { log.Fatalf("Unmarshal: %v", err) } - return config + } diff --git a/internal/frontend/notification.go b/internal/notifications/desktop.go similarity index 82% rename from internal/frontend/notification.go rename to internal/notifications/desktop.go index 250c5db..5f35efd 100644 --- a/internal/frontend/notification.go +++ b/internal/notifications/desktop.go @@ -1,18 +1,16 @@ -package frontend +package notifications import ( + "git.smsvc.net/pomodoro/ChronoTomato/internal/shared" "fmt" "github.com/gen2brain/beeep" - - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) -func desktopNotifications(pomodoro GoTomato.ServerMessage) { +func DesktopNotifications() { + var duration int + var notification string - var ( - duration int - notification string - ) + pomodoro := &shared.ServerMessage mode := pomodoro.Mode session := pomodoro.Session diff --git a/internal/frontend/terminal.go b/internal/notifications/terminal.go similarity index 82% rename from internal/frontend/terminal.go rename to internal/notifications/terminal.go index 70d9deb..acf0bd5 100644 --- a/internal/frontend/terminal.go +++ b/internal/notifications/terminal.go @@ -1,18 +1,17 @@ -package frontend +package notifications import ( "fmt" + "git.smsvc.net/pomodoro/ChronoTomato/internal/shared" "github.com/fatih/color" "strings" - - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) -func terminalOutput(pomodoro GoTomato.ServerMessage) { - var ( - modePrefix string - timerOutput string - ) +func TerminalOutput() { + var modePrefix string + var timerOutput string + + pomodoro := &shared.ServerMessage fmt.Print("\033[H\033[2J") // Clears the screen @@ -32,6 +31,7 @@ func terminalOutput(pomodoro GoTomato.ServerMessage) { modePrefix = " " if pomodoro.Paused { modePrefix = " " + } else { } minutes := pomodoro.TimeLeft / 60 seconds := pomodoro.TimeLeft % 60 diff --git a/internal/shared/state.go b/internal/shared/state.go new file mode 100644 index 0000000..2944910 --- /dev/null +++ b/internal/shared/state.go @@ -0,0 +1,7 @@ +package shared + +import ( + "git.smsvc.net/pomodoro/GoTomato/pkg/models" +) + +var ServerMessage models.ServerMessage diff --git a/internal/websocket/receive.go b/internal/websocket/receive.go index d17cac6..889a8ce 100644 --- a/internal/websocket/receive.go +++ b/internal/websocket/receive.go @@ -3,23 +3,22 @@ package websocket import ( "encoding/json" "fmt" + "git.smsvc.net/pomodoro/ChronoTomato/internal/notifications" + "git.smsvc.net/pomodoro/ChronoTomato/internal/shared" "github.com/charmbracelet/log" "github.com/gorilla/websocket" - - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) var Done = make(chan struct{}) -func ProcessServerMessages(conn *websocket.Conn, channel chan<- GoTomato.ServerMessage) { - var serverMessage GoTomato.ServerMessage +func ProcessServerMessages(conn *websocket.Conn) { defer close(Done) for { _, message, err := conn.ReadMessage() if err != nil { - if websocket.IsCloseError(err, websocket.CloseNormalClosure) { + if websocket.IsCloseError(err, 1000) { // Ignore normal closure and exit gracefully return } @@ -29,12 +28,14 @@ func ProcessServerMessages(conn *websocket.Conn, channel chan<- GoTomato.ServerM return } - err = json.Unmarshal(message, &serverMessage) + err = json.Unmarshal(message, &shared.ServerMessage) if err != nil { log.Error("Error unmarshalling!", "reason", err) continue } - channel <- serverMessage + notifications.DesktopNotifications() + notifications.TerminalOutput() } + } diff --git a/internal/websocket/send.go b/internal/websocket/send.go index 90df844..dec081c 100644 --- a/internal/websocket/send.go +++ b/internal/websocket/send.go @@ -2,14 +2,14 @@ package websocket import ( "encoding/json" + "git.smsvc.net/pomodoro/GoTomato/pkg/models" "github.com/charmbracelet/log" "github.com/gorilla/websocket" - - GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" ) -func sendClientCommand(conn *websocket.Conn, msg GoTomato.ClientCommand) { +func sendClientCommand(conn *websocket.Conn, msg models.ClientCommand) { messageBytes, err := json.Marshal(msg) + if err != nil { log.Error("Error marshalling!", "reason", err) return @@ -23,7 +23,7 @@ func sendClientCommand(conn *websocket.Conn, msg GoTomato.ClientCommand) { } func SendCmd(conn *websocket.Conn, pwd string, cmd string) { - message := GoTomato.ClientCommand{ + message := models.ClientCommand{ Command: cmd, Password: pwd, } @@ -31,8 +31,8 @@ func SendCmd(conn *websocket.Conn, pwd string, cmd string) { sendClientCommand(conn, message) } -func Send_updateSettings(conn *websocket.Conn, pwd string, settings GoTomato.GoTomatoPomodoroConfig) { - message := GoTomato.ClientCommand{ +func Send_updateSettings(conn *websocket.Conn, pwd string, settings models.GoTomatoPomodoroConfig) { + message := models.ClientCommand{ Command: "updateSettings", Password: pwd, PomodoroSettings: settings, diff --git a/pkg/models/configfile.go b/pkg/models/configfile.go index b8ea721..28c3fa9 100644 --- a/pkg/models/configfile.go +++ b/pkg/models/configfile.go @@ -1,9 +1,11 @@ package models -import GoTomato "git.smsvc.net/pomodoro/GoTomato/pkg/models" +import ( + "git.smsvc.net/pomodoro/GoTomato/pkg/models" +) -type Config struct { - URL string `yaml:"url"` - Password string `yaml:"password"` - PomodoroConfig GoTomato.GoTomatoPomodoroConfig `yaml:"config"` +type ConfigFile struct { + URL string `yaml:"url"` + Password string `yaml:"password"` + PomodoroConfig models.GoTomatoPomodoroConfig `yaml:"config"` }