From 010d6b270cc164109b865e82b91ee305ebdc1c8f Mon Sep 17 00:00:00 2001 From: Jorge Ferrero Linacero Date: Wed, 27 Dec 2023 22:52:55 +0100 Subject: [PATCH] chore: apply Opts pattern to create a sync emitter --- event.go | 30 +++++++++++++++++++++++++++--- event_test.go | 16 ++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/event.go b/event.go index 87c50b5..26a377f 100644 --- a/event.go +++ b/event.go @@ -9,16 +9,36 @@ type Event string // Listerner defines the callback function signature. type Listerner[T any] func(context.Context, T) +// EmitterOption configures the emitter. +type EmitterOption[T any] func(*Emitter[T]) + +// SyncEmitter configures the emitter to be synchronous. +// It means that listeners are executed sequentially. +// Default: false. +func SyncEmitter[T any](e *Emitter[T]) { + e.sync = true +} + // Emitter emits an event with associated data. type Emitter[T any] struct { listeners map[Event][]Listerner[T] + sync bool } // NewEmitter creates a new emitter. -func NewEmitter[T any]() *Emitter[T] { - return &Emitter[T]{ +// It accepts a list of options to configure the emitter. +// By default, the emitter is asynchronous. It means that each listener is +// executed in a separate goroutine. +func NewEmitter[T any](opts ...EmitterOption[T]) *Emitter[T] { + e := &Emitter[T]{ listeners: make(map[Event][]Listerner[T]), } + + for _, opt := range opts { + opt(e) + } + + return e } // On registers a callback for an event. @@ -32,6 +52,10 @@ func (e *Emitter[T]) On(ev Event, l ...Listerner[T]) *Emitter[T] { func (e *Emitter[T]) Emit(ctx context.Context, ev Event, data T) { l := e.listeners[ev] for _, f := range l { - go f(ctx, data) + if e.sync { + f(ctx, data) + } else { + go f(ctx, data) + } } } diff --git a/event_test.go b/event_test.go index 04d6290..666606d 100644 --- a/event_test.go +++ b/event_test.go @@ -70,6 +70,22 @@ func TestEmitter_Emit(t *testing.T) { }, eventEmmited: true, }, + { + name: "single event listerner executed synchronously", + e: NewEmitter[*eventPayload](SyncEmitter), + args: args{ + ctx: ctx, + bootstrapEvent: "test", + triggerEvent: "test", + data: &eventPayload{}, + }, + listeners: []Listerner[*eventPayload]{ + func(ctx context.Context, data *eventPayload) { + data.called = true + }, + }, + eventEmmited: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {