Files
go-trustlog/api/adapter/tcp_protocol.go
ryan d313449c5c refactor: 重构trustlog-sdk目录结构到trustlog/go-trustlog
- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录
- 更新README中所有import路径从trustlog-sdk改为go-trustlog
- 更新cookiecutter配置文件中的项目名称
- 更新根目录.lefthook.yml以引用新位置的配置
- 添加go.sum文件到版本控制
- 删除过时的示例文件

这次重构与trustlog-server保持一致的目录结构,
为未来支持多语言SDK(Python、Java等)预留空间。
2025-12-22 13:37:57 +08:00

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
}