154 lines
3.8 KiB
Go
154 lines
3.8 KiB
Go
package load
|
||
|
||
import (
|
||
"bytes"
|
||
"fmt"
|
||
"io"
|
||
|
||
"github.com/mochi-mqtt/server/v2/packets"
|
||
)
|
||
|
||
const (
|
||
mqttProtocolLevel5 = 5
|
||
mqttKeepaliveSec = 30
|
||
)
|
||
|
||
// encodeConnect 按 DEVELOPMENT §5 生成 MQTT 5 CONNECT:
|
||
// ClientID=Username=端编号、CleanStart、心跳 30、会话过期间隔缺省为 0(Clean Start 时即为 0)。
|
||
// 不声明 Receive Maximum,避免踩 mochi 发送配额路径。
|
||
func encodeConnect(endpointID, password string) ([]byte, error) {
|
||
pk := packets.Packet{
|
||
FixedHeader: packets.FixedHeader{Type: packets.Connect},
|
||
ProtocolVersion: mqttProtocolLevel5,
|
||
Connect: packets.ConnectParams{
|
||
ProtocolName: []byte("MQTT"),
|
||
Clean: true,
|
||
ClientIdentifier: endpointID,
|
||
Keepalive: mqttKeepaliveSec,
|
||
UsernameFlag: true,
|
||
Username: []byte(endpointID),
|
||
PasswordFlag: true,
|
||
Password: []byte(password),
|
||
},
|
||
}
|
||
var buf bytes.Buffer
|
||
if err := pk.ConnectEncode(&buf); err != nil {
|
||
return nil, err
|
||
}
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
func encodeSubscribe(packetID uint16, endpointID string) ([]byte, error) {
|
||
pk := packets.Packet{
|
||
FixedHeader: packets.FixedHeader{Type: packets.Subscribe, Qos: 1},
|
||
ProtocolVersion: mqttProtocolLevel5,
|
||
PacketID: packetID,
|
||
Filters: packets.Subscriptions{
|
||
{Filter: downTopic(endpointID), Qos: 1},
|
||
},
|
||
}
|
||
var buf bytes.Buffer
|
||
if err := pk.SubscribeEncode(&buf); err != nil {
|
||
return nil, err
|
||
}
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
func encodePublish(packetID uint16, endpointID string, payload []byte) ([]byte, error) {
|
||
pk := packets.Packet{
|
||
FixedHeader: packets.FixedHeader{Type: packets.Publish, Qos: 1},
|
||
ProtocolVersion: mqttProtocolLevel5,
|
||
TopicName: upTopic(endpointID),
|
||
PacketID: packetID,
|
||
Payload: payload,
|
||
}
|
||
var buf bytes.Buffer
|
||
if err := pk.PublishEncode(&buf); err != nil {
|
||
return nil, err
|
||
}
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
func encodePuback(packetID uint16) ([]byte, error) {
|
||
pk := packets.Packet{
|
||
FixedHeader: packets.FixedHeader{Type: packets.Puback},
|
||
ProtocolVersion: mqttProtocolLevel5,
|
||
PacketID: packetID,
|
||
}
|
||
var buf bytes.Buffer
|
||
if err := pk.PubackEncode(&buf); err != nil {
|
||
return nil, err
|
||
}
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
func encodePingreq() []byte {
|
||
return []byte{0xC0, 0x00}
|
||
}
|
||
|
||
func downTopic(id string) string { return "nix/c/" + id + "/down" }
|
||
func upTopic(id string) string { return "nix/c/" + id + "/up" }
|
||
|
||
func connackReason(raw []byte) (byte, error) {
|
||
if len(raw) < 2 || raw[0]>>4 != packets.Connack {
|
||
return 0, fmt.Errorf("不是 CONNACK:type=0x%02x len=%d", byteAt(raw, 0), len(raw))
|
||
}
|
||
rem, n, err := decodeRemainingLength(raw[1:])
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
body := raw[1+n:]
|
||
if rem < 2 || len(body) < 2 {
|
||
return 0, fmt.Errorf("CONNACK 过短 remaining=%d body=%d", rem, len(body))
|
||
}
|
||
return body[1], nil
|
||
}
|
||
|
||
func decodePublish(raw []byte) (payload []byte, packetID uint16, qos byte, err error) {
|
||
if len(raw) < 2 {
|
||
return nil, 0, 0, io.ErrUnexpectedEOF
|
||
}
|
||
qos = (raw[0] >> 1) & 0x3
|
||
rem, n, err := decodeRemainingLength(raw[1:])
|
||
if err != nil {
|
||
return nil, 0, 0, err
|
||
}
|
||
body := raw[1+n:]
|
||
if len(body) != rem {
|
||
return nil, 0, 0, io.ErrUnexpectedEOF
|
||
}
|
||
pk := packets.Packet{
|
||
ProtocolVersion: mqttProtocolLevel5,
|
||
FixedHeader: packets.FixedHeader{
|
||
Type: packets.Publish,
|
||
Remaining: rem,
|
||
Qos: qos,
|
||
},
|
||
}
|
||
if err := pk.PublishDecode(body); err != nil {
|
||
return nil, 0, qos, err
|
||
}
|
||
return pk.Payload, pk.PacketID, qos, nil
|
||
}
|
||
|
||
func decodeRemainingLength(b []byte) (value int, n int, err error) {
|
||
var mul uint32 = 1
|
||
var v uint32
|
||
for i := 0; i < len(b) && i < 4; i++ {
|
||
v += uint32(b[i]&127) * mul
|
||
n++
|
||
if b[i]&128 == 0 {
|
||
return int(v), n, nil
|
||
}
|
||
mul *= 128
|
||
}
|
||
return 0, 0, io.ErrUnexpectedEOF
|
||
}
|
||
|
||
func byteAt(b []byte, i int) byte {
|
||
if i < 0 || i >= len(b) {
|
||
return 0
|
||
}
|
||
return b[i]
|
||
}
|