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.
125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
package codec
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"git.noahlan.cn/northlan/ngs/internal/packet"
|
|
)
|
|
|
|
// Codec constants.
|
|
const (
|
|
HeadLength = 4
|
|
MaxPacketSize = 64 * 1024
|
|
)
|
|
|
|
// ErrPacketSizeExceed is the error used for encode/decode.
|
|
var ErrPacketSizeExceed = errors.New("codec: packet size exceed")
|
|
|
|
// A Decoder reads and decodes network data slice
|
|
type Decoder struct {
|
|
buf *bytes.Buffer
|
|
size int // last packet length
|
|
typ byte // last packet type
|
|
}
|
|
|
|
// NewDecoder returns a new decoder that used for decode network bytes slice.
|
|
func NewDecoder() *Decoder {
|
|
return &Decoder{
|
|
buf: bytes.NewBuffer(nil),
|
|
size: -1,
|
|
}
|
|
}
|
|
|
|
func (c *Decoder) forward() error {
|
|
header := c.buf.Next(HeadLength)
|
|
c.typ = header[0]
|
|
if c.typ < packet.Handshake || c.typ > packet.Kick {
|
|
return packet.ErrWrongPacketType
|
|
}
|
|
c.size = bytesToInt(header[1:])
|
|
|
|
// packet length limitation
|
|
if c.size > MaxPacketSize {
|
|
return ErrPacketSizeExceed
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Decode decode the network bytes slice to packet.Packet(s)
|
|
// TODO(Warning): shared slice
|
|
func (c *Decoder) Decode(data []byte) ([]*packet.Packet, error) {
|
|
c.buf.Write(data)
|
|
|
|
var (
|
|
packets []*packet.Packet
|
|
err error
|
|
)
|
|
// check length
|
|
if c.buf.Len() < HeadLength {
|
|
return nil, err
|
|
}
|
|
|
|
// first time
|
|
if c.size < 0 {
|
|
if err = c.forward(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
for c.size <= c.buf.Len() {
|
|
p := &packet.Packet{Type: packet.Type(c.typ), Length: c.size, Data: c.buf.Next(c.size)}
|
|
packets = append(packets, p)
|
|
|
|
// more packet
|
|
if c.buf.Len() < HeadLength {
|
|
c.size = -1
|
|
break
|
|
}
|
|
|
|
if err = c.forward(); err != nil {
|
|
return packets, err
|
|
}
|
|
}
|
|
|
|
return packets, nil
|
|
}
|
|
|
|
// Encode 从原始raw bytes创建一个用于网络传输的 packet.Packet 结构,参考网易 pomelo 协议
|
|
// Protocol refs: https://github.com/NetEase/pomelo/wiki/Communication-Protocol
|
|
//
|
|
// -<type>-|--------<length>--------|-<data>-
|
|
// --------|------------------------|--------
|
|
// 1 byte packet type, 3 bytes packet data length(big end), and data segment
|
|
func Encode(typ packet.Type, data []byte) ([]byte, error) {
|
|
if typ < packet.Handshake || typ > packet.Kick {
|
|
return nil, packet.ErrWrongPacketType
|
|
}
|
|
|
|
p := &packet.Packet{Type: typ, Length: len(data)}
|
|
buf := make([]byte, p.Length+HeadLength)
|
|
buf[0] = byte(p.Type) // 编译器提示,此处 byte 转换不能删
|
|
|
|
copy(buf[1:HeadLength], intToBytes(p.Length))
|
|
copy(buf[HeadLength:], data)
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
// Decode packet data length byte to int(Big end)
|
|
func bytesToInt(b []byte) int {
|
|
result := 0
|
|
for _, v := range b {
|
|
result = result<<8 + int(v)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Encode packet data length to bytes(Big end)
|
|
func intToBytes(n int) []byte {
|
|
buf := make([]byte, 3)
|
|
buf[0] = byte((n >> 16) & 0xFF)
|
|
buf[1] = byte((n >> 8) & 0xFF)
|
|
buf[2] = byte(n & 0xFF)
|
|
return buf
|
|
}
|