server_events/emitter.go
2025-06-23 21:03:52 +02:00

100 lines
2.2 KiB
Go

package serverevents
import (
"slices"
"sync"
"github.com/google/uuid"
)
var emitter *EventEmitter
type Subscription struct {
id string
eventType string
todo func(Event)
emitter *EventEmitter
}
func (sub Subscription) Unsubscribe() {
if len(sub.eventType) < 1 {
emitter.onAllSubscribers = slices.DeleteFunc(emitter.onAllSubscribers, func(existSub Subscription) bool {
return existSub.id == sub.id
})
return
}
eventSubscribers := emitter.subscribers[sub.eventType]
if eventSubscribers == nil || len(eventSubscribers) < 1 {
return
}
emitter.subscribers[sub.eventType] = slices.DeleteFunc(emitter.subscribers[sub.eventType], func(existSub Subscription) bool {
return existSub.id == sub.id
})
}
type Event struct {
Type string `json:"type"`
Data any `json:"data"`
IsBackendOnly bool `json:"-"`
}
type EventEmitter struct {
subscribers map[string][]Subscription
onAllSubscribers []Subscription
mu sync.RWMutex
}
func GetEventEmitter() *EventEmitter {
if emitter == nil {
emitter = &EventEmitter{
subscribers: make(map[string][]Subscription),
onAllSubscribers: make([]Subscription, 0),
}
}
return emitter
}
func (em *EventEmitter) On(eventType string, do func(Event)) Subscription {
em.mu.Lock()
defer em.mu.Unlock()
if em.subscribers[eventType] == nil {
em.subscribers[eventType] = make([]Subscription, 0)
}
sub := Subscription{
id: uuid.NewString(),
eventType: eventType,
todo: do,
emitter: em,
}
em.subscribers[eventType] = append(em.subscribers[eventType], sub)
return sub
}
func (em *EventEmitter) OnAll(do func(Event)) Subscription {
em.mu.Lock()
defer em.mu.Unlock()
sub := Subscription{
id: uuid.NewString(),
todo: do,
emitter: em,
}
em.onAllSubscribers = append(em.onAllSubscribers, sub)
return sub
}
func (em *EventEmitter) Emit(event Event) {
executeSubscribers(em.onAllSubscribers, event)
eventSubscribers := em.subscribers[event.Type]
if eventSubscribers != nil {
executeSubscribers(eventSubscribers, event)
}
}
func executeSubscribers(toDos []Subscription, event Event) {
for _, sub := range toDos {
sub.todo(event)
}
}