diff --git a/event/event_bus.go b/event/event_bus.go index e608054..5b55b14 100644 --- a/event/event_bus.go +++ b/event/event_bus.go @@ -2,11 +2,13 @@ package event import ( "errors" + "fmt" "reflect" + "strings" ) -type HandlerInst interface { - Default(event any) (err error) +type Default struct { + Val any } type OnStart struct{} @@ -14,32 +16,48 @@ type OnLoopCycle struct{} var HandlerDone = errors.New("handler done") -func FindHandlers(inst HandlerInst) (handlers map[reflect.Type]reflect.Value) { - handlers = make(map[reflect.Type]reflect.Value) - t := reflect.TypeOf(inst) - v := reflect.ValueOf(inst) - for i := 0; i < t.NumMethod(); i++ { - method := t.Method(i) - if method.Type.NumIn() != 2 || method.Type.NumOut() != 1 { - continue +func FindHandlers(insts []any) (handlers map[reflect.Type][]reflect.Value) { + handlers = make(map[reflect.Type][]reflect.Value) + for _, inst := range insts { + t := reflect.TypeOf(inst) + v := reflect.ValueOf(inst) + for i := 0; i < t.NumMethod(); i++ { + method := t.Method(i) + if strings.HasPrefix(method.Name, "On") { + if method.Type.NumIn() != 2 || method.Type.NumOut() != 1 || method.Type.Out(0) != reflect.TypeFor[error]() { + fmt.Println("Invalid event handler signature:", method.Name) + continue + } + } else { + continue + } + eventType := method.Type.In(1) + handlers[eventType] = append(handlers[eventType], v.Method(i)) } - if method.Type.Out(0) != reflect.TypeFor[error]() { - continue - } - eventType := method.Type.In(1) - handlers[eventType] = v.Method(i) } return } -func Fire(inst HandlerInst, event any, handlers map[reflect.Type]reflect.Value) (err error) { - if handler, ok := handlers[reflect.TypeOf(event)]; ok { - errV := handler.Call([]reflect.Value{reflect.ValueOf(event)})[0] - if !errV.IsNil() { - err = errV.Interface().(error) +func FireFound(event any, handlersMap map[reflect.Type][]reflect.Value) (found bool, err error) { + var handlers []reflect.Value + if handlers, found = handlersMap[reflect.TypeOf(event)]; found { + for _, handler := range handlers { + errV := handler.Call([]reflect.Value{reflect.ValueOf(event)})[0] + if !errV.IsNil() { + err = errV.Interface().(error) + } } - } else { - err = inst.Default(event) + } + return +} + +func Fire(event any, handlersMap map[reflect.Type][]reflect.Value) (err error) { + found, err := FireFound(event, handlersMap) + if err != nil { + return + } + if !found { + _, err = FireFound(Default{event}, handlersMap) } return } diff --git a/proto/connection.go b/proto/connection.go index 1f3b38d..9c635b4 100644 --- a/proto/connection.go +++ b/proto/connection.go @@ -129,21 +129,25 @@ func (c *Conn) Receive() (packet any, err error) { return } -func (c *Conn) Start(inst event.HandlerInst) (err error) { +func (c *Conn) StartOne(inst any) (err error) { + return c.Start([]any{inst}) +} + +func (c *Conn) Start(insts []any) (err error) { _ = *c // exit early on nil connection - handlers := event.FindHandlers(inst) - err = event.Fire(inst, event.OnStart{}, handlers) + handlers := event.FindHandlers(insts) + err = event.Fire(event.OnStart{}, handlers) for err == nil { var packet any packet, err = c.Receive() if err != nil { return } - err = event.Fire(inst, packet, handlers) + err = event.Fire(packet, handlers) if err != nil { break } - err = event.Fire(inst, event.OnLoopCycle{}, handlers) + err = event.Fire(event.OnLoopCycle{}, handlers) } if errors.Is(err, event.HandlerDone) { err = nil diff --git a/proto_generated/v1_21_8/helpers.go b/proto_generated/v1_21_8/helpers.go index 4830d78..13bc4a1 100644 --- a/proto_generated/v1_21_8/helpers.go +++ b/proto_generated/v1_21_8/helpers.go @@ -1,8 +1,9 @@ package v1_21_8 import ( - "github.com/admin-else/strom/proto_base" "io" + + "github.com/admin-else/strom/proto_base" ) func HandshakingToServerPacketIdentifierToType(s string) (t any) {