diff --git a/bus.go b/bus.go index a7c0806..7b5eb27 100644 --- a/bus.go +++ b/bus.go @@ -8,7 +8,7 @@ func New() *Bus { return &Bus{topics: make(map[string]*topic)} } -func (d *Bus) On(event string, receiver interface{}) error { +func (d *Bus) On(event string, receiver interface{}) { // TODO: make thread safe t, hasTopic := d.topics[event] if !hasTopic { @@ -18,25 +18,41 @@ func (d *Bus) On(event string, receiver interface{}) error { sub, err := newSubscriptionFromFunc(receiver) if err != nil { - return err + panic(err) } t.addSubscriber(sub) - return nil } 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 + return nil } preparedArgs := prepareArgs(args) + var errs []error + for sub := topic.head; sub != nil; sub = sub.next { - sub.handler.invoke(preparedArgs) + 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 { @@ -65,4 +81,4 @@ func newSubscriptionFromFunc(fn interface{}) (*subscription, error) { return nil, err } return &subscription{handler: handler, next: nil}, nil -} \ No newline at end of file +} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..4f8cc5c --- /dev/null +++ b/errors.go @@ -0,0 +1,16 @@ +package events + +import "fmt" + +type HandlerError struct { + topic string + errs []error +} + +func (h HandlerError) Error() string { + return fmt.Sprintf("caught %d errors from topic '%v': %v", len(h.errs), h.topic, h.errs) +} + +func (h HandlerError) Unwrap() []error { + return h.errs +} diff --git a/handler.go b/handler.go index 99dfd81..ec30350 100644 --- a/handler.go +++ b/handler.go @@ -1,3 +1,4 @@ +//go:build !tinygo // +build !tinygo package events @@ -21,7 +22,7 @@ func newReceiptHandler(receiver interface{}) (receiptHandler, error) { return receiptHandler{receiverFunc: val, funcType: val.Type()}, nil } -func (rh *receiptHandler) invoke(values preparedArgs) { +func (rh *receiptHandler) invoke(values preparedArgs) error { args := make([]reflect.Value, rh.funcType.NumIn()) for i := range args { args[i] = reflect.Zero(rh.funcType.In(i)) @@ -32,7 +33,22 @@ func (rh *receiptHandler) invoke(values preparedArgs) { } } - rh.receiverFunc.Call(args) + rets := rh.receiverFunc.Call(args) + if len(rets) == 0 { + return nil + } + + lastRet := rets[len(rets)-1] + switch { + case lastRet.IsNil(): + return nil + case lastRet.CanInterface(): + err, ok := lastRet.Interface().(error) + if ok { + return err + } + } + return nil } type preparedArgs []reflect.Value @@ -43,4 +59,4 @@ func prepareArgs(argIfacess []interface{}) preparedArgs { values[i] = reflect.ValueOf(a) } return values -} \ No newline at end of file +}