mumble-discord-bridge/pkg/sleepct/sleepct.go

74 lines
1.6 KiB
Go

package sleepct
import (
"fmt"
"time"
)
// SleepCT - Sleep constant time step crates a sleep based ticker.
// designed maintain a consistent sleep/tick interval.
// The sleeper can be paused waiting to be singaled from another go routine.
// This allows for the pausing of loops that do not have work to complete
type SleepCT struct {
d time.Duration // desired duration between targets
t time.Time // last time target
resume chan bool
}
func (s *SleepCT) Start(d time.Duration) {
s.resume = make(chan bool, 1)
if s.t.IsZero() {
s.d = d
s.t = time.Now()
} else {
panic("SleepCT already started")
}
}
// Sleep to the next target duration.
// If pause it set to true will sleep the duration and wait to be notified.
// The notification channel will be cleared when the thread wakes.
// SleepNextTarget should not be call more than once concurrently.
func (s *SleepCT) SleepNextTarget(pause bool) {
var last time.Time
if s.t.IsZero() {
fmt.Println("SleepCT reset")
last = time.Now().Add(-s.d)
} else {
last = s.t
}
// Sleep to Next Target
s.t = last.Add(s.d)
d := time.Until(s.t)
time.Sleep(d)
// delta := time.Since(s.t)
// fmt.Println("delta", delta, d, time.Since(s.t))
if pause {
// wait until resume
if len(s.resume) == 0 {
<-s.resume
// if we did pause set the last sleep target to now
last = time.Now()
}
}
// Drain the resume channel
select {
case <-s.resume:
default:
}
}
// Notify attempts to resume a paused sleeper.
// It is safe to call notify from other processes and as often as desired.
func (s *SleepCT) Notify() {
select {
case s.resume <- true:
}
}