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