You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.6 KiB
Go

2 years ago
package msg_util
import (
2 years ago
"app/tools"
2 years ago
"fmt"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
2 years ago
"strings"
2 years ago
)
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{}
}