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
		
	
| package msg_util
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/binary"
 | |
| 	"errors"
 | |
| 	"google.golang.org/protobuf/proto"
 | |
| 
 | |
| 	"app/network"
 | |
| 	"app/tools"
 | |
| )
 | |
| 
 | |
| 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
 | |
| 
 | |
| var ErrUnmarshal = errors.New("message unmarshal failed")
 | |
| 
 | |
| func (s *ProtoCodec) Decode(data []byte) (msgIds []int32, ret []interface{}, err error) {
 | |
| 	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
 | |
| }
 | |
| 
 | |
| func (s *ProtoCodec) Encode(data interface{}) []byte {
 | |
| 	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
 | |
| 	}
 | |
| }
 |