package packet // CONNECT represents a CONNECT Packet. type CONNECT struct { base // clientID is the Client Identifier of the payload. clientID []byte // userName is the User Name of the payload. userName []byte // password is the Password of the payload. password []byte // cleanSession is the Clean Session of the variable header. cleanSession bool // keepAlive is the Keep Alive of the variable header. keepAlive uint16 // willTopic is the Will Topic of the payload. willTopic []byte // willMessage is the Will Message of the payload. willMessage []byte // willQoS is the Will QoS of the variable header. willQoS byte // willRetain is the Will Retain of the variable header. willRetain bool } // setFixedHeader sets the fixed header to the Packet. func (p *CONNECT) setFixedHeader() { // Append the first byte to the fixed header. p.fixedHeader = append(p.fixedHeader, TypeCONNECT<<4) // Append the Remaining Length to the fixed header. p.appendRemainingLength() } // setVariableHeader sets the variable header to the Packet. func (p *CONNECT) setVariableHeader() { // Convert the Keep Alive to the slice. keepAlive := encodeUint16(p.keepAlive) // Create a variable header and set it to the Packet. p.variableHeader = []byte{ 0x00, // Length MSB (0) 0x04, // Length LSB (4) 0x4D, // 'M' 0x51, // 'Q' 0x54, // 'T' 0x54, // 'T' 0x04, // Level(4) p.connectFlags(), // Connect Flags keepAlive[0], // Keep Alive MSB keepAlive[1], // Keep Alive LSB } } // setPayload sets the payload to the Packet. func (p *CONNECT) setPayload() { // Append the Client Identifier to the payload. p.payload = appendLenStr(p.payload, p.clientID) // Append the Will Topic and the Will Message to the payload // if the Packet has them. if p.will() { p.payload = appendLenStr(p.payload, p.willTopic) p.payload = appendLenStr(p.payload, p.willMessage) } // Append the User Name to the payload if the Packet has it. if len(p.userName) > 0 { p.payload = appendLenStr(p.payload, p.userName) } // Append the Password to the payload if the Packet has it. if len(p.password) > 0 { p.payload = appendLenStr(p.payload, p.password) } } // connectFlags creates and returns a byte which represents the Connect Flags. func (p *CONNECT) connectFlags() byte { // Create a byte which represents the Connect Flags. var b byte // Set 1 to the Bit 7 if the Packet has the User Name. if len(p.userName) > 0 { b |= 0x80 } // Set 1 to the Bit 6 if the Packet has the Password. if len(p.password) > 0 { b |= 0x40 } // Set 1 to the Bit 5 if the Will Retain is true. if p.willRetain { b |= 0x20 } // Set the value of the Will QoS to the Bit 4 and 3. b |= p.willQoS << 3 // Set 1 to the Bit 2 if the Packet has the Will Topic and the Will Message. if p.will() { b |= 0x04 } // Set 1 to the Bit 1 if the Clean Session is true. if p.cleanSession { b |= 0x02 } // Return the byte. return b } // will return true if both the Will Topic and the Will Message are not zero-byte. func (p *CONNECT) will() bool { return len(p.willTopic) > 0 && len(p.willMessage) > 0 } // NewCONNECT creates and returns a CONNECT Packet. func NewCONNECT(opts *CONNECTOptions) (Packet, error) { // Initialize the options. if opts == nil { opts = &CONNECTOptions{} } // Validate the options. if err := opts.validate(); err != nil { return nil, err } // Create a CONNECT Packet. p := &CONNECT{ clientID: opts.ClientID, userName: opts.UserName, password: opts.Password, cleanSession: opts.CleanSession, keepAlive: opts.KeepAlive, willTopic: opts.WillTopic, willMessage: opts.WillMessage, willQoS: opts.WillQoS, willRetain: opts.WillRetain, } // Set the variable header to the Packet. p.setVariableHeader() // Set the payload to the Packet. p.setPayload() // Set the fixed header to the packet. p.setFixedHeader() // Return the Packet. return p, nil }