sati-go/events.go
2023-06-28 13:56:39 +03:00

81 lines
1.4 KiB
Go

package sati
import (
"fmt"
"sync"
"github.com/mitchellh/mapstructure"
)
type EventBus struct {
mu *sync.Mutex
idCounter uint32
handlers map[string]map[uint32]func(data any)
eventTypes map[string]any
}
type EventHandler struct {
id uint32
type_ string
bus *EventBus
}
func (e *EventHandler) Off() {
e.bus.mu.Lock()
defer e.bus.mu.Unlock()
delete(e.bus.handlers[e.type_], e.id)
}
func (e *EventBus) On(event string, handler func(data any)) (*EventHandler, error) {
e.mu.Lock()
defer e.mu.Unlock()
if _, ok := e.eventTypes[event]; !ok {
return nil, fmt.Errorf("bad event type")
}
e.idCounter++
e.handlers[event][e.idCounter] = handler
return &EventHandler{
id: e.idCounter,
type_: event,
bus: e,
}, nil
}
func (e *EventBus) dispatch(event string, data any) error {
e.mu.Lock()
defer e.mu.Unlock()
formattedData, ok := e.eventTypes[event]
if !ok {
return fmt.Errorf("bad event type")
}
if err := mapstructure.Decode(data, &formattedData); err != nil {
return err
}
for _, handler := range e.handlers[event] {
handler(formattedData)
}
return nil
}
// eventTypes values must be structs, not pointers
func newEventBus(eventTypes map[string]any) *EventBus {
e := &EventBus{
mu: &sync.Mutex{},
handlers: make(map[string]map[uint32]func(data any)),
eventTypes: eventTypes,
}
for event := range eventTypes {
e.handlers[event] = make(map[uint32]func(data any))
}
return e
}