Added TryFire
This allows handlers to return errors which will be returned to the caller. Also replaced error returned from On with a panic.
This commit is contained in:
parent
a2269cd439
commit
91d1562e0e
26
bus.go
26
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,27 +18,43 @@ 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 {
|
||||
head *subscription
|
||||
tail *subscription
|
||||
|
|
16
errors.go
Normal file
16
errors.go
Normal file
|
@ -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
|
||||
}
|
20
handler.go
20
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
|
||||
|
|
Loading…
Reference in a new issue