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.
ngs/internal/codec/codec.go

125 lines
2.7 KiB
Go

package codec
import (
"bytes"
"errors"
"ng/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 create a packet.Packet from the raw bytes slice and then encode to network bytes slice
// 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)
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
}