package msg_util import ( "app/tools" "fmt" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "strings" ) type ProtoParser struct { typemap map[int32]protoreflect.MessageType // 此map初始化后,所有session都会并发读取 msgNames map[string]int32 // 此map初始化后,所有session都会并发读取 } func NewProtoParser(packageName, msgEnum string) *ProtoParser { p := &ProtoParser{ typemap: make(map[int32]protoreflect.MessageType), msgNames: make(map[string]int32), } p.init(packageName, msgEnum) return p } // 协议enum->message自动解析: // 1、不区分大小写 // 2、过滤下划线 func (s *ProtoParser) init(packageName, msgEnum string) { lowerNames := map[string]protoreflect.MessageType{} protoregistry.GlobalTypes.RangeMessages(func(messageType protoreflect.MessageType) bool { if !strings.HasPrefix(string(messageType.Descriptor().FullName()), packageName+".") { return true } name := convertMsgName(string(messageType.Descriptor().Name())) tools.AssertTrue(nil == lowerNames[name], "msg name repeated name=%s", messageType.Descriptor().FullName()) lowerNames[name] = messageType return true }) enums, err := protoregistry.GlobalTypes.FindEnumByName(protoreflect.FullName(packageName + "." + msgEnum)) tools.AssertNil(err) values := enums.Descriptor().Values() adapter := adapters() msgDealFunc := func(msgTypeName string, msgId int32, isForce bool) { fullName := "" ln := convertMsgName(msgTypeName) if tp, ok := lowerNames[ln]; ok { s.typemap[msgId] = tp fullName = string(tp.Descriptor().FullName()) } else if tp, ok := adapter[ln]; ok { s.typemap[msgId] = tp fullName = string(tp.Descriptor().FullName()) delete(adapter, ln) } else { if isForce { panic(fmt.Errorf("msg format error msgTypeName=%v", msgTypeName)) } else { return } } if _, ok := s.msgNames[fullName]; ok { panic(fmt.Sprintf("msg name repeated name=%s", fullName)) } s.msgNames[fullName] = msgId } for i := 0; i < values.Len(); i++ { msgTypeName := string(values.Get(i).Name()) msgId := int32(values.Get(i).Number()) msgDealFunc(msgTypeName, msgId, true) } tools.AssertTrue(len(adapter) == 0, "msg not fix") } func (p *ProtoParser) Unmarshal(msgId int32, data []byte) (proto.Message, bool) { tp, ok := p.typemap[msgId] if !ok { return nil, false } msg := tp.New().Interface() err := proto.Unmarshal(data, msg) if err != nil { return nil, false } return msg, true } func (p *ProtoParser) UnmarshalByName(msgName string, data []byte) (proto.Message, bool) { msgId, ok := p.MsgNameToId(msgName) if !ok { return nil, false } return p.Unmarshal(msgId, data) } func (s *ProtoParser) MsgIdToName(msgId int32) (msgName string, ok bool) { if ptype, has := s.typemap[msgId]; has { return string(ptype.Descriptor().FullName()), true } return } func (s *ProtoParser) MsgNameToId(msgName string) (msgId int32, ok bool) { msgId, ok = s.msgNames[msgName] return } func (s *ProtoParser) MsgToId(msg proto.Message) (msgId int32, ok bool) { return s.MsgNameToId(ProtoFullName(msg)) } func convertMsgName(msgName string) (name string) { words := strings.Split(msgName, "_") for _, word := range words { name += strings.ToLower(word) } return } func ProtoFullName(msg proto.Message) string { return string(msg.ProtoReflect().Type().Descriptor().FullName()) } // 之前定义的消息id和消息体不适用自动解析的部分 func adapters() map[string]protoreflect.MessageType { return map[string]protoreflect.MessageType{} }