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