Files
bl/logic/controller/controller.go

186 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controller
import (
"blazing/cool"
"blazing/logic/service/common"
"fmt"
"strconv"
"strings"
"bytes"
"context"
"reflect"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/glog"
"github.com/lunixbochs/struc"
)
var Maincontroller = &Controller{} //注入service
// 分发cmd逻辑实现Controller
type Controller struct {
Port uint16
RPCClient struct {
Kick func(uint32) error
RegisterLogic func(uint16, uint16) error
}
}
func ParseCmd[T any](a T, data []byte) T {
// := info.NewLoginSidInfo()
struc.Unpack(bytes.NewBuffer(data), &a)
return a
//fmt.Println(pinfo)
//login.OnData_1001(pinfo, player)
//fmt.Println(data)
}
func init() { //默认初始化扫描
// 解析命令行参数
cool.Config.PortBL = gcmd.GetOpt("port", "1").Uint16()
// 获取对象的反射值和类型
value := reflect.ValueOf(Maincontroller)
// 获取类型
typ := value.Type()
for i := 0; i < typ.NumMethod(); i++ {
method := typ.Method(i)
methodValue := value.MethodByName(method.Name)
//fmt.Println("找到注册方法", method.Name)
methodValue.Type().NumIn()
for _, func_cmd := range getCmd(methodValue.Type().In(0)) {
if func_cmd == 0 { //说明不是注册方法
glog.Warning(context.Background(), "方法参数必须包含CMD参数", method.Name, "跳过注册")
continue
}
if cool.Config.PortBL == 0 && func_cmd > 1000 { //判断login服务器
continue
}
if cool.Config.PortBL != 0 && func_cmd < 1000 { //判断login服务器
continue
}
glog.Debug(context.Background(), "注册方法", func_cmd, method.Name)
_, ok := cool.CmdCache.LoadOrStore(func_cmd, cool.Cmd{
Func: methodValue,
Req: methodValue.Type().In(0).Elem(),
// Res: ,
}) //TODO 待实现对不同用户初始化方法以取消全局cmdcache
if ok { //方法已存在init
glog.Error(context.Background(), "方法已存在init,不会初始化后面的方法", func_cmd)
}
}
}
}
var targetType = reflect.TypeOf(common.TomeeHeader{})
// 默认返回值(无匹配字段/解析失败时)
const defaultCmdValue = 0
// getCmd 从结构体类型中提取绑定的cmd指令递归查找嵌套结构体支持值/指针类型的TomeeHeader
// 参数 typ待解析的结构体类型支持多层指针
// 返回值解析到的cmd切片无匹配/解析失败时返回[defaultCmdValue]
func getCmd(typ reflect.Type) []uint32 {
// 初始化目标类型(仅第一次调用时执行)
// 1. 递归解引用所有指针类型(处理 *struct、**struct 等场景)
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
// 2. 非结构体类型直接返回默认值
if typ.Kind() != reflect.Struct {
return []uint32{defaultCmdValue}
}
// 3. 遍历结构体字段查找TomeeHeader字段并解析cmd
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
// 4. 调用解析函数判断是否为目标类型并解析cmd
cmdSlice, err := ParseCmdTagWithStructField(field)
if err == nil { // 解析成功,直接返回结果
return cmdSlice
}
// 5. 递归处理嵌套结构体(值/指针类型)
nestedTyp := field.Type
if nestedTyp.Kind() == reflect.Ptr {
nestedTyp = nestedTyp.Elem()
}
if nestedTyp.Kind() == reflect.Struct {
// 递归查找找到有效cmd则立即返回
if nestedCmd := getCmd(nestedTyp); len(nestedCmd) > 0 && nestedCmd[0] != defaultCmdValue {
return nestedCmd
}
}
}
// 6. 未找到目标字段/所有解析失败,返回默认值
return []uint32{defaultCmdValue}
}
// ParseCmdTagWithStructField 校验字段是否为TomeeHeader值/指针并解析cmd标签
// 参数 field结构体字段元信息
// 返回值解析后的cmd切片非目标类型/解析失败返回错误
func ParseCmdTagWithStructField(field reflect.StructField) ([]uint32, error) {
// 判断字段类型是否为 TomeeHeader 或 *TomeeHeader
var isTomeeHeader bool
switch {
case field.Type == targetType: // 值类型
isTomeeHeader = true
case field.Type.Kind() == reflect.Ptr && field.Type.Elem() == targetType: // 指针类型
isTomeeHeader = true
default:
isTomeeHeader = false
}
// 非目标类型返回错误
if !isTomeeHeader {
return nil, fmt.Errorf("field %s (type: %v) is not common.TomeeHeader or *common.TomeeHeader",
field.Name, field.Type)
}
// 提取cmd标签
cmdStr := field.Tag.Get("cmd")
if cmdStr == "" {
return nil, fmt.Errorf("field %s cmd tag is empty", field.Name)
}
// 高性能解析标签为uint32切片替代gconv减少第三方依赖且可控
parts := strings.Split(cmdStr, "|")
result := make([]uint32, 0, len(parts))
for idx, s := range parts {
// 去除空白字符(兼容标签中意外的空格)
s = strings.TrimSpace(s)
if s == "" {
return nil, fmt.Errorf("field %s cmd tag part %d is empty", field.Name, idx)
}
// 手动解析uint32比gconv更可控避免隐式转换问题
num, err := strconv.ParseUint(s, 10, 32)
if err != nil {
return nil, fmt.Errorf("field %s cmd tag part %d parse error: %v (value: %s)",
field.Name, idx, err, s)
}
result = append(result, uint32(num))
}
return result, nil
}