|
|
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{}
|
|
|
}
|