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 }