Skip to content

Instantly share code, notes, and snippets.

@maciekmm
Last active January 1, 2016 16:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save maciekmm/4c291b6c8c0ac789efba to your computer and use it in GitHub Desktop.
Save maciekmm/4c291b6c8c0ac789efba to your computer and use it in GitHub Desktop.
Event dispatcher
package events
import (
"fmt"
"reflect"
"sync"
)
type Event interface {
Clone() Event
}
type Dispatcher struct {
handlers map[reflect.Type][]reflect.Value
lock *sync.RWMutex
}
func NewDispatcher() *Dispatcher {
return &Dispatcher{
handlers: make(map[reflect.Type][]reflect.Value),
lock: &sync.RWMutex{},
}
}
// RegisterEvent registers custom events making it possible to register listeners for them.
// It has to be mentioned that in order to listen for the event it has to be registered firstly.
// It is REQUIRED to override Clone() method provided by anonymous struct BaseEvent,
// otherwise thesame copy will be sent to all listeners
func (d *Dispatcher) RegisterEvent(event Event) bool {
d.lock.Lock()
defer d.lock.Unlock()
typ := reflect.TypeOf(event).Elem()
fmt.Println(typ)
if _, ok := d.handlers[typ]; ok {
return false
}
var chanArr []reflect.Value
d.handlers[typ] = chanArr
return true
}
// RegisterListener registers chanel accepting desired event - a listener.
// It is important to note that what channel accepts determines what will be sent to it.
// If listened event is not registered false is returned
// It's advised to use a buffered channel for the listener, otherwise events might be lost in action.
// Panics if pipe is not a channel
func (d *Dispatcher) RegisterListener(pipe interface{}) bool {
d.lock.Lock()
defer d.lock.Unlock()
channelValue := reflect.ValueOf(pipe)
channelType := channelValue.Type()
if channelType.Kind() != reflect.Chan {
panic("Trying to register a non-channel listener")
}
channelIn := channelType.Elem()
if arr, ok := d.handlers[channelIn]; ok {
d.handlers[channelIn] = append(arr, channelValue)
return true
}
return false
}
// Dispatch provides thread safe method to send event to all listeners
// Returns true if succeded and false if event was not registered
func (d *Dispatcher) Dispatch(event Event) bool {
d.lock.RLock()
defer d.lock.RUnlock()
eventType := reflect.TypeOf(event).Elem()
if listeners, ok := d.handlers[eventType]; ok {
for _, listener := range listeners {
listener.TrySend(reflect.ValueOf(event.Clone()).Elem())
}
return true
}
return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment