doc: add and improve comments
This commit is contained in:
parent
d83acc77b2
commit
83a3a3b052
12 changed files with 67 additions and 41 deletions
|
@ -14,35 +14,42 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Define CLI flags
|
// define CLI flags
|
||||||
listenAddress = flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on")
|
listenAddress = flag.String("listenAddress", shared.DefaultServerConfig.ListenAddress, "IP address to listen on")
|
||||||
listenPort = flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on")
|
listenPort = flag.Int("listenPort", shared.DefaultServerConfig.ListenPort, "Port to listen on")
|
||||||
password = flag.String("password", "", "Control password for pomodoro session (optional)")
|
password = flag.String("password", "", "Control password for pomodoro session (optional)")
|
||||||
showVersionFlag = flag.Bool("version", false, "Output version")
|
showVersionFlag = flag.Bool("version", false, "Output version")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Start the pomodoro server
|
||||||
func Start() {
|
func Start() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
// show server and protocl version and exit
|
||||||
if *showVersionFlag {
|
if *showVersionFlag {
|
||||||
fmt.Println("App-Version:", metadata.GoTomatoVersion)
|
fmt.Println("Server-Version:", metadata.GoTomatoVersion)
|
||||||
fmt.Println("Protocol-Version:", metadata.ProtocolVersion)
|
fmt.Println("Protocol-Version:", metadata.ProtocolVersion)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set server config
|
||||||
serverConfig := models.ServerConfig{
|
serverConfig := models.ServerConfig{
|
||||||
ListenAddress: *listenAddress,
|
ListenAddress: *listenAddress,
|
||||||
ListenPort: *listenPort,
|
ListenPort: *listenPort,
|
||||||
}
|
}
|
||||||
shared.PomodoroPassword = *password
|
shared.PomodoroPassword = *password
|
||||||
|
|
||||||
|
// define listen address for websocket
|
||||||
listen := fmt.Sprintf("%s:%d", serverConfig.ListenAddress, serverConfig.ListenPort)
|
listen := fmt.Sprintf("%s:%d", serverConfig.ListenAddress, serverConfig.ListenPort)
|
||||||
|
|
||||||
|
// start connection handler and broadcast
|
||||||
http.HandleFunc("/ws", websocket.HandleConnection)
|
http.HandleFunc("/ws", websocket.HandleConnection)
|
||||||
go websocket.SendPermanentBroadCastMessage()
|
go websocket.SendPermanentBroadCastMessage()
|
||||||
|
|
||||||
log.Info("GoTomato started", "version", metadata.GoTomatoVersion)
|
log.Info("GoTomato started", "version", metadata.GoTomatoVersion)
|
||||||
log.Info("Websocket listening", "address", listen)
|
log.Info("Websocket listening", "address", listen)
|
||||||
|
|
||||||
|
// start the listener
|
||||||
err := http.ListenAndServe(listen, nil)
|
err := http.ListenAndServe(listen, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error starting server:", "msg", err)
|
log.Fatal("Error starting server:", "msg", err)
|
||||||
|
|
|
@ -2,5 +2,5 @@ package metadata
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
const GoTomatoVersion = "v0.0.4" // The GoTomato Version
|
const GoTomatoVersion = "v0.0.4" // The GoTomato version
|
||||||
var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0]
|
var ProtocolVersion = strings.Split(GoTomatoVersion, ".")[0] // The protocol version
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
var mu sync.Mutex // to synchronize access to shared state
|
var mu sync.Mutex // to synchronize access to shared state
|
||||||
var timer Timer
|
var timer Timer
|
||||||
|
|
||||||
|
// Update `State` with the remaining seconds of the passed timer
|
||||||
|
// until the timer sends an End or Abort signal
|
||||||
func waitForTimer(t Timer) bool {
|
func waitForTimer(t Timer) bool {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -24,7 +26,7 @@ func waitForTimer(t Timer) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunPomodoro iterates the Pomodoro work/break sessions.
|
// RunPomodoro iterates the Pomodoro work/break sessions
|
||||||
func RunPomodoro() {
|
func RunPomodoro() {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
shared.State.Ongoing = true
|
shared.State.Ongoing = true
|
||||||
|
@ -38,12 +40,14 @@ func RunPomodoro() {
|
||||||
|
|
||||||
shared.State.Session = session
|
shared.State.Session = session
|
||||||
|
|
||||||
|
// Work
|
||||||
shared.State.Mode = "Work"
|
shared.State.Mode = "Work"
|
||||||
go timer.Start(pomodoroConfig.Work)
|
go timer.Start(pomodoroConfig.Work)
|
||||||
if !waitForTimer(timer) {
|
if !waitForTimer(timer) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Breaks
|
||||||
if session < pomodoroConfig.Sessions {
|
if session < pomodoroConfig.Sessions {
|
||||||
shared.State.Mode = "ShortBreak"
|
shared.State.Mode = "ShortBreak"
|
||||||
go timer.Start(pomodoroConfig.ShortBreak)
|
go timer.Start(pomodoroConfig.ShortBreak)
|
||||||
|
@ -56,6 +60,8 @@ func RunPomodoro() {
|
||||||
if !waitForTimer(timer) {
|
if !waitForTimer(timer) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send "End" state for one second
|
||||||
shared.State.Mode = "End"
|
shared.State.Mode = "End"
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
@ -92,13 +98,13 @@ func ResumePomodoro() {
|
||||||
|
|
||||||
func IsPomodoroOngoing() bool {
|
func IsPomodoroOngoing() bool {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock() // Ensures that the mutex is unlocked after the function is done
|
defer mu.Unlock()
|
||||||
return shared.State.Ongoing
|
return shared.State.Ongoing
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsPomodoroPaused() bool {
|
func IsPomodoroPaused() bool {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock() // Ensures that the mutex is unlocked after the function is done
|
defer mu.Unlock()
|
||||||
return shared.State.Paused
|
return shared.State.Paused
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,17 @@ package pomodoro
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
// Represents a timer
|
||||||
type Timer struct {
|
type Timer struct {
|
||||||
TimeLeft chan int // time left
|
TimeLeft chan int // signals time left on every second
|
||||||
End chan bool // signal on successful end
|
End chan bool // signal on successful end
|
||||||
Abort chan bool // signal on premature end
|
Abort chan bool // signal on premature end
|
||||||
stop chan bool
|
stop chan bool // internal channel
|
||||||
wait chan bool
|
wait chan bool // internal channel
|
||||||
resume chan bool
|
resume chan bool // internal channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initializes a new timer with fresh channels
|
||||||
func (t Timer) Init() Timer {
|
func (t Timer) Init() Timer {
|
||||||
return Timer{
|
return Timer{
|
||||||
TimeLeft: make(chan int),
|
TimeLeft: make(chan int),
|
||||||
|
@ -22,25 +24,28 @@ func (t Timer) Init() Timer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the timer
|
||||||
func (t *Timer) Start(duration int) {
|
func (t *Timer) Start(duration int) {
|
||||||
tick := time.NewTicker(time.Second)
|
tick := time.NewTicker(time.Second)
|
||||||
for timeLeft := duration; timeLeft > 0; {
|
go func() {
|
||||||
select {
|
for timeLeft := duration; timeLeft > 0; {
|
||||||
case <-t.stop:
|
select {
|
||||||
t.Abort <- true
|
case <-t.stop:
|
||||||
return
|
t.Abort <- true
|
||||||
case <-t.wait:
|
return
|
||||||
<-t.resume
|
case <-t.wait:
|
||||||
continue
|
<-t.resume
|
||||||
case <-tick.C:
|
continue
|
||||||
timeLeft--
|
case <-tick.C:
|
||||||
default:
|
timeLeft--
|
||||||
t.TimeLeft <- timeLeft
|
default:
|
||||||
|
t.TimeLeft <- timeLeft
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
t.TimeLeft <- 0
|
||||||
t.TimeLeft <- 0
|
|
||||||
|
|
||||||
t.End <- true
|
t.End <- true
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Timer) Stop() {
|
func (t *Timer) Stop() {
|
||||||
|
|
|
@ -2,11 +2,13 @@ package shared
|
||||||
|
|
||||||
import "git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
import "git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
||||||
|
|
||||||
|
// The default server config if nothing else is set
|
||||||
var DefaultServerConfig = models.ServerConfig{
|
var DefaultServerConfig = models.ServerConfig{
|
||||||
ListenAddress: "0.0.0.0",
|
ListenAddress: "0.0.0.0",
|
||||||
ListenPort: 8080,
|
ListenPort: 8080,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The default pomodoro config if nothing else is set
|
||||||
var DefaultPomodoroConfig = models.PomodoroConfig{
|
var DefaultPomodoroConfig = models.PomodoroConfig{
|
||||||
Work: 25 * 60,
|
Work: 25 * 60,
|
||||||
ShortBreak: 5 * 60,
|
ShortBreak: 5 * 60,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
"git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The global state of the pomodoro
|
||||||
var State = models.ServerMessage{
|
var State = models.ServerMessage{
|
||||||
Mode: "Idle",
|
Mode: "Idle",
|
||||||
Settings: DefaultPomodoroConfig,
|
Settings: DefaultPomodoroConfig,
|
||||||
|
@ -15,4 +16,5 @@ var State = models.ServerMessage{
|
||||||
ProtocolVersion: metadata.ProtocolVersion,
|
ProtocolVersion: metadata.ProtocolVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The password needed to execute client commands or change the pomodoro config
|
||||||
var PomodoroPassword string
|
var PomodoroPassword string
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
|
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sends continous messages to all connected WebSocket clients.
|
// Sends continous messages to all connected WebSocket clients
|
||||||
func SendPermanentBroadCastMessage() {
|
func SendPermanentBroadCastMessage() {
|
||||||
tick := time.NewTicker(time.Second)
|
tick := time.NewTicker(time.Second)
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
"git.smsvc.net/pomodoro/GoTomato/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// handleClientCommands listens for commands from WebSocket clients
|
// Listens for commands from a client and handles them
|
||||||
func handleClientCommands(ws *websocket.Conn) {
|
func handleClientCommands(ws *websocket.Conn) {
|
||||||
for {
|
for {
|
||||||
var clientCommand models.ClientCommand
|
var clientCommand models.ClientCommand
|
||||||
|
|
|
@ -13,12 +13,12 @@ import (
|
||||||
var Clients = make(map[*websocket.Conn]*models.Client)
|
var Clients = make(map[*websocket.Conn]*models.Client)
|
||||||
var mu sync.Mutex // Mutex to protect access to the Clients map
|
var mu sync.Mutex // Mutex to protect access to the Clients map
|
||||||
|
|
||||||
// Upgrader to upgrade HTTP requests to WebSocket connections
|
// Upgrade HTTP requests to WebSocket connections
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleConnection upgrades HTTP requests to WebSocket connections and manages the client lifecycle.
|
// Upgrades HTTP requests to WebSocket connections and manages the client lifecycle
|
||||||
func HandleConnection(w http.ResponseWriter, r *http.Request) {
|
func HandleConnection(w http.ResponseWriter, r *http.Request) {
|
||||||
// Upgrade initial GET request to a WebSocket
|
// Upgrade initial GET request to a WebSocket
|
||||||
ws, err := upgrader.Upgrade(w, r, nil)
|
ws, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
|
|
@ -6,19 +6,21 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientCommand represents a command from the client (start/stop).
|
// Represents a command from the client (start/stop)
|
||||||
type ClientCommand struct {
|
type ClientCommand struct {
|
||||||
Command string `json:"command"` // comman send to the server
|
Command string `json:"command"` // Command send to the server
|
||||||
Password string `json:"password"` // pomodoro control password
|
Password string `json:"password"` // Pomodoro control password
|
||||||
Settings PomodoroConfig `json:"settings"` // pomodoro config
|
Settings PomodoroConfig `json:"settings"` // Pomodoro config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Represents a single client
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Conn *websocket.Conn
|
Conn *websocket.Conn // Websocket connection of the client
|
||||||
Mutex sync.Mutex
|
Mutex sync.Mutex // Mutex used to lock
|
||||||
}
|
}
|
||||||
|
|
||||||
// It automatically locks and unlocks the mutex to ensure that only one goroutine can write at a time.
|
// 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 *Client) SendMessage(messageType int, data []byte) error {
|
||||||
c.Mutex.Lock()
|
c.Mutex.Lock()
|
||||||
defer c.Mutex.Unlock()
|
defer c.Mutex.Unlock()
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
// Represents the configuration of a pomodoro
|
||||||
type PomodoroConfig struct {
|
type PomodoroConfig struct {
|
||||||
Work int `json:"work"` // Length of work sessions in seconds
|
Work int `json:"work"` // Length of work sessions in seconds
|
||||||
ShortBreak int `json:"shortBreak"` // Length of short break in seconds
|
ShortBreak int `json:"shortBreak"` // Length of short break in seconds
|
||||||
LongBreak int `json:"longBreak"` // Length if ling break in seconds
|
LongBreak int `json:"longBreak"` // Length of long break in seconds
|
||||||
Sessions int `json:"sessions"` // Number of total sessions
|
Sessions int `json:"sessions"` // Number of total sessions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Represents the server configuration
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
ListenAddress string `json:"listenAddress"` // Server listen address
|
ListenAddress string `json:"listenAddress"` // Server listen address
|
||||||
ListenPort int `json:"listenPort"` // Server listen port
|
ListenPort int `json:"listenPort"` // Server listen port
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
// ServerMessage represents the data sent to the client via WebSocket.
|
// Represents the data sent to the client via WebSocket
|
||||||
type ServerMessage struct {
|
type ServerMessage struct {
|
||||||
Mode string `json:"mode"` // "Idle", "Work", "ShortBreak", "LongBreak" or "End"
|
Mode string `json:"mode"` // "Idle", "Work", "ShortBreak", "LongBreak" or "End"
|
||||||
Settings PomodoroConfig `json:"settings"` // The currrent pomodoro settings
|
Settings PomodoroConfig `json:"settings"` // The currrent pomodoro settings
|
||||||
Session int `json:"session"` // Current session number
|
Session int `json:"session"` // Current session number
|
||||||
TimeLeft int `json:"time_left"` // Remaining time in seconds
|
TimeLeft int `json:"time_left"` // Remaining time in seconds
|
||||||
Ongoing bool `json:"ongoing"` // Ongoing pomodoro
|
Ongoing bool `json:"ongoing"` // Pomodoro ongoing
|
||||||
Paused bool `json:"paused"` // Is timer paused
|
Paused bool `json:"paused"` // Is timer paused
|
||||||
ProtocolVersion string `json:"version"` // Version of the server
|
ProtocolVersion string `json:"version"` // Version of the protocol
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue