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.
		
		
		
		
		
			
		
			
	
	
		
			99 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
		
		
			
		
	
	
			99 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
| 
											2 years ago
										 | package msg_util | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"bytes" | ||
|  | 	"encoding/binary" | ||
|  | 	"errors" | ||
|  | 	"google.golang.org/protobuf/proto" | ||
| 
											2 years ago
										 | 
 | ||
|  | 	"app/network" | ||
|  | 	"app/tools" | ||
| 
											2 years ago
										 | ) | ||
|  | 
 | ||
|  | func NewProtoCodec(parser *ProtoParser, maxDecode int, isRaw bool) *ProtoCodec { | ||
|  | 	return &ProtoCodec{ | ||
|  | 		parser:    parser, | ||
|  | 		maxDecode: maxDecode, | ||
|  | 		isRaw:     isRaw, | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | type ProtoCodec struct { | ||
|  | 	maxDecode int | ||
|  | 	msglen    uint32 | ||
|  | 	context   bytes.Buffer | ||
|  | 	parser    *ProtoParser | ||
|  | 	isRaw     bool //是否需要解析
 | ||
|  | } | ||
|  | 
 | ||
|  | const STREAM_HEADLEN = 4 | ||
|  | const STREAM_MSGID_LEN = 2 //uint16
 | ||
|  | 
 | ||
| 
											2 years ago
										 | var ErrUnmarshal = errors.New("message unmarshal failed") | ||
| 
											2 years ago
										 | 
 | ||
| 
											2 years ago
										 | func (s *ProtoCodec) Decode(data []byte) (msgIds []int32, ret []interface{}, err error) { | ||
| 
											2 years ago
										 | 	s.context.Write(data) | ||
|  | 
 | ||
|  | 	for s.context.Len() >= STREAM_HEADLEN+STREAM_MSGID_LEN { | ||
|  | 		if s.msglen == 0 { | ||
|  | 			d := s.context.Bytes() | ||
|  | 			s.msglen = binary.BigEndian.Uint32(d[:STREAM_HEADLEN]) - STREAM_HEADLEN //客户端headlen也算入长度
 | ||
|  | 			if s.msglen < STREAM_MSGID_LEN { | ||
|  | 				err = errors.New("data is too small") | ||
|  | 				return | ||
|  | 			} | ||
|  | 			if s.maxDecode > 0 && int(s.msglen) > s.maxDecode { | ||
|  | 				err = network.ErrRecvLen | ||
|  | 				return | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if int(s.msglen)+STREAM_HEADLEN > s.context.Len() { | ||
|  | 			break | ||
|  | 		} | ||
|  | 
 | ||
|  | 		d := make([]byte, s.msglen+STREAM_HEADLEN) | ||
|  | 		if n, err := s.context.Read(d); n != int(s.msglen)+STREAM_HEADLEN || err != nil { | ||
|  | 			s.msglen = 0 | ||
|  | 			continue | ||
|  | 		} | ||
|  | 
 | ||
|  | 		msgId := int32(binary.BigEndian.Uint16(d[STREAM_HEADLEN : STREAM_HEADLEN+STREAM_MSGID_LEN])) | ||
|  | 		var msg interface{} | ||
|  | 		if s.isRaw { | ||
|  | 			msg = d[STREAM_HEADLEN+STREAM_MSGID_LEN:] | ||
|  | 		} else { | ||
|  | 			var ok bool | ||
|  | 			msg, ok = s.parser.Unmarshal(msgId, d[STREAM_HEADLEN+STREAM_MSGID_LEN:]) | ||
|  | 			if !ok { | ||
|  | 				err = ErrUnmarshal | ||
|  | 				return | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		s.msglen = 0 | ||
|  | 		ret = append(ret, msg) | ||
|  | 		msgIds = append(msgIds, msgId) | ||
|  | 	} | ||
|  | 	return | ||
|  | } | ||
|  | 
 | ||
| 
											2 years ago
										 | func (s *ProtoCodec) Encode(data interface{}) []byte { | ||
| 
											2 years ago
										 | 	if pb, ok := data.(proto.Message); ok { | ||
|  | 		msgId, ok := s.parser.MsgToId(pb) | ||
|  | 		tools.AssertTrue(ok, "msgId=%v not found", msgId, pb) | ||
|  | 
 | ||
|  | 		pbBuf, err := proto.Marshal(pb) | ||
|  | 		tools.AssertNil(err) | ||
|  | 		buf := make([]byte, STREAM_HEADLEN+STREAM_MSGID_LEN+len(pbBuf)) | ||
|  | 		binary.BigEndian.PutUint32(buf, uint32(len(buf))) | ||
|  | 		binary.BigEndian.PutUint16(buf[STREAM_HEADLEN:], uint16(msgId)) | ||
|  | 		copy(buf[STREAM_HEADLEN+STREAM_MSGID_LEN:], pbBuf) | ||
|  | 		return buf | ||
|  | 	} else if byteArray, ok := data.([]byte); ok { | ||
|  | 		return byteArray | ||
|  | 	} else { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } |