refactor event handling to support multiple handlers and improve default behavior

This commit is contained in:
adman
2025-12-26 04:18:51 +01:00
parent 6369ed08e2
commit 08f265c259
3 changed files with 51 additions and 28 deletions
+29 -11
View File
@@ -2,11 +2,13 @@ package event
import ( import (
"errors" "errors"
"fmt"
"reflect" "reflect"
"strings"
) )
type HandlerInst interface { type Default struct {
Default(event any) (err error) Val any
} }
type OnStart struct{} type OnStart struct{}
@@ -14,32 +16,48 @@ type OnLoopCycle struct{}
var HandlerDone = errors.New("handler done") var HandlerDone = errors.New("handler done")
func FindHandlers(inst HandlerInst) (handlers map[reflect.Type]reflect.Value) { func FindHandlers(insts []any) (handlers map[reflect.Type][]reflect.Value) {
handlers = make(map[reflect.Type]reflect.Value) handlers = make(map[reflect.Type][]reflect.Value)
for _, inst := range insts {
t := reflect.TypeOf(inst) t := reflect.TypeOf(inst)
v := reflect.ValueOf(inst) v := reflect.ValueOf(inst)
for i := 0; i < t.NumMethod(); i++ { for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i) method := t.Method(i)
if method.Type.NumIn() != 2 || method.Type.NumOut() != 1 { 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 continue
} }
if method.Type.Out(0) != reflect.TypeFor[error]() { } else {
continue continue
} }
eventType := method.Type.In(1) eventType := method.Type.In(1)
handlers[eventType] = v.Method(i) handlers[eventType] = append(handlers[eventType], v.Method(i))
}
} }
return return
} }
func Fire(inst HandlerInst, event any, handlers map[reflect.Type]reflect.Value) (err error) { func FireFound(event any, handlersMap map[reflect.Type][]reflect.Value) (found bool, err error) {
if handler, ok := handlers[reflect.TypeOf(event)]; ok { 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] errV := handler.Call([]reflect.Value{reflect.ValueOf(event)})[0]
if !errV.IsNil() { if !errV.IsNil() {
err = errV.Interface().(error) 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 return
} }
+9 -5
View File
@@ -129,21 +129,25 @@ func (c *Conn) Receive() (packet any, err error) {
return 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 _ = *c // exit early on nil connection
handlers := event.FindHandlers(inst) handlers := event.FindHandlers(insts)
err = event.Fire(inst, event.OnStart{}, handlers) err = event.Fire(event.OnStart{}, handlers)
for err == nil { for err == nil {
var packet any var packet any
packet, err = c.Receive() packet, err = c.Receive()
if err != nil { if err != nil {
return return
} }
err = event.Fire(inst, packet, handlers) err = event.Fire(packet, handlers)
if err != nil { if err != nil {
break break
} }
err = event.Fire(inst, event.OnLoopCycle{}, handlers) err = event.Fire(event.OnLoopCycle{}, handlers)
} }
if errors.Is(err, event.HandlerDone) { if errors.Is(err, event.HandlerDone) {
err = nil err = nil
+2 -1
View File
@@ -1,8 +1,9 @@
package v1_21_8 package v1_21_8
import ( import (
"github.com/admin-else/strom/proto_base"
"io" "io"
"github.com/admin-else/strom/proto_base"
) )
func HandshakingToServerPacketIdentifierToType(s string) (t any) { func HandshakingToServerPacketIdentifierToType(s string) (t any) {