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