From df1be55debeece9292087fa947905c9864f4c700 Mon Sep 17 00:00:00 2001 From: Roman Date: Sun, 8 Oct 2023 13:13:29 +0400 Subject: [PATCH] Add OnEvery timer event --- emit/event.go | 32 ++++++++++++++++++++++++++++++++ emit/event_test.go | 23 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/emit/event.go b/emit/event.go index 22c98ae..a5d4bee 100644 --- a/emit/event.go +++ b/emit/event.go @@ -6,6 +6,7 @@ package emit import ( "context" "math" + "sync/atomic" "time" "github.com/kelindar/event" @@ -46,6 +47,20 @@ func (e fault) Type() uint32 { return math.MaxUint32 } +// ----------------------------------------- Timer Event ----------------------------------------- + +var nextTimerID uint32 = 1 << 30 + +// timer represents a timer event +type timer struct { + ID uint32 +} + +// Type returns the type of the event +func (e timer) Type() uint32 { + return e.ID +} + // ----------------------------------------- Subscribe ----------------------------------------- // On subscribes to an event, the type of the event will be automatically @@ -74,6 +89,23 @@ func OnError(handler func(err error, about any)) context.CancelFunc { }) } +// OnEvery creates a timer that fires every 'interval' and calls the handler. +func OnEvery(handler func(now time.Time, elapsed time.Duration) error, interval time.Duration) context.CancelFunc { + id := atomic.AddUint32(&nextTimerID, 1) + if id >= (math.MaxUint32 - 1) { + panic("emit: too many timers created") + } + + // Subscribe to the timer event + cancel := OnType[timer](id, func(_ timer, now time.Time, elapsed time.Duration) error { + return handler(now, elapsed) + }) + + // Start the timer + Every(timer{ID: id}, interval) + return cancel +} + // ----------------------------------------- Publish ----------------------------------------- // Next writes an event during the next tick. diff --git a/emit/event_test.go b/emit/event_test.go index fc707a1..1b7f6ab 100644 --- a/emit/event_test.go +++ b/emit/event_test.go @@ -2,6 +2,7 @@ package emit import ( "fmt" + "math" "sync/atomic" "testing" "time" @@ -125,6 +126,28 @@ func TestOnTypeError(t *testing.T) { assert.Equal(t, "OnType()", (<-errors).Error()) } +func TestOnEvery(t *testing.T) { + events := make(chan MyEvent2) + defer OnEvery(func(now time.Time, elapsed time.Duration) error { + events <- MyEvent2{} + return nil + }, 20*time.Millisecond)() + + // Emit the event + <-events + <-events + <-events +} + +func TestTooManyTimers(t *testing.T) { + assert.Panics(t, func() { + nextTimerID = math.MaxUint32 - 1 + defer OnEvery(func(now time.Time, elapsed time.Duration) error { + return nil + }, 200*time.Millisecond)() + }) +} + // ------------------------------------- Test Events ------------------------------------- const (