Compare commits

...

4 commits

Author SHA1 Message Date
636f8c2feb feat: bump version to v0.0.3 2024-10-25 23:20:20 +02:00
3eae584d6d recator: use timer signals instead of shared.Message.TimeLeft
- remove shared.Message.TimeLeft
- modify Timer struct
  - add TimeLeft signal
  - add End and Abort signals
- add syncronised ticker
- update RunPomodoro to use goroutines for timer starts
  - add waitForTimer function
2024-10-25 23:19:58 +02:00
aa5c24f06d refactor: move timer function to method
- introduce Timer struct to manage timer state
- update RunPomodoro to use Timer methods for starting, stopping, and pausing
- remove unused pomodoro channels
2024-10-25 23:19:53 +02:00
62fbb1d356 feat: add a ticker to manage broadcast timing 2024-10-25 23:18:46 +02:00
4 changed files with 88 additions and 48 deletions

View file

@ -1,3 +1,3 @@
package metadata
const GoTomatoVersion = "v0.0.2" // The GoTomato Version
const GoTomatoVersion = "v0.0.3" // The GoTomato Version

View file

@ -6,11 +6,21 @@ import (
"time"
)
var pomodoroResetChannel = make(chan bool, 1)
var pomodoroPauseChannel = make(chan bool, 1)
var pomodoroResumeChannel = make(chan bool, 1)
var mu sync.Mutex // to synchronize access to shared state
var timer Timer
func waitForTimer(t Timer) bool {
for {
select {
case <-t.End:
return true
case <-t.Abort:
return false
case shared.Message.TimeLeft = <-t.TimeLeft:
// do nothing, just let the timer update the message
}
}
}
// RunPomodoro iterates the Pomodoro work/break sessions.
func RunPomodoro() {
@ -22,26 +32,32 @@ func RunPomodoro() {
pomodoroConfig := shared.Message.PomodoroSettings
for session := 1; session <= pomodoroConfig.Sessions; session++ {
timer = timer.Init()
shared.Message.Session = session
shared.Message.Mode = "Work"
if !startTimer(pomodoroConfig.Work) {
go timer.Start(pomodoroConfig.Work)
if !waitForTimer(timer) {
break
}
if session == pomodoroConfig.Sessions {
shared.Message.Mode = "LongBreak"
if !startTimer(pomodoroConfig.LongBreak) {
break
}
} else {
shared.Message.Mode = "ShortBreak"
if !startTimer(pomodoroConfig.ShortBreak) {
break
}
}
shared.Message.Mode = "End"
}
if session < pomodoroConfig.Sessions {
shared.Message.Mode = "ShortBreak"
go timer.Start(pomodoroConfig.ShortBreak)
if !waitForTimer(timer) {
break
}
} else { // last phase, prepare for finish
shared.Message.Mode = "LongBreak"
go timer.Start(pomodoroConfig.LongBreak)
if !waitForTimer(timer) {
break
}
shared.Message.Mode = "End"
time.Sleep(time.Second)
}
}
mu.Lock()
shared.Message.Ongoing = false
@ -53,12 +69,8 @@ func RunPomodoro() {
shared.Message.TimeLeft = shared.Message.PomodoroSettings.Work
}
// Stops and resets the running Pomodoro
func ResetPomodoro() {
shared.Message.Mode = "Idle"
shared.Message.Session = 0
shared.Message.TimeLeft = shared.Message.PomodoroSettings.Work
pomodoroResetChannel <- true
timer.Stop()
}
func PausePomodoro() {
@ -66,14 +78,14 @@ func PausePomodoro() {
shared.Message.Paused = true
mu.Unlock()
pomodoroPauseChannel <- true
timer.Pause()
}
func ResumePomodoro() {
mu.Lock()
shared.Message.Paused = false
mu.Unlock()
pomodoroResumeChannel <- true
timer.Resume()
}
func IsPomodoroOngoing() bool {

View file

@ -1,32 +1,59 @@
package pomodoro
import (
"git.smsvc.net/pomodoro/GoTomato/internal/shared"
"time"
)
// runs the countdown and updates shared.Message.TimeLeft every second.
func startTimer(remainingSeconds int) bool {
for remainingSeconds > 0 {
select {
case <-pomodoroResetChannel:
return false
case <-pomodoroPauseChannel:
// Nothing to set here, just waiting for the signal
case <-pomodoroResumeChannel:
// Nothing to set here, just waiting for the signal
default:
// Broadcast the current state to all clients
if !IsPomodoroPaused() {
shared.Message.TimeLeft = remainingSeconds
time.Sleep(time.Second)
remainingSeconds--
}
}
}
// Final shared.Message when time reaches zero
shared.Message.TimeLeft = remainingSeconds
return true
type Timer struct {
TimeLeft chan int // time left
End chan bool // signal on successful end
Abort chan bool // signal on premature end
stop chan bool
wait chan bool
resume chan bool
}
func (t Timer) Init() Timer {
return Timer{
TimeLeft: make(chan int),
End: make(chan bool, 1),
Abort: make(chan bool, 1),
stop: make(chan bool, 1),
wait: make(chan bool, 1),
resume: make(chan bool, 1),
}
}
func (t *Timer) Start(duration int) {
tick := time.NewTicker(time.Second)
for timeLeft := duration; timeLeft > 0; {
select {
case <-t.stop:
t.Abort <- true
return
case <-t.wait:
<-t.resume
continue
case <-tick.C:
timeLeft--
default:
t.TimeLeft <- timeLeft
}
}
t.TimeLeft <- 0
t.End <- true
}
func (t *Timer) Stop() {
t.resume <- true
t.stop <- true
}
func (t *Timer) Pause() {
t.wait <- true
}
func (t *Timer) Resume() {
t.resume <- true
}

View file

@ -10,6 +10,7 @@ import (
// sends continous messages to all connected WebSocket clients.
func SendPermanentBroadCastMessage() {
tick := time.NewTicker(time.Second)
for {
// Marshal the message into JSON format
jsonMessage, err := json.Marshal(shared.Message)
@ -25,6 +26,6 @@ func SendPermanentBroadCastMessage() {
// The client is responsible for closing itself on error
}
}
time.Sleep(time.Second)
<-tick.C
}
}