go项目脚手架
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sorbet/pkg/app/appkit/codec.go

81 lines
2.1 KiB

package appkit
import (
"bytes"
"encoding/binary"
"errors"
"math"
)
// 数据协议如下:
//
// +-----------+--------+--------------+-------+------+
// | 0x01,0x02 | length | topic-length | topic | data |
// +-----------+--------+--------------+-------+------+
// 2 2 2 n n
//
// * 头部有两个模数 0x01、0x02;
// * length 表示消息的总长度;
// * 然后分别是 topic、data,包含其长度和数据;
// * 长度使用 uint16 类型,所以占用 2 个字节;
//
// todo 实现数据校验码,防止篡改
// Encode 数据编码
func Encode(topic, data []byte) ([]byte, error) {
topicLen := len(topic)
dataLen := len(data)
size := 2 + topicLen + dataLen // 不包括模数和数据长度
if topicLen == 0 {
return nil, errors.New("topic too small")
}
if size+4 > math.MaxUint16 {
return nil, errors.New("data too big")
}
buf := &bytes.Buffer{}
// 由于 模数、topic 和 data 都是基本类型,所以当
// 执行 binary.Write() 时是不会出错的
_ = binary.Write(buf, binary.BigEndian, []byte{0x01, 0x02})
_ = binary.Write(buf, binary.BigEndian, uint16(size))
_ = binary.Write(buf, binary.BigEndian, uint16(topicLen))
_ = binary.Write(buf, binary.BigEndian, topic)
_ = binary.Write(buf, binary.BigEndian, data) // 如果没有数据会不会报错
return buf.Bytes(), nil
}
// Decode 数据解码
func Decode(buf []byte) (topic, data []byte, err error) {
r := bytes.NewReader(buf)
// 读取模数
var v [2]byte
err = binary.Read(r, binary.BigEndian, &v)
if err != nil {
return
}
if v[0] != 0x01 || v[1] != 0x02 {
err = errors.New("protocol error")
return
}
// 读取数据长度
var size uint16
err = binary.Read(r, binary.BigEndian, &size)
if err != nil {
return
}
// 读取主题长度
var topicLen uint16
err = binary.Read(r, binary.BigEndian, &topicLen)
if err != nil {
return
}
// 读取主题
topic = make([]byte, topicLen)
err = binary.Read(r, binary.BigEndian, &topic)
if err != nil {
return
}
// 读取数据
data = make([]byte, size-2-topicLen)
err = binary.Read(r, binary.BigEndian, &data)
return
}