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
77 lines
1.7 KiB
Go
2 years ago
|
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)
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
}
|