101 lines
1.9 KiB
Go
101 lines
1.9 KiB
Go
package event
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
type IntervalTask struct {
|
|
F func() error
|
|
LastTrigger time.Time
|
|
Interval time.Duration
|
|
}
|
|
|
|
type OnceTask struct {
|
|
F func() error
|
|
Trigger time.Time
|
|
}
|
|
|
|
type Timer struct {
|
|
Once []OnceTask
|
|
Interval []IntervalTask
|
|
}
|
|
|
|
func (t *Timer) Trigger(ch chan any) {
|
|
triggerAt := time.Time{}
|
|
found := false
|
|
iOnce, iInterval := -1, -1
|
|
|
|
for i, oTask := range t.Once {
|
|
if oTask.Trigger.Before(triggerAt) || triggerAt.IsZero() {
|
|
found = true
|
|
triggerAt = oTask.Trigger
|
|
iOnce = i
|
|
}
|
|
}
|
|
|
|
for i, iTask := range t.Interval {
|
|
if iTask.LastTrigger.Add(iTask.Interval).Before(triggerAt) || triggerAt.IsZero() {
|
|
found = true
|
|
triggerAt = iTask.LastTrigger.Add(iTask.Interval)
|
|
iOnce = -1
|
|
iInterval = i
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
return
|
|
}
|
|
now := time.Now()
|
|
sleepFor := triggerAt.Sub(now)
|
|
//slog.Debug("sleep next", "dur", sleepFor)
|
|
time.Sleep(sleepFor)
|
|
if iOnce >= 0 {
|
|
ch <- CallFunc{F: reflect.ValueOf(t.Once[iOnce].F), Args: []reflect.Value{}}
|
|
t.Once = slices.Delete(t.Once, iOnce, iOnce+1)
|
|
return
|
|
}
|
|
if iInterval >= 0 {
|
|
t.Interval[iInterval].LastTrigger = triggerAt
|
|
ch <- CallFunc{F: reflect.ValueOf(t.Interval[iInterval].F), Args: []reflect.Value{}}
|
|
return
|
|
}
|
|
panic("unreachable")
|
|
}
|
|
func (t *Timer) Every(interval time.Duration, f func() error) {
|
|
t.Interval = append(t.Interval, IntervalTask{
|
|
F: f,
|
|
Interval: interval,
|
|
LastTrigger: time.Now(),
|
|
})
|
|
}
|
|
|
|
func (t *Timer) In(interval time.Duration, f func() error) {
|
|
t.Once = append(t.Once, OnceTask{
|
|
F: f,
|
|
Trigger: time.Now().Add(interval),
|
|
})
|
|
}
|
|
|
|
func (t *Timer) MakeEventSource(ctx context.Context) (chSending <-chan any) {
|
|
ch := make(chan any)
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
t.Trigger(ch)
|
|
}
|
|
}
|
|
}()
|
|
chSending = ch
|
|
return
|
|
}
|
|
|
|
func (t *Timer) Start(c *Loop) {
|
|
c.RegisterEventSource(t.MakeEventSource(c.Ctx))
|
|
}
|