You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
1.7 KiB
Go

package events
import (
"log"
"sync"
"golang.org/x/exp/slices"
)
type ListenerFunc func(interface{})
type Listener struct {
Event string
Handle ListenerFunc
}
type EventBus struct {
lock sync.RWMutex
listeners map[string][]*Listener
}
func NewEventBus() *EventBus {
return &EventBus{
listeners: map[string][]*Listener{},
}
}
// Subscribe a listener for the given event type
func (eb *EventBus) Subscribe(event string, f ListenerFunc) *Listener {
eb.lock.Lock()
defer eb.lock.Unlock()
log.Printf("[EventBus] Subscribed listener for %q", event)
l := &Listener{event, f}
if prev, found := eb.listeners[event]; !found {
eb.listeners[event] = []*Listener{l}
} else {
eb.listeners[event] = append(prev, l)
}
return l
}
// Unsubscribe removes a listener for the given event type
func (eb *EventBus) Unsubscribe(l *Listener) {
eb.lock.Lock()
defer eb.lock.Unlock()
listeners := eb.listeners[l.Event]
i := slices.Index(listeners, l)
if i >= 0 {
// TODO: Magari usare la tecnica di spostare l'ultimo alla posizione dell'elemento rimosso e accorciare lo slice, tanto alla fine l'ordine dei listener non conta veramente
eb.listeners[l.Event] = append(listeners[:i], listeners[i+1:]...)
}
}
// Dispatch
func (eb *EventBus) Dispatch(event string, data interface{}) {
eb.lock.RLock()
defer eb.lock.RUnlock()
log.Printf("[EventBus] Fired event %q with value %v", event, data)
if listeners, found := eb.listeners[event]; found {
// make a copy of "listeners" to pass to the goroutine and not block the dispatcher thread
tmpListeners := append([]*Listener{}, listeners...)
go func() {
for _, listener := range tmpListeners {
listener.Handle(data)
}
}()
}
}