pkg/{timex,wait}: Unify code

This commit is contained in:
Tom Wiesing 2022-10-16 19:33:25 +02:00
parent 59fff07b59
commit 8701fab93b
No known key found for this signature in database
10 changed files with 77 additions and 74 deletions

View file

@ -1,3 +1,4 @@
// Package timex provides Interval and Wait
package timex
import (
@ -5,21 +6,49 @@ import (
"time"
)
// SetInterval invokes f with the current time and then spawns a new goroutine that runs f every d, until context is closed.
func SetInterval(ctx context.Context, d time.Duration, f func(t time.Time)) {
f(time.Now())
// TickContext is like [time.Tick], but closes the returned channel once the context closes.
// As such it can be recovered by the garbage collector; see [time.TickContext].
//
// Unlike [time.Tick], immediatly send the current time on the given channel.
func TickContext(c context.Context, d time.Duration) <-chan time.Time {
if d < 0 {
return nil
}
timer := make(chan time.Time, 1)
timer <- time.Now()
go func() {
t := time.NewTicker(d)
defer t.Stop()
defer close(timer)
for {
select {
case tick := <-t.C:
f(tick)
case <-ctx.Done():
timer <- tick
case <-c.Done():
return
}
}
}()
return timer
}
// TickUntilFunc invokes f every d until either context is closed, or f returns true.
// f is invoked once immediatly when the timer starts.
//
// TickUntilFunc blocks until f is no longer invoked.
//
// Returns the error of the context (if any).
func TickUntilFunc(f func(t time.Time) bool, c context.Context, d time.Duration) error {
context, cancel := context.WithCancel(c)
defer cancel()
for t := range TickContext(context, d) {
if f(t) {
break
}
}
return c.Err()
}

View file

@ -1,31 +0,0 @@
package wait
import (
"context"
"time"
)
// Wait repeatedly invokes f, until it returns true or the context is closed.
// The invocation interval is determined by interval.
func Wait(f func() bool, interval time.Duration, context context.Context) error {
// create a new timer
timer := time.NewTimer(interval)
if !timer.Stop() {
<-timer.C
}
defer timer.Stop()
for {
if f() {
return nil
}
// reset the timer, and wait for it again!
timer.Reset(interval)
select {
case <-timer.C:
case <-context.Done():
return context.Err()
}
}
}