summaryrefslogtreecommitdiff
path: root/vendor/github.com/eclipse/paho.mqtt.golang/packets
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/eclipse/paho.mqtt.golang/packets')
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go68
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go171
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go50
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go377
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go50
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go50
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go58
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go58
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go99
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go58
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go58
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go73
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go85
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go58
-rw-r--r--vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go72
15 files changed, 1385 insertions, 0 deletions
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go
new file mode 100644
index 0000000..3a7b98f
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// ConnackPacket is an internal representation of the fields of the
+// Connack MQTT packet
+type ConnackPacket struct {
+ FixedHeader
+ SessionPresent bool
+ ReturnCode byte
+}
+
+func (ca *ConnackPacket) String() string {
+ return fmt.Sprintf("%s sessionpresent: %t returncode: %d", ca.FixedHeader, ca.SessionPresent, ca.ReturnCode)
+}
+
+func (ca *ConnackPacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+
+ body.WriteByte(boolToByte(ca.SessionPresent))
+ body.WriteByte(ca.ReturnCode)
+ ca.FixedHeader.RemainingLength = 2
+ packet := ca.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (ca *ConnackPacket) Unpack(b io.Reader) error {
+ flags, err := decodeByte(b)
+ if err != nil {
+ return err
+ }
+ ca.SessionPresent = 1&flags > 0
+ ca.ReturnCode, err = decodeByte(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (ca *ConnackPacket) Details() Details {
+ return Details{Qos: 0, MessageID: 0}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go
new file mode 100644
index 0000000..b4446a5
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// ConnectPacket is an internal representation of the fields of the
+// Connect MQTT packet
+type ConnectPacket struct {
+ FixedHeader
+ ProtocolName string
+ ProtocolVersion byte
+ CleanSession bool
+ WillFlag bool
+ WillQos byte
+ WillRetain bool
+ UsernameFlag bool
+ PasswordFlag bool
+ ReservedBit byte
+ Keepalive uint16
+
+ ClientIdentifier string
+ WillTopic string
+ WillMessage []byte
+ Username string
+ Password []byte
+}
+
+func (c *ConnectPacket) String() string {
+ var password string
+ if len(c.Password) > 0 {
+ password = "<redacted>"
+ }
+ return fmt.Sprintf("%s protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalive: %d clientId: %s willtopic: %s willmessage: %s Username: %s Password: %s", c.FixedHeader, c.ProtocolVersion, c.ProtocolName, c.CleanSession, c.WillFlag, c.WillQos, c.WillRetain, c.UsernameFlag, c.PasswordFlag, c.Keepalive, c.ClientIdentifier, c.WillTopic, c.WillMessage, c.Username, password)
+}
+
+func (c *ConnectPacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+
+ body.Write(encodeString(c.ProtocolName))
+ body.WriteByte(c.ProtocolVersion)
+ body.WriteByte(boolToByte(c.CleanSession)<<1 | boolToByte(c.WillFlag)<<2 | c.WillQos<<3 | boolToByte(c.WillRetain)<<5 | boolToByte(c.PasswordFlag)<<6 | boolToByte(c.UsernameFlag)<<7)
+ body.Write(encodeUint16(c.Keepalive))
+ body.Write(encodeString(c.ClientIdentifier))
+ if c.WillFlag {
+ body.Write(encodeString(c.WillTopic))
+ body.Write(encodeBytes(c.WillMessage))
+ }
+ if c.UsernameFlag {
+ body.Write(encodeString(c.Username))
+ }
+ if c.PasswordFlag {
+ body.Write(encodeBytes(c.Password))
+ }
+ c.FixedHeader.RemainingLength = body.Len()
+ packet := c.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (c *ConnectPacket) Unpack(b io.Reader) error {
+ var err error
+ c.ProtocolName, err = decodeString(b)
+ if err != nil {
+ return err
+ }
+ c.ProtocolVersion, err = decodeByte(b)
+ if err != nil {
+ return err
+ }
+ options, err := decodeByte(b)
+ if err != nil {
+ return err
+ }
+ c.ReservedBit = 1 & options
+ c.CleanSession = 1&(options>>1) > 0
+ c.WillFlag = 1&(options>>2) > 0
+ c.WillQos = 3 & (options >> 3)
+ c.WillRetain = 1&(options>>5) > 0
+ c.PasswordFlag = 1&(options>>6) > 0
+ c.UsernameFlag = 1&(options>>7) > 0
+ c.Keepalive, err = decodeUint16(b)
+ if err != nil {
+ return err
+ }
+ c.ClientIdentifier, err = decodeString(b)
+ if err != nil {
+ return err
+ }
+ if c.WillFlag {
+ c.WillTopic, err = decodeString(b)
+ if err != nil {
+ return err
+ }
+ c.WillMessage, err = decodeBytes(b)
+ if err != nil {
+ return err
+ }
+ }
+ if c.UsernameFlag {
+ c.Username, err = decodeString(b)
+ if err != nil {
+ return err
+ }
+ }
+ if c.PasswordFlag {
+ c.Password, err = decodeBytes(b)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Validate performs validation of the fields of a Connect packet
+func (c *ConnectPacket) Validate() byte {
+ if c.PasswordFlag && !c.UsernameFlag {
+ return ErrRefusedBadUsernameOrPassword
+ }
+ if c.ReservedBit != 0 {
+ // Bad reserved bit
+ return ErrProtocolViolation
+ }
+ if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) {
+ // Mismatched or unsupported protocol version
+ return ErrRefusedBadProtocolVersion
+ }
+ if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" {
+ // Bad protocol name
+ return ErrProtocolViolation
+ }
+ if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 {
+ // Bad size field
+ return ErrProtocolViolation
+ }
+ if len(c.ClientIdentifier) == 0 && !c.CleanSession {
+ // Bad client identifier
+ return ErrRefusedIDRejected
+ }
+ return Accepted
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (c *ConnectPacket) Details() Details {
+ return Details{Qos: 0, MessageID: 0}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go
new file mode 100644
index 0000000..cf352a3
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "io"
+)
+
+// DisconnectPacket is an internal representation of the fields of the
+// Disconnect MQTT packet
+type DisconnectPacket struct {
+ FixedHeader
+}
+
+func (d *DisconnectPacket) String() string {
+ return d.FixedHeader.String()
+}
+
+func (d *DisconnectPacket) Write(w io.Writer) error {
+ packet := d.FixedHeader.pack()
+ _, err := packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (d *DisconnectPacket) Unpack(b io.Reader) error {
+ return nil
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (d *DisconnectPacket) Details() Details {
+ return Details{Qos: 0, MessageID: 0}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go
new file mode 100644
index 0000000..7cc3c6d
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// ControlPacket defines the interface for structs intended to hold
+// decoded MQTT packets, either from being read or before being
+// written
+type ControlPacket interface {
+ Write(io.Writer) error
+ Unpack(io.Reader) error
+ String() string
+ Details() Details
+}
+
+// PacketNames maps the constants for each of the MQTT packet types
+// to a string representation of their name.
+var PacketNames = map[uint8]string{
+ 1: "CONNECT",
+ 2: "CONNACK",
+ 3: "PUBLISH",
+ 4: "PUBACK",
+ 5: "PUBREC",
+ 6: "PUBREL",
+ 7: "PUBCOMP",
+ 8: "SUBSCRIBE",
+ 9: "SUBACK",
+ 10: "UNSUBSCRIBE",
+ 11: "UNSUBACK",
+ 12: "PINGREQ",
+ 13: "PINGRESP",
+ 14: "DISCONNECT",
+}
+
+// Below are the constants assigned to each of the MQTT packet types
+const (
+ Connect = 1
+ Connack = 2
+ Publish = 3
+ Puback = 4
+ Pubrec = 5
+ Pubrel = 6
+ Pubcomp = 7
+ Subscribe = 8
+ Suback = 9
+ Unsubscribe = 10
+ Unsuback = 11
+ Pingreq = 12
+ Pingresp = 13
+ Disconnect = 14
+)
+
+// Below are the const definitions for error codes returned by
+// Connect()
+const (
+ Accepted = 0x00
+ ErrRefusedBadProtocolVersion = 0x01
+ ErrRefusedIDRejected = 0x02
+ ErrRefusedServerUnavailable = 0x03
+ ErrRefusedBadUsernameOrPassword = 0x04
+ ErrRefusedNotAuthorised = 0x05
+ ErrNetworkError = 0xFE
+ ErrProtocolViolation = 0xFF
+)
+
+// ConnackReturnCodes is a map of the error codes constants for Connect()
+// to a string representation of the error
+var ConnackReturnCodes = map[uint8]string{
+ 0: "Connection Accepted",
+ 1: "Connection Refused: Bad Protocol Version",
+ 2: "Connection Refused: Client Identifier Rejected",
+ 3: "Connection Refused: Server Unavailable",
+ 4: "Connection Refused: Username or Password in unknown format",
+ 5: "Connection Refused: Not Authorised",
+ 254: "Connection Error",
+ 255: "Connection Refused: Protocol Violation",
+}
+
+var (
+ ErrorRefusedBadProtocolVersion = errors.New("unacceptable protocol version")
+ ErrorRefusedIDRejected = errors.New("identifier rejected")
+ ErrorRefusedServerUnavailable = errors.New("server Unavailable")
+ ErrorRefusedBadUsernameOrPassword = errors.New("bad user name or password")
+ ErrorRefusedNotAuthorised = errors.New("not Authorized")
+ ErrorNetworkError = errors.New("network Error")
+ ErrorProtocolViolation = errors.New("protocol Violation")
+)
+
+// ConnErrors is a map of the errors codes constants for Connect()
+// to a Go error
+var ConnErrors = map[byte]error{
+ Accepted: nil,
+ ErrRefusedBadProtocolVersion: ErrorRefusedBadProtocolVersion,
+ ErrRefusedIDRejected: ErrorRefusedIDRejected,
+ ErrRefusedServerUnavailable: ErrorRefusedServerUnavailable,
+ ErrRefusedBadUsernameOrPassword: ErrorRefusedBadUsernameOrPassword,
+ ErrRefusedNotAuthorised: ErrorRefusedNotAuthorised,
+ ErrNetworkError: ErrorNetworkError,
+ ErrProtocolViolation: ErrorProtocolViolation,
+}
+
+// ReadPacket takes an instance of an io.Reader (such as net.Conn) and attempts
+// to read an MQTT packet from the stream. It returns a ControlPacket
+// representing the decoded MQTT packet and an error. One of these returns will
+// always be nil, a nil ControlPacket indicating an error occurred.
+func ReadPacket(r io.Reader) (ControlPacket, error) {
+ var fh FixedHeader
+ b := make([]byte, 1)
+
+ _, err := io.ReadFull(r, b)
+ if err != nil {
+ return nil, err
+ }
+
+ err = fh.unpack(b[0], r)
+ if err != nil {
+ return nil, err
+ }
+
+ cp, err := NewControlPacketWithHeader(fh)
+ if err != nil {
+ return nil, err
+ }
+
+ packetBytes := make([]byte, fh.RemainingLength)
+ n, err := io.ReadFull(r, packetBytes)
+ if err != nil {
+ return nil, err
+ }
+ if n != fh.RemainingLength {
+ return nil, errors.New("failed to read expected data")
+ }
+
+ err = cp.Unpack(bytes.NewBuffer(packetBytes))
+ return cp, err
+}
+
+// NewControlPacket is used to create a new ControlPacket of the type specified
+// by packetType, this is usually done by reference to the packet type constants
+// defined in packets.go. The newly created ControlPacket is empty and a pointer
+// is returned.
+func NewControlPacket(packetType byte) ControlPacket {
+ switch packetType {
+ case Connect:
+ return &ConnectPacket{FixedHeader: FixedHeader{MessageType: Connect}}
+ case Connack:
+ return &ConnackPacket{FixedHeader: FixedHeader{MessageType: Connack}}
+ case Disconnect:
+ return &DisconnectPacket{FixedHeader: FixedHeader{MessageType: Disconnect}}
+ case Publish:
+ return &PublishPacket{FixedHeader: FixedHeader{MessageType: Publish}}
+ case Puback:
+ return &PubackPacket{FixedHeader: FixedHeader{MessageType: Puback}}
+ case Pubrec:
+ return &PubrecPacket{FixedHeader: FixedHeader{MessageType: Pubrec}}
+ case Pubrel:
+ return &PubrelPacket{FixedHeader: FixedHeader{MessageType: Pubrel, Qos: 1}}
+ case Pubcomp:
+ return &PubcompPacket{FixedHeader: FixedHeader{MessageType: Pubcomp}}
+ case Subscribe:
+ return &SubscribePacket{FixedHeader: FixedHeader{MessageType: Subscribe, Qos: 1}}
+ case Suback:
+ return &SubackPacket{FixedHeader: FixedHeader{MessageType: Suback}}
+ case Unsubscribe:
+ return &UnsubscribePacket{FixedHeader: FixedHeader{MessageType: Unsubscribe, Qos: 1}}
+ case Unsuback:
+ return &UnsubackPacket{FixedHeader: FixedHeader{MessageType: Unsuback}}
+ case Pingreq:
+ return &PingreqPacket{FixedHeader: FixedHeader{MessageType: Pingreq}}
+ case Pingresp:
+ return &PingrespPacket{FixedHeader: FixedHeader{MessageType: Pingresp}}
+ }
+ return nil
+}
+
+// NewControlPacketWithHeader is used to create a new ControlPacket of the type
+// specified within the FixedHeader that is passed to the function.
+// The newly created ControlPacket is empty and a pointer is returned.
+func NewControlPacketWithHeader(fh FixedHeader) (ControlPacket, error) {
+ switch fh.MessageType {
+ case Connect:
+ return &ConnectPacket{FixedHeader: fh}, nil
+ case Connack:
+ return &ConnackPacket{FixedHeader: fh}, nil
+ case Disconnect:
+ return &DisconnectPacket{FixedHeader: fh}, nil
+ case Publish:
+ return &PublishPacket{FixedHeader: fh}, nil
+ case Puback:
+ return &PubackPacket{FixedHeader: fh}, nil
+ case Pubrec:
+ return &PubrecPacket{FixedHeader: fh}, nil
+ case Pubrel:
+ return &PubrelPacket{FixedHeader: fh}, nil
+ case Pubcomp:
+ return &PubcompPacket{FixedHeader: fh}, nil
+ case Subscribe:
+ return &SubscribePacket{FixedHeader: fh}, nil
+ case Suback:
+ return &SubackPacket{FixedHeader: fh}, nil
+ case Unsubscribe:
+ return &UnsubscribePacket{FixedHeader: fh}, nil
+ case Unsuback:
+ return &UnsubackPacket{FixedHeader: fh}, nil
+ case Pingreq:
+ return &PingreqPacket{FixedHeader: fh}, nil
+ case Pingresp:
+ return &PingrespPacket{FixedHeader: fh}, nil
+ }
+ return nil, fmt.Errorf("unsupported packet type 0x%x", fh.MessageType)
+}
+
+// Details struct returned by the Details() function called on
+// ControlPackets to present details of the Qos and MessageID
+// of the ControlPacket
+type Details struct {
+ Qos byte
+ MessageID uint16
+}
+
+// FixedHeader is a struct to hold the decoded information from
+// the fixed header of an MQTT ControlPacket
+type FixedHeader struct {
+ MessageType byte
+ Dup bool
+ Qos byte
+ Retain bool
+ RemainingLength int
+}
+
+func (fh FixedHeader) String() string {
+ return fmt.Sprintf("%s: dup: %t qos: %d retain: %t rLength: %d", PacketNames[fh.MessageType], fh.Dup, fh.Qos, fh.Retain, fh.RemainingLength)
+}
+
+func boolToByte(b bool) byte {
+ switch b {
+ case true:
+ return 1
+ default:
+ return 0
+ }
+}
+
+func (fh *FixedHeader) pack() bytes.Buffer {
+ var header bytes.Buffer
+ header.WriteByte(fh.MessageType<<4 | boolToByte(fh.Dup)<<3 | fh.Qos<<1 | boolToByte(fh.Retain))
+ header.Write(encodeLength(fh.RemainingLength))
+ return header
+}
+
+func (fh *FixedHeader) unpack(typeAndFlags byte, r io.Reader) error {
+ fh.MessageType = typeAndFlags >> 4
+ fh.Dup = (typeAndFlags>>3)&0x01 > 0
+ fh.Qos = (typeAndFlags >> 1) & 0x03
+ fh.Retain = typeAndFlags&0x01 > 0
+
+ var err error
+ fh.RemainingLength, err = decodeLength(r)
+ return err
+}
+
+func decodeByte(b io.Reader) (byte, error) {
+ num := make([]byte, 1)
+ _, err := b.Read(num)
+ if err != nil {
+ return 0, err
+ }
+
+ return num[0], nil
+}
+
+func decodeUint16(b io.Reader) (uint16, error) {
+ num := make([]byte, 2)
+ _, err := b.Read(num)
+ if err != nil {
+ return 0, err
+ }
+ return binary.BigEndian.Uint16(num), nil
+}
+
+func encodeUint16(num uint16) []byte {
+ bytesResult := make([]byte, 2)
+ binary.BigEndian.PutUint16(bytesResult, num)
+ return bytesResult
+}
+
+func encodeString(field string) []byte {
+ return encodeBytes([]byte(field))
+}
+
+func decodeString(b io.Reader) (string, error) {
+ buf, err := decodeBytes(b)
+ return string(buf), err
+}
+
+func decodeBytes(b io.Reader) ([]byte, error) {
+ fieldLength, err := decodeUint16(b)
+ if err != nil {
+ return nil, err
+ }
+
+ field := make([]byte, fieldLength)
+ _, err = b.Read(field)
+ if err != nil {
+ return nil, err
+ }
+
+ return field, nil
+}
+
+func encodeBytes(field []byte) []byte {
+ // Attempting to encode more than 65,535 bytes would lead to an unexpected 16-bit length and extra data written
+ // (which would be parsed as later parts of the message). The safest option is to truncate.
+ if len(field) > 65535 {
+ field = field[0:65535]
+ }
+ fieldLength := make([]byte, 2)
+ binary.BigEndian.PutUint16(fieldLength, uint16(len(field)))
+ return append(fieldLength, field...)
+}
+
+func encodeLength(length int) []byte {
+ var encLength []byte
+ for {
+ digit := byte(length % 128)
+ length /= 128
+ if length > 0 {
+ digit |= 0x80
+ }
+ encLength = append(encLength, digit)
+ if length == 0 {
+ break
+ }
+ }
+ return encLength
+}
+
+func decodeLength(r io.Reader) (int, error) {
+ var rLength uint32
+ var multiplier uint32
+ b := make([]byte, 1)
+ for multiplier < 27 { // fix: Infinite '(digit & 128) == 1' will cause the dead loop
+ _, err := io.ReadFull(r, b)
+ if err != nil {
+ return 0, err
+ }
+
+ digit := b[0]
+ rLength |= uint32(digit&127) << multiplier
+ if (digit & 128) == 0 {
+ break
+ }
+ multiplier += 7
+ }
+ return int(rLength), nil
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go
new file mode 100644
index 0000000..cd52948
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "io"
+)
+
+// PingreqPacket is an internal representation of the fields of the
+// Pingreq MQTT packet
+type PingreqPacket struct {
+ FixedHeader
+}
+
+func (pr *PingreqPacket) String() string {
+ return pr.FixedHeader.String()
+}
+
+func (pr *PingreqPacket) Write(w io.Writer) error {
+ packet := pr.FixedHeader.pack()
+ _, err := packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pr *PingreqPacket) Unpack(b io.Reader) error {
+ return nil
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pr *PingreqPacket) Details() Details {
+ return Details{Qos: 0, MessageID: 0}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go
new file mode 100644
index 0000000..d7becdf
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "io"
+)
+
+// PingrespPacket is an internal representation of the fields of the
+// Pingresp MQTT packet
+type PingrespPacket struct {
+ FixedHeader
+}
+
+func (pr *PingrespPacket) String() string {
+ return pr.FixedHeader.String()
+}
+
+func (pr *PingrespPacket) Write(w io.Writer) error {
+ packet := pr.FixedHeader.pack()
+ _, err := packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pr *PingrespPacket) Unpack(b io.Reader) error {
+ return nil
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pr *PingrespPacket) Details() Details {
+ return Details{Qos: 0, MessageID: 0}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go
new file mode 100644
index 0000000..f6e727e
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "fmt"
+ "io"
+)
+
+// PubackPacket is an internal representation of the fields of the
+// Puback MQTT packet
+type PubackPacket struct {
+ FixedHeader
+ MessageID uint16
+}
+
+func (pa *PubackPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", pa.FixedHeader, pa.MessageID)
+}
+
+func (pa *PubackPacket) Write(w io.Writer) error {
+ var err error
+ pa.FixedHeader.RemainingLength = 2
+ packet := pa.FixedHeader.pack()
+ packet.Write(encodeUint16(pa.MessageID))
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pa *PubackPacket) Unpack(b io.Reader) error {
+ var err error
+ pa.MessageID, err = decodeUint16(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pa *PubackPacket) Details() Details {
+ return Details{Qos: pa.Qos, MessageID: pa.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go
new file mode 100644
index 0000000..84a1af5
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "fmt"
+ "io"
+)
+
+// PubcompPacket is an internal representation of the fields of the
+// Pubcomp MQTT packet
+type PubcompPacket struct {
+ FixedHeader
+ MessageID uint16
+}
+
+func (pc *PubcompPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", pc.FixedHeader, pc.MessageID)
+}
+
+func (pc *PubcompPacket) Write(w io.Writer) error {
+ var err error
+ pc.FixedHeader.RemainingLength = 2
+ packet := pc.FixedHeader.pack()
+ packet.Write(encodeUint16(pc.MessageID))
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pc *PubcompPacket) Unpack(b io.Reader) error {
+ var err error
+ pc.MessageID, err = decodeUint16(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pc *PubcompPacket) Details() Details {
+ return Details{Qos: pc.Qos, MessageID: pc.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go
new file mode 100644
index 0000000..9fba5df
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// PublishPacket is an internal representation of the fields of the
+// Publish MQTT packet
+type PublishPacket struct {
+ FixedHeader
+ TopicName string
+ MessageID uint16
+ Payload []byte
+}
+
+func (p *PublishPacket) String() string {
+ return fmt.Sprintf("%s topicName: %s MessageID: %d payload: %s", p.FixedHeader, p.TopicName, p.MessageID, string(p.Payload))
+}
+
+func (p *PublishPacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+
+ body.Write(encodeString(p.TopicName))
+ if p.Qos > 0 {
+ body.Write(encodeUint16(p.MessageID))
+ }
+ p.FixedHeader.RemainingLength = body.Len() + len(p.Payload)
+ packet := p.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ packet.Write(p.Payload)
+ _, err = w.Write(packet.Bytes())
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (p *PublishPacket) Unpack(b io.Reader) error {
+ var payloadLength = p.FixedHeader.RemainingLength
+ var err error
+ p.TopicName, err = decodeString(b)
+ if err != nil {
+ return err
+ }
+
+ if p.Qos > 0 {
+ p.MessageID, err = decodeUint16(b)
+ if err != nil {
+ return err
+ }
+ payloadLength -= len(p.TopicName) + 4
+ } else {
+ payloadLength -= len(p.TopicName) + 2
+ }
+ if payloadLength < 0 {
+ return fmt.Errorf("error unpacking publish, payload length < 0")
+ }
+ p.Payload = make([]byte, payloadLength)
+ _, err = b.Read(p.Payload)
+
+ return err
+}
+
+// Copy creates a new PublishPacket with the same topic and payload
+// but an empty fixed header, useful for when you want to deliver
+// a message with different properties such as Qos but the same
+// content
+func (p *PublishPacket) Copy() *PublishPacket {
+ newP := NewControlPacket(Publish).(*PublishPacket)
+ newP.TopicName = p.TopicName
+ newP.Payload = p.Payload
+
+ return newP
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (p *PublishPacket) Details() Details {
+ return Details{Qos: p.Qos, MessageID: p.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go
new file mode 100644
index 0000000..da9ed2a
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "fmt"
+ "io"
+)
+
+// PubrecPacket is an internal representation of the fields of the
+// Pubrec MQTT packet
+type PubrecPacket struct {
+ FixedHeader
+ MessageID uint16
+}
+
+func (pr *PubrecPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", pr.FixedHeader, pr.MessageID)
+}
+
+func (pr *PubrecPacket) Write(w io.Writer) error {
+ var err error
+ pr.FixedHeader.RemainingLength = 2
+ packet := pr.FixedHeader.pack()
+ packet.Write(encodeUint16(pr.MessageID))
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pr *PubrecPacket) Unpack(b io.Reader) error {
+ var err error
+ pr.MessageID, err = decodeUint16(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pr *PubrecPacket) Details() Details {
+ return Details{Qos: pr.Qos, MessageID: pr.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go
new file mode 100644
index 0000000..f418ff8
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "fmt"
+ "io"
+)
+
+// PubrelPacket is an internal representation of the fields of the
+// Pubrel MQTT packet
+type PubrelPacket struct {
+ FixedHeader
+ MessageID uint16
+}
+
+func (pr *PubrelPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", pr.FixedHeader, pr.MessageID)
+}
+
+func (pr *PubrelPacket) Write(w io.Writer) error {
+ var err error
+ pr.FixedHeader.RemainingLength = 2
+ packet := pr.FixedHeader.pack()
+ packet.Write(encodeUint16(pr.MessageID))
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (pr *PubrelPacket) Unpack(b io.Reader) error {
+ var err error
+ pr.MessageID, err = decodeUint16(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (pr *PubrelPacket) Details() Details {
+ return Details{Qos: pr.Qos, MessageID: pr.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go
new file mode 100644
index 0000000..261cf21
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// SubackPacket is an internal representation of the fields of the
+// Suback MQTT packet
+type SubackPacket struct {
+ FixedHeader
+ MessageID uint16
+ ReturnCodes []byte
+}
+
+func (sa *SubackPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", sa.FixedHeader, sa.MessageID)
+}
+
+func (sa *SubackPacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+ body.Write(encodeUint16(sa.MessageID))
+ body.Write(sa.ReturnCodes)
+ sa.FixedHeader.RemainingLength = body.Len()
+ packet := sa.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (sa *SubackPacket) Unpack(b io.Reader) error {
+ var qosBuffer bytes.Buffer
+ var err error
+ sa.MessageID, err = decodeUint16(b)
+ if err != nil {
+ return err
+ }
+
+ _, err = qosBuffer.ReadFrom(b)
+ if err != nil {
+ return err
+ }
+ sa.ReturnCodes = qosBuffer.Bytes()
+
+ return nil
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (sa *SubackPacket) Details() Details {
+ return Details{Qos: 0, MessageID: sa.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go
new file mode 100644
index 0000000..313bf5a
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// SubscribePacket is an internal representation of the fields of the
+// Subscribe MQTT packet
+type SubscribePacket struct {
+ FixedHeader
+ MessageID uint16
+ Topics []string
+ Qoss []byte
+}
+
+func (s *SubscribePacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d topics: %s", s.FixedHeader, s.MessageID, s.Topics)
+}
+
+func (s *SubscribePacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+
+ body.Write(encodeUint16(s.MessageID))
+ for i, topic := range s.Topics {
+ body.Write(encodeString(topic))
+ body.WriteByte(s.Qoss[i])
+ }
+ s.FixedHeader.RemainingLength = body.Len()
+ packet := s.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (s *SubscribePacket) Unpack(b io.Reader) error {
+ var err error
+ s.MessageID, err = decodeUint16(b)
+ if err != nil {
+ return err
+ }
+ payloadLength := s.FixedHeader.RemainingLength - 2
+ for payloadLength > 0 {
+ topic, err := decodeString(b)
+ if err != nil {
+ return err
+ }
+ s.Topics = append(s.Topics, topic)
+ qos, err := decodeByte(b)
+ if err != nil {
+ return err
+ }
+ s.Qoss = append(s.Qoss, qos)
+ payloadLength -= 2 + len(topic) + 1 // 2 bytes of string length, plus string, plus 1 byte for Qos
+ }
+
+ return nil
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (s *SubscribePacket) Details() Details {
+ return Details{Qos: 1, MessageID: s.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go
new file mode 100644
index 0000000..acdd400
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "fmt"
+ "io"
+)
+
+// UnsubackPacket is an internal representation of the fields of the
+// Unsuback MQTT packet
+type UnsubackPacket struct {
+ FixedHeader
+ MessageID uint16
+}
+
+func (ua *UnsubackPacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", ua.FixedHeader, ua.MessageID)
+}
+
+func (ua *UnsubackPacket) Write(w io.Writer) error {
+ var err error
+ ua.FixedHeader.RemainingLength = 2
+ packet := ua.FixedHeader.pack()
+ packet.Write(encodeUint16(ua.MessageID))
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (ua *UnsubackPacket) Unpack(b io.Reader) error {
+ var err error
+ ua.MessageID, err = decodeUint16(b)
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (ua *UnsubackPacket) Details() Details {
+ return Details{Qos: 0, MessageID: ua.MessageID}
+}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go
new file mode 100644
index 0000000..54d06aa
--- /dev/null
+++ b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021 IBM Corp and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander
+ */
+
+package packets
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// UnsubscribePacket is an internal representation of the fields of the
+// Unsubscribe MQTT packet
+type UnsubscribePacket struct {
+ FixedHeader
+ MessageID uint16
+ Topics []string
+}
+
+func (u *UnsubscribePacket) String() string {
+ return fmt.Sprintf("%s MessageID: %d", u.FixedHeader, u.MessageID)
+}
+
+func (u *UnsubscribePacket) Write(w io.Writer) error {
+ var body bytes.Buffer
+ var err error
+ body.Write(encodeUint16(u.MessageID))
+ for _, topic := range u.Topics {
+ body.Write(encodeString(topic))
+ }
+ u.FixedHeader.RemainingLength = body.Len()
+ packet := u.FixedHeader.pack()
+ packet.Write(body.Bytes())
+ _, err = packet.WriteTo(w)
+
+ return err
+}
+
+// Unpack decodes the details of a ControlPacket after the fixed
+// header has been read
+func (u *UnsubscribePacket) Unpack(b io.Reader) error {
+ var err error
+ u.MessageID, err = decodeUint16(b)
+ if err != nil {
+ return err
+ }
+
+ for topic, err := decodeString(b); err == nil && topic != ""; topic, err = decodeString(b) {
+ u.Topics = append(u.Topics, topic)
+ }
+
+ return err
+}
+
+// Details returns a Details struct containing the Qos and
+// MessageID of this ControlPacket
+func (u *UnsubscribePacket) Details() Details {
+ return Details{Qos: 1, MessageID: u.MessageID}
+}