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