vRp.CD2g_test/server/event.go

365 lines
16 KiB
Go

package server
import (
"fmt"
"github.com/kercylan98/minotaur/utils/log"
"github.com/kercylan98/minotaur/utils/runtimes"
"github.com/kercylan98/minotaur/utils/slice"
"reflect"
"runtime/debug"
"sync"
"time"
)
type StartBeforeEventHandle func(srv *Server)
type StartFinishEventHandle func(srv *Server)
type StopEventHandle func(srv *Server)
type ConnectionReceivePacketEventHandle func(srv *Server, conn *Conn, packet []byte)
type ConnectionOpenedEventHandle func(srv *Server, conn *Conn)
type ConnectionClosedEventHandle func(srv *Server, conn *Conn, err any)
type ReceiveCrossPacketEventHandle func(srv *Server, senderServerId int64, packet []byte)
type MessageErrorEventHandle func(srv *Server, message *Message, err error)
type MessageLowExecEventHandle func(srv *Server, message *Message, cost time.Duration)
type ConsoleCommandEventHandle func(srv *Server)
type ConnectionOpenedAfterEventHandle func(srv *Server, conn *Conn)
type ConnectionWritePacketBeforeEventHandle func(srv *Server, conn *Conn, packet []byte) []byte
type ShuntChannelCreatedEventHandle func(srv *Server, guid int64)
type ShuntChannelClosedEventHandle func(srv *Server, guid int64)
type ConnectionPacketPreprocessEventHandle func(srv *Server, conn *Conn, packet []byte, abort func(), usePacket func(newPacket []byte))
func newEvent(srv *Server) *event {
return &event{
Server: srv,
startBeforeEventHandles: slice.NewPriority[StartBeforeEventHandle](),
startFinishEventHandles: slice.NewPriority[StartFinishEventHandle](),
stopEventHandles: slice.NewPriority[StopEventHandle](),
connectionReceivePacketEventHandles: slice.NewPriority[ConnectionReceivePacketEventHandle](),
connectionOpenedEventHandles: slice.NewPriority[ConnectionOpenedEventHandle](),
connectionClosedEventHandles: slice.NewPriority[ConnectionClosedEventHandle](),
receiveCrossPacketEventHandles: slice.NewPriority[ReceiveCrossPacketEventHandle](),
messageErrorEventHandles: slice.NewPriority[MessageErrorEventHandle](),
messageLowExecEventHandles: slice.NewPriority[MessageLowExecEventHandle](),
connectionOpenedAfterEventHandles: slice.NewPriority[ConnectionOpenedAfterEventHandle](),
connectionWritePacketBeforeHandles: slice.NewPriority[ConnectionWritePacketBeforeEventHandle](),
shuntChannelCreatedEventHandles: slice.NewPriority[ShuntChannelCreatedEventHandle](),
shuntChannelClosedEventHandles: slice.NewPriority[ShuntChannelClosedEventHandle](),
connectionPacketPreprocessEventHandles: slice.NewPriority[ConnectionPacketPreprocessEventHandle](),
}
}
type event struct {
*Server
startBeforeEventHandles *slice.Priority[StartBeforeEventHandle]
startFinishEventHandles *slice.Priority[StartFinishEventHandle]
stopEventHandles *slice.Priority[StopEventHandle]
connectionReceivePacketEventHandles *slice.Priority[ConnectionReceivePacketEventHandle]
connectionOpenedEventHandles *slice.Priority[ConnectionOpenedEventHandle]
connectionClosedEventHandles *slice.Priority[ConnectionClosedEventHandle]
receiveCrossPacketEventHandles *slice.Priority[ReceiveCrossPacketEventHandle]
messageErrorEventHandles *slice.Priority[MessageErrorEventHandle]
messageLowExecEventHandles *slice.Priority[MessageLowExecEventHandle]
connectionOpenedAfterEventHandles *slice.Priority[ConnectionOpenedAfterEventHandle]
connectionWritePacketBeforeHandles *slice.Priority[ConnectionWritePacketBeforeEventHandle]
shuntChannelCreatedEventHandles *slice.Priority[ShuntChannelCreatedEventHandle]
shuntChannelClosedEventHandles *slice.Priority[ShuntChannelClosedEventHandle]
connectionPacketPreprocessEventHandles *slice.Priority[ConnectionPacketPreprocessEventHandle]
consoleCommandEventHandles map[string]*slice.Priority[ConsoleCommandEventHandle]
consoleCommandEventHandleInitOnce sync.Once
}
// RegStopEvent 服务器停止时将立即执行被注册的事件处理函数
func (slf *event) RegStopEvent(handle StopEventHandle, priority ...int) {
slf.stopEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnStopEvent() {
slf.stopEventHandles.RangeValue(func(index int, value StopEventHandle) bool {
value(slf.Server)
return true
})
}
// RegConsoleCommandEvent 控制台收到指令时将立即执行被注册的事件处理函数
// - 默认将注册 "exit", "quit", "close", "shutdown", "EXIT", "QUIT", "CLOSE", "SHUTDOWN" 指令作为关闭服务器的指令
// - 可通过注册默认指令进行默认行为的覆盖
func (slf *event) RegConsoleCommandEvent(command string, handle ConsoleCommandEventHandle, priority ...int) {
slf.consoleCommandEventHandleInitOnce.Do(func() {
slf.consoleCommandEventHandles = map[string]*slice.Priority[ConsoleCommandEventHandle]{}
go func() {
for {
var input string
_, _ = fmt.Scanln(&input)
slf.OnConsoleCommandEvent(input)
}
}()
})
slf.consoleCommandEventHandles[command].Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConsoleCommandEvent(command string) {
PushSystemMessage(slf.Server, func() {
handles, exist := slf.consoleCommandEventHandles[command]
if !exist {
switch command {
case "exit", "quit", "close", "shutdown", "EXIT", "QUIT", "CLOSE", "SHUTDOWN":
log.Info("Console", log.String("Receive", command), log.String("Action", "Shutdown"))
slf.Server.shutdown(nil)
return
}
log.Warn("Server", log.String("Command", "unregistered"))
} else {
handles.RangeValue(func(index int, value ConsoleCommandEventHandle) bool {
value(slf.Server)
return true
})
}
}, "ConsoleCommandEvent")
}
// RegStartBeforeEvent 在服务器初始化完成启动前立刻执行被注册的事件处理函数
func (slf *event) RegStartBeforeEvent(handle StartBeforeEventHandle, priority ...int) {
slf.startBeforeEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnStartBeforeEvent() {
defer func() {
if err := recover(); err != nil {
log.Error("Server", log.String("OnStartBeforeEvent", fmt.Sprintf("%v", err)))
debug.PrintStack()
}
}()
slf.startBeforeEventHandles.RangeValue(func(index int, value StartBeforeEventHandle) bool {
value(slf.Server)
return true
})
}
// RegStartFinishEvent 在服务器启动完成时将立刻执行被注册的事件处理函数
func (slf *event) RegStartFinishEvent(handle StartFinishEventHandle, priority ...int) {
slf.startFinishEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnStartFinishEvent() {
PushSystemMessage(slf.Server, func() {
slf.startFinishEventHandles.RangeValue(func(index int, value StartFinishEventHandle) bool {
value(slf.Server)
return true
})
}, "StartFinishEvent")
}
// RegConnectionClosedEvent 在连接关闭后将立刻执行被注册的事件处理函数
func (slf *event) RegConnectionClosedEvent(handle ConnectionClosedEventHandle, priority ...int) {
if slf.network == NetworkHttp {
panic(ErrNetworkIncompatibleHttp)
}
slf.connectionClosedEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionClosedEvent(conn *Conn, err any) {
PushSystemMessage(slf.Server, func() {
slf.connectionClosedEventHandles.RangeValue(func(index int, value ConnectionClosedEventHandle) bool {
value(slf.Server, conn, err)
return true
})
conn.Close()
slf.Server.online.Delete(conn.GetID())
}, "ConnectionClosedEvent")
}
// RegConnectionOpenedEvent 在连接打开后将立刻执行被注册的事件处理函数
func (slf *event) RegConnectionOpenedEvent(handle ConnectionOpenedEventHandle, priority ...int) {
if slf.network == NetworkHttp {
panic(ErrNetworkIncompatibleHttp)
}
slf.connectionOpenedEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionOpenedEvent(conn *Conn) {
PushSystemMessage(slf.Server, func() {
slf.Server.online.Set(conn.GetID(), conn)
slf.connectionOpenedEventHandles.RangeValue(func(index int, value ConnectionOpenedEventHandle) bool {
value(slf.Server, conn)
return true
})
}, "ConnectionOpenedEvent")
}
// RegConnectionReceivePacketEvent 在接收到数据包时将立刻执行被注册的事件处理函数
func (slf *event) RegConnectionReceivePacketEvent(handle ConnectionReceivePacketEventHandle, priority ...int) {
if slf.network == NetworkHttp {
panic(ErrNetworkIncompatibleHttp)
}
slf.connectionReceivePacketEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionReceivePacketEvent(conn *Conn, packet []byte) {
slf.connectionReceivePacketEventHandles.RangeValue(func(index int, value ConnectionReceivePacketEventHandle) bool {
value(slf.Server, conn, packet)
return true
})
}
// RegReceiveCrossPacketEvent 在接收到跨服数据包时将立即执行被注册的事件处理函数
func (slf *event) RegReceiveCrossPacketEvent(handle ReceiveCrossPacketEventHandle, priority ...int) {
slf.receiveCrossPacketEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnReceiveCrossPacketEvent(serverId int64, packet []byte) {
slf.receiveCrossPacketEventHandles.RangeValue(func(index int, value ReceiveCrossPacketEventHandle) bool {
value(slf.Server, serverId, packet)
return true
})
}
// RegMessageErrorEvent 在处理消息发生错误时将立即执行被注册的事件处理函数
func (slf *event) RegMessageErrorEvent(handle MessageErrorEventHandle, priority ...int) {
slf.messageErrorEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnMessageErrorEvent(message *Message, err error) {
PushSystemMessage(slf.Server, func() {
slf.messageErrorEventHandles.RangeValue(func(index int, value MessageErrorEventHandle) bool {
value(slf.Server, message, err)
return true
})
}, "MessageErrorEvent")
}
// RegMessageLowExecEvent 在处理消息缓慢时将立即执行被注册的事件处理函数
func (slf *event) RegMessageLowExecEvent(handle MessageLowExecEventHandle, priority ...int) {
slf.messageLowExecEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnMessageLowExecEvent(message *Message, cost time.Duration) {
PushSystemMessage(slf.Server, func() {
slf.messageLowExecEventHandles.RangeValue(func(index int, value MessageLowExecEventHandle) bool {
value(slf.Server, message, cost)
return true
})
}, "MessageLowExecEvent")
}
// RegConnectionOpenedAfterEvent 在连接打开事件处理完成后将立刻执行被注册的事件处理函数
func (slf *event) RegConnectionOpenedAfterEvent(handle ConnectionOpenedAfterEventHandle, priority ...int) {
if slf.network == NetworkHttp {
panic(ErrNetworkIncompatibleHttp)
}
slf.connectionOpenedAfterEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionOpenedAfterEvent(conn *Conn) {
PushSystemMessage(slf.Server, func() {
slf.connectionOpenedAfterEventHandles.RangeValue(func(index int, value ConnectionOpenedAfterEventHandle) bool {
value(slf.Server, conn)
return true
})
}, "ConnectionOpenedAfterEvent")
}
// RegConnectionWritePacketBeforeEvent 在发送数据包前将立刻执行被注册的事件处理函数
func (slf *event) RegConnectionWritePacketBeforeEvent(handle ConnectionWritePacketBeforeEventHandle, priority ...int) {
if slf.network == NetworkHttp {
panic(ErrNetworkIncompatibleHttp)
}
slf.connectionWritePacketBeforeHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionWritePacketBeforeEvent(conn *Conn, packet []byte) (newPacket []byte) {
if slf.connectionWritePacketBeforeHandles.Len() == 0 {
return packet
}
newPacket = packet
slf.connectionWritePacketBeforeHandles.RangeValue(func(index int, value ConnectionWritePacketBeforeEventHandle) bool {
newPacket = value(slf.Server, conn, newPacket)
return true
})
return newPacket
}
// RegShuntChannelCreatedEvent 在分流通道创建时将立刻执行被注册的事件处理函数
func (slf *event) RegShuntChannelCreatedEvent(handle ShuntChannelCreatedEventHandle, priority ...int) {
slf.shuntChannelCreatedEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnShuntChannelCreatedEvent(guid int64) {
PushSystemMessage(slf.Server, func() {
slf.shuntChannelCreatedEventHandles.RangeValue(func(index int, value ShuntChannelCreatedEventHandle) bool {
value(slf.Server, guid)
return true
})
}, "ShuntChannelCreatedEvent")
}
// RegShuntChannelCloseEvent 在分流通道关闭时将立刻执行被注册的事件处理函数
func (slf *event) RegShuntChannelCloseEvent(handle ShuntChannelClosedEventHandle, priority ...int) {
slf.shuntChannelClosedEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnShuntChannelClosedEvent(guid int64) {
PushSystemMessage(slf.Server, func() {
slf.shuntChannelClosedEventHandles.RangeValue(func(index int, value ShuntChannelClosedEventHandle) bool {
value(slf.Server, guid)
return true
})
}, "ShuntChannelCloseEvent")
}
// RegConnectionPacketPreprocessEvent 在接收到数据包后将立刻执行被注册的事件处理函数
// - 预处理函数可以用于对数据包进行预处理,如解密、解压缩等
// - 在调用 abort() 后,将不会再调用后续的预处理函数,也不会调用 OnConnectionReceivePacketEvent 函数
// - 在调用 usePacket() 后,将使用新的数据包,而不会使用原始数据包,同时阻止后续的预处理函数的调用
//
// 场景:
// - 数据包格式校验
// - 数据包分包等情况处理
func (slf *event) RegConnectionPacketPreprocessEvent(handle ConnectionPacketPreprocessEventHandle, priority ...int) {
slf.connectionPacketPreprocessEventHandles.Append(handle, slice.GetValue(priority, 0))
log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String()))
}
func (slf *event) OnConnectionPacketPreprocessEvent(conn *Conn, packet []byte, usePacket func(newPacket []byte)) bool {
if slf.connectionPacketPreprocessEventHandles.Len() == 0 {
return false
}
var abort = false
slf.connectionPacketPreprocessEventHandles.RangeValue(func(index int, value ConnectionPacketPreprocessEventHandle) bool {
value(slf.Server, conn, packet, func() { abort = true }, usePacket)
if abort {
return false
}
return true
})
return abort
}
func (slf *event) check() {
switch slf.network {
case NetworkHttp, NetworkGRPC, NetworkNone:
default:
if slf.connectionReceivePacketEventHandles.Len() == 0 {
log.Warn("Server", log.String("ConnectionReceivePacketEvent", "invalid server, no packets processed"))
}
}
if slf.receiveCrossPacketEventHandles.Len() > 0 && slf.cross == nil {
log.Warn("Server", log.String("ReceiveCrossPacketEvent", "invalid server, not register cross server"))
}
}