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 }