events/bus.go

85 lines
1.4 KiB
Go

package events
type Bus struct {
topics map[string]*topic
}
func New() *Bus {
return &Bus{topics: make(map[string]*topic)}
}
func (d *Bus) On(event string, receiver interface{}) {
// TODO: make thread safe
t, hasTopic := d.topics[event]
if !hasTopic {
t = &topic{}
d.topics[event] = t
}
sub, err := newSubscriptionFromFunc(receiver)
if err != nil {
panic(err)
}
t.addSubscriber(sub)
}
func (d *Bus) Fire(event string, args ...interface{}) {
_ = d.TryFire(event, args...)
}
func (d *Bus) TryFire(event string, args ...interface{}) error {
// TODO: make thead safe
topic, hasTopic := d.topics[event]
if !hasTopic {
return nil
}
preparedArgs := prepareArgs(args)
var errs []error
for sub := topic.head; sub != nil; sub = sub.next {
err := sub.handler.invoke(preparedArgs)
if err != nil {
errs = append(errs, err)
}
}
switch len(errs) {
case 0:
return nil
case 1:
return errs[0]
}
return HandlerError{topic: event, errs: errs}
}
type topic struct {
head *subscription
tail *subscription
}
func (t *topic) addSubscriber(sub *subscription) {
if t.head == nil {
t.head = sub
}
if t.tail != nil {
t.tail.next = sub
}
t.tail = sub
}
type subscription struct {
handler receiptHandler
next *subscription
}
func newSubscriptionFromFunc(fn interface{}) (*subscription, error) {
handler, err := newReceiptHandler(fn)
if err != nil {
return nil, err
}
return &subscription{handler: handler, next: nil}, nil
}