- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录 - 更新README中所有import路径从trustlog-sdk改为go-trustlog - 更新cookiecutter配置文件中的项目名称 - 更新根目录.lefthook.yml以引用新位置的配置 - 添加go.sum文件到版本控制 - 删除过时的示例文件 这次重构与trustlog-server保持一致的目录结构, 为未来支持多语言SDK(Python、Java等)预留空间。
150 lines
3.5 KiB
Go
150 lines
3.5 KiB
Go
package adapter
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// 协议常量.
|
|
const (
|
|
// MessageTypeData 表示数据消息.
|
|
MessageTypeData byte = 0x01
|
|
// MessageTypeAck 表示 ACK 确认.
|
|
MessageTypeAck byte = 0x02
|
|
// MessageTypeNack 表示 NACK 否定确认.
|
|
MessageTypeNack byte = 0x03
|
|
|
|
// 协议限制.
|
|
maxTopicLength = 65535
|
|
maxUUIDLength = 255
|
|
maxPayloadSize = 1 << 30
|
|
topicLengthSize = 2
|
|
uuidLengthSize = 1
|
|
payloadLengthSize = 4
|
|
)
|
|
|
|
// 预定义错误.
|
|
var (
|
|
ErrNilMessage = errors.New("message is nil")
|
|
ErrTopicTooLong = errors.New("topic too long")
|
|
ErrUUIDTooLong = errors.New("uuid too long")
|
|
ErrPayloadTooLarge = errors.New("payload too large")
|
|
)
|
|
|
|
// TCPMessage 表示 TCP 传输的消息.
|
|
type TCPMessage struct {
|
|
Type byte // 消息类型
|
|
Topic string // 主题
|
|
UUID string // 消息 UUID
|
|
Payload []byte // 消息内容
|
|
}
|
|
|
|
// EncodeTCPMessage 将消息编码为字节数组.
|
|
// 格式: [消息类型 1字节][Topic长度 2字节][Topic][UUID长度 1字节][UUID][Payload长度 4字节][Payload].
|
|
func EncodeTCPMessage(msg *TCPMessage) ([]byte, error) {
|
|
if msg == nil {
|
|
return nil, ErrNilMessage
|
|
}
|
|
|
|
topicLen := len(msg.Topic)
|
|
if topicLen > maxTopicLength {
|
|
return nil, ErrTopicTooLong
|
|
}
|
|
|
|
uuidLen := len(msg.UUID)
|
|
if uuidLen > maxUUIDLength {
|
|
return nil, ErrUUIDTooLong
|
|
}
|
|
|
|
payloadLen := len(msg.Payload)
|
|
if payloadLen > maxPayloadSize {
|
|
return nil, ErrPayloadTooLarge
|
|
}
|
|
|
|
// 计算总长度
|
|
totalLen := 1 + topicLengthSize + topicLen + uuidLengthSize + uuidLen + payloadLengthSize + payloadLen
|
|
buf := make([]byte, totalLen)
|
|
|
|
offset := 0
|
|
|
|
// 写入消息类型
|
|
buf[offset] = msg.Type
|
|
offset++
|
|
|
|
// 写入 Topic 长度和内容
|
|
binary.BigEndian.PutUint16(buf[offset:], uint16(topicLen))
|
|
offset += topicLengthSize
|
|
copy(buf[offset:], []byte(msg.Topic))
|
|
offset += topicLen
|
|
|
|
// 写入 UUID 长度和内容
|
|
buf[offset] = byte(uuidLen)
|
|
offset++
|
|
copy(buf[offset:], []byte(msg.UUID))
|
|
offset += uuidLen
|
|
|
|
// 写入 Payload 长度和内容
|
|
binary.BigEndian.PutUint32(buf[offset:], uint32(payloadLen))
|
|
offset += payloadLengthSize
|
|
copy(buf[offset:], msg.Payload)
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
// DecodeTCPMessage 从字节数组解码消息.
|
|
func DecodeTCPMessage(reader io.Reader) (*TCPMessage, error) {
|
|
msg := &TCPMessage{}
|
|
|
|
// 读取消息类型
|
|
msgTypeBuf := make([]byte, 1)
|
|
if _, err := io.ReadFull(reader, msgTypeBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
msg.Type = msgTypeBuf[0]
|
|
|
|
// 读取 Topic 长度
|
|
topicLenBuf := make([]byte, topicLengthSize)
|
|
if _, err := io.ReadFull(reader, topicLenBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
topicLen := binary.BigEndian.Uint16(topicLenBuf)
|
|
|
|
// 读取 Topic
|
|
topicBuf := make([]byte, topicLen)
|
|
if _, err := io.ReadFull(reader, topicBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
msg.Topic = string(topicBuf)
|
|
|
|
// 读取 UUID 长度
|
|
uuidLenBuf := make([]byte, 1)
|
|
if _, err := io.ReadFull(reader, uuidLenBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
uuidLen := uuidLenBuf[0]
|
|
|
|
// 读取 UUID
|
|
uuidBuf := make([]byte, uuidLen)
|
|
if _, err := io.ReadFull(reader, uuidBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
msg.UUID = string(uuidBuf)
|
|
|
|
// 读取 Payload 长度
|
|
payloadLenBuf := make([]byte, payloadLengthSize)
|
|
if _, err := io.ReadFull(reader, payloadLenBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
payloadLen := binary.BigEndian.Uint32(payloadLenBuf)
|
|
|
|
// 读取 Payload
|
|
payloadBuf := make([]byte, payloadLen)
|
|
if _, err := io.ReadFull(reader, payloadBuf); err != nil {
|
|
return nil, err
|
|
}
|
|
msg.Payload = payloadBuf
|
|
|
|
return msg, nil
|
|
}
|