refactor event systems

This commit is contained in:
adman
2026-03-08 11:52:25 +01:00
parent 73d4e07b06
commit 2eee7bde24
12 changed files with 100 additions and 33 deletions
+1
View File
@@ -1,3 +1,4 @@
.devres/ .devres/
.idea/ .idea/
.failed_packets/ .failed_packets/
tools/.*/
+5 -1
View File
@@ -46,7 +46,11 @@ func (s *LoginClient) OnCycle(_ event.Tick) (err error) {
return return
} }
func (s *LoginClient) OnStart(_ event.OnStart) (err error) { func (s *LoginClient) OnClose(_ event.Close) (err error) {
return
}
func (s *LoginClient) OnStart(_ event.Start) (err error) {
if s.ServerHost == "" && s.ServerPort == 0 { if s.ServerHost == "" && s.ServerPort == 0 {
var portStr string var portStr string
s.ServerHost, portStr, err = net.SplitHostPort(s.RemoteAddr().String()) s.ServerHost, portStr, err = net.SplitHostPort(s.RemoteAddr().String())
+1 -1
View File
@@ -23,7 +23,7 @@ func (s *StatusClient) Default(event any) (err error) {
return return
} }
func (s *StatusClient) OnStart(_ event.OnStart) (err error) { func (s *StatusClient) OnStart(_ event.Start) (err error) {
parts := strings.Split(s.RemoteAddr().String(), ":") parts := strings.Split(s.RemoteAddr().String(), ":")
versionData, err := data.LookUpVersionByName(s.Version) versionData, err := data.LookUpVersionByName(s.Version)
if err != nil { if err != nil {
+21 -12
View File
@@ -10,9 +10,8 @@ import (
) )
type Loop struct { type Loop struct {
HandlerFunctions map[reflect.Type][]reflect.Value handlerFunctions map[reflect.Type][]reflect.Value
Handlers []any Handlers []any
HandlerIndex int
} }
type Unhandled struct { type Unhandled struct {
@@ -24,7 +23,7 @@ type Anything struct {
} }
type ( type (
OnStart struct{} Start struct{}
Tick struct{} Tick struct{}
) )
@@ -33,6 +32,11 @@ type HandlerDoneErr struct {
Return error Return error
} }
// Close is fired when the loop shuts down.
type Close struct {
Reason error
}
func (e HandlerDoneErr) Error() string { func (e HandlerDoneErr) Error() string {
return "HandlerDoneErr" return "HandlerDoneErr"
} }
@@ -43,10 +47,11 @@ func (e HandlerDoneErr) Unwrap() error {
// ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers. // ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers.
var ErrDontForward = errors.New("dont forward") var ErrDontForward = errors.New("dont forward")
var WhileClosingErr = errors.New("error while closing")
// SetHandlerFunctions initializes and populates the HandlerFunctions map by reflecting over methods of registered handlers. // UpdateHandlerFunctions initializes and populates the handlerFunctions map by reflecting over methods of registered handlers.
func (l *Loop) SetHandlerFunctions() { func (l *Loop) UpdateHandlerFunctions() {
l.HandlerFunctions = make(map[reflect.Type][]reflect.Value) l.handlerFunctions = make(map[reflect.Type][]reflect.Value)
for _, inst := range l.Handlers { for _, inst := range l.Handlers {
t := reflect.TypeOf(inst) t := reflect.TypeOf(inst)
v := reflect.ValueOf(inst) v := reflect.ValueOf(inst)
@@ -54,14 +59,14 @@ func (l *Loop) SetHandlerFunctions() {
method := t.Method(i) method := t.Method(i)
if strings.HasPrefix(method.Name, "On") { if strings.HasPrefix(method.Name, "On") {
if method.Type.NumIn() != 2 || method.Type.NumOut() != 1 || method.Type.Out(0) != reflect.TypeFor[error]() { if method.Type.NumIn() != 2 || method.Type.NumOut() != 1 || method.Type.Out(0) != reflect.TypeFor[error]() {
fmt.Println("Invalid event handler signature:", t.String(), ".", method.Name) slog.Warn("Invalid event handler signature", "at", t.String()+"."+method.Name)
continue continue
} }
} else { } else {
continue continue
} }
eventType := method.Type.In(1) eventType := method.Type.In(1)
l.HandlerFunctions[eventType] = append(l.HandlerFunctions[eventType], v.Method(i)) l.handlerFunctions[eventType] = append(l.handlerFunctions[eventType], v.Method(i))
slog.Debug("Registered Handler", "at", t.String()+"."+method.Name, "for", eventType.String()) slog.Debug("Registered Handler", "at", t.String()+"."+method.Name, "for", eventType.String())
} }
} }
@@ -70,7 +75,7 @@ func (l *Loop) SetHandlerFunctions() {
// FireFound triggers all handlers registered for the specified event type and returns if handlers were found or an error occurred. // FireFound triggers all handlers registered for the specified event type and returns if handlers were found or an error occurred.
func (l *Loop) FireFound(event any) (found bool, err error) { func (l *Loop) FireFound(event any) (found bool, err error) {
var handlers []reflect.Value var handlers []reflect.Value
if handlers, found = l.HandlerFunctions[reflect.TypeOf(event)]; found { if handlers, found = l.handlerFunctions[reflect.TypeOf(event)]; found {
for _, handler := range handlers { 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() {
@@ -103,9 +108,9 @@ func (l *Loop) Fire(event any) (err error) {
} }
func (l *Loop) Start() (err error) { func (l *Loop) Start() (err error) {
_ = *l // exit early on nil connection _ = *l // exit early on nil loop
l.SetHandlerFunctions() l.UpdateHandlerFunctions()
err = l.Fire(OnStart{}) err = l.Fire(Start{})
for err == nil { for err == nil {
err = l.Fire(Tick{}) err = l.Fire(Tick{})
if err != nil { if err != nil {
@@ -115,5 +120,9 @@ func (l *Loop) Start() (err error) {
if errors.Is(err, HandlerDoneErr{}) { if errors.Is(err, HandlerDoneErr{}) {
err = errors.Unwrap(err) err = errors.Unwrap(err)
} }
closeErr := l.Fire(Close{err})
if closeErr != nil {
err = errors.Join(err, errors.Join(WhileClosingErr, closeErr))
}
return return
} }
+51
View File
@@ -0,0 +1,51 @@
package event
import (
"bufio"
"context"
"os"
)
type Stdin struct {
Val string
}
type StdinHandler struct {
*Loop
stdInChan chan Stdin
ctx context.Context
cancel context.CancelFunc
}
func (s *StdinHandler) OnTick(_ Tick) (err error) {
select {
case stdin := <-s.stdInChan:
err = s.Fire(Stdin{stdin.Val})
default:
}
return
}
func (s *StdinHandler) ScanJob() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
select {
case <-s.ctx.Done():
return
default:
s.stdInChan <- Stdin{scanner.Text()}
}
}
}
func (s *StdinHandler) OnStart(_ Start) (err error) {
s.stdInChan = make(chan Stdin)
s.ctx, s.cancel = context.WithCancel(context.Background())
go s.ScanJob()
return
}
func (s *StdinHandler) OnClose(_ Close) (err error) {
s.cancel()
return
}
+1 -1
View File
@@ -1,4 +1,4 @@
package client package event
import ( import (
"slices" "slices"
+5 -5
View File
@@ -17,7 +17,7 @@ var BadPacketTypeError = errors.New("bad packet type")
var BadPacketIdError = errors.New("bad packet id") var BadPacketIdError = errors.New("bad packet id")
var PacketNotFullyDecodedError = errors.New("packet not fully decoded") var PacketNotFullyDecodedError = errors.New("packet not fully decoded")
// UnCodablePacket represents a packet that could not be decoded due to proto_generated not supporting all packets. // UnCodablePacket represents a packet that could not be decoded.
type UnCodablePacket struct { type UnCodablePacket struct {
Err error Err error
Data []byte Data []byte
@@ -109,13 +109,13 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) {
if err != nil { if err != nil {
packet = &UnCodablePacket{Err: err, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: err, Data: packetBytes, Direction: c.Actor.ReceiveDirection()}
err = nil err = nil
return
} }
if b.Len() != 0 { if b.Len() != 0 {
err = nil err = nil
packet = &UnCodablePacket{Err: PacketNotFullyDecodedError, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: PacketNotFullyDecodedError, Data: packetBytes, Direction: c.Actor.ReceiveDirection()}
return return
} }
//fmt.Println("recv:", packet)
return return
} }
@@ -130,11 +130,11 @@ func (c *Conn) OnTick(_ event.Tick) (err error) {
} }
func (c *Conn) Start(handlers ...any) (err error) { func (c *Conn) Start(handlers ...any) (err error) {
if c.Loop == nil {
c.Loop = &event.Loop{} c.Loop = &event.Loop{}
c.Handlers = append(c.Handlers, c) }
c.Handlers = []any{c}
c.Handlers = append(c.Handlers, handlers...) c.Handlers = append(c.Handlers, handlers...)
err = c.Loop.Start() err = c.Loop.Start()
c.Handlers = c.Handlers[:len(c.Handlers)-len(handlers)]
c.Loop.SetHandlerFunctions()
return return
} }
+1 -2
View File
@@ -30,7 +30,7 @@ func (c *RawConn) SendRaw(rawPacketBytes []byte) (err error) {
if err != nil { if err != nil {
return return
} }
zW := zlib.NewWriter(packetBuffer) zW := zlib.NewWriter(packetBuffer) // ignore we don't care about the result if it errors
_, err = zW.Write(rawPacketBytes) _, err = zW.Write(rawPacketBytes)
if err != nil { if err != nil {
return return
@@ -106,7 +106,6 @@ func (c *RawConn) ReceiveRaw() (packetBytes []byte, err error) {
} else { } else {
packetBytes = rawPacketBytes packetBytes = rawPacketBytes
} }
//fmt.Println("recv:", packetBytes)
return return
} }
+1 -1
View File
@@ -21,7 +21,7 @@ func (c *ConfigServer) Default(event event.Anything) (err error) {
return return
} }
func (c *ConfigServer) OnStart(_ event.OnStart) (err error) { func (c *ConfigServer) OnStart(_ event.Start) (err error) {
n, err := data.LoadRegistry(c.Version) n, err := data.LoadRegistry(c.Version)
if err != nil { if err != nil {
return return
+5 -1
View File
@@ -116,7 +116,7 @@ func (l *LoginServer) OnDefault(event event.Unhandled) (err error) {
return return
} }
func (l *LoginServer) OnStart(_ event.OnStart) (err error) { func (l *LoginServer) OnStart(_ event.Start) (err error) {
return return
} }
@@ -124,6 +124,10 @@ func (l *LoginServer) OnCycle(_ event.Tick) (err error) {
return return
} }
func (s *LoginServer) OnClose(_ event.Close) (err error) {
return
}
type LoginServerSetting func(*LoginServer) type LoginServerSetting func(*LoginServer)
func WithOtherAccount(a *api.Account) LoginServerSetting { func WithOtherAccount(a *api.Account) LoginServerSetting {
+3 -4
View File
@@ -5,7 +5,6 @@ import (
"math/rand/v2" "math/rand/v2"
"time" "time"
"github.com/admin-else/strom/client"
"github.com/admin-else/strom/data" "github.com/admin-else/strom/data"
"github.com/admin-else/strom/event" "github.com/admin-else/strom/event"
"github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto"
@@ -34,7 +33,7 @@ var StatusResponse = server.StatusResponse{
type Server struct { type Server struct {
*proto.Conn *proto.Conn
*client.Timer *event.Timer
MinCycle, MaxCycle, Current int32 MinCycle, MaxCycle, Current int32
} }
@@ -66,7 +65,7 @@ var voidChunk = &v1_21_8.PlayToClientPacketMapChunk{X: 3, Z: 3, Heightmaps: []st
Data []int64 Data []int64
}{Type: "motion_blocking", Data: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}, ChunkData: v1_21_8.ByteArray{Val: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39}}, BlockEntities: []v1_21_8.ChunkBlockEntity{}, SkyLightMask: []int64{}, BlockLightMask: []int64{}, EmptySkyLightMask: []int64{}, EmptyBlockLightMask: []int64{}, SkyLight: [][]uint8{}, BlockLight: [][]uint8{}} }{Type: "motion_blocking", Data: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}, ChunkData: v1_21_8.ByteArray{Val: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0, 0x39}}, BlockEntities: []v1_21_8.ChunkBlockEntity{}, SkyLightMask: []int64{}, BlockLightMask: []int64{}, EmptySkyLightMask: []int64{}, EmptyBlockLightMask: []int64{}, SkyLight: [][]uint8{}, BlockLight: [][]uint8{}}
func (s *Server) OnStart(_ event.OnStart) (err error) { func (s *Server) OnStart(_ event.Start) (err error) {
//goland:noinspection GoResourceLeak captures the conn object which should NOT be closed //goland:noinspection GoResourceLeak captures the conn object which should NOT be closed
playerData, err := server.ServeLogin(s.Conn, server.WithRawStatus(StatusResponse), server.WithCompatibleVersions(772)) playerData, err := server.ServeLogin(s.Conn, server.WithRawStatus(StatusResponse), server.WithCompatibleVersions(772))
if err != nil { if err != nil {
@@ -170,7 +169,7 @@ func main() {
slog.SetLogLoggerLevel(slog.LevelInfo) slog.SetLogLoggerLevel(slog.LevelInfo)
err := server.StartServerWithFactory(":25565", func(c *proto.Conn) (h any, err error) { err := server.StartServerWithFactory(":25565", func(c *proto.Conn) (h any, err error) {
s := &Server{Conn: c, MinCycle: 8297, MaxCycle: 8304, Current: 8297} s := &Server{Conn: c, MinCycle: 8297, MaxCycle: 8304, Current: 8297}
s.Timer = &client.Timer{} s.Timer = &event.Timer{}
h = s h = s
return return
}) })
+3 -3
View File
@@ -34,7 +34,7 @@ func (p *ProxyClient) OnCycle(_ event.Tick) (err error) {
return return
} }
func (p *ProxyClient) OnStart(_ event.OnStart) (err error) { func (p *ProxyClient) OnStart(_ event.Start) (err error) {
return return
} }
@@ -65,7 +65,7 @@ func (p *Proxy) OnCycle(_ event.Tick) (err error) {
return return
} }
func (p *Proxy) OnStart(_ event.OnStart) (err error) { func (p *Proxy) OnStart(_ event.Start) (err error) {
return return
} }
@@ -121,7 +121,7 @@ func SaveUnCodeAbleAsTest(d proto_base.Direction, packet *proto.UnCodablePacket)
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println("Error", packet.Err, "saved to", f.Name(), "data:", packet.Data) slog.Info("Packet failed to parse", "error", packet.Err, "saved", f.Name(), "data", fmt.Sprintf("%q", packet.Data))
} }
var StatusResponse = server.StatusResponse{ var StatusResponse = server.StatusResponse{