Class: PahoMqtt::Packet::Base
- Inherits:
-
Object
- Object
- PahoMqtt::Packet::Base
- Defined in:
- lib/paho_mqtt/packet/base.rb
Overview
Class representing a MQTT Packet Performs binary encoding and decoding of headers
Direct Known Subclasses
Connack, Connect, Disconnect, Pingreq, Pingresp, Puback, Pubcomp, Publish, Pubrec, Pubrel, Suback, Subscribe, Unsuback, Unsubscribe
Constant Summary collapse
- ATTR_DEFAULTS =
Default attribute values
{ :version => '3.1.0', :id => 0, :body_length => nil }
Instance Attribute Summary collapse
-
#body_length ⇒ Object
The length of the parsed packet body.
-
#flags ⇒ Object
Array of 4 bits in the fixed header.
-
#id ⇒ Object
Identifier to link related control packets together.
-
#version ⇒ Object
The version number of the MQTT protocol to use (default 3.1.0).
Class Method Summary collapse
-
.create_from_header(byte) ⇒ Object
Create a new packet object from the first byte of a MQTT packet.
-
.parse(buffer) ⇒ Object
Parse buffer into new packet object.
-
.parse_header(buffer) ⇒ Object
Parse the header and create a new packet object of the correct type The header is removed from the buffer passed into this function.
-
.read(socket) ⇒ Object
Read in a packet from a socket.
Instance Method Summary collapse
-
#encode_body ⇒ Object
Get serialisation of packet’s body (variable header and payload).
-
#initialize(args = {}) ⇒ Base
constructor
Create a new empty packet.
-
#inspect ⇒ Object
Returns a human readable string.
-
#parse_body(buffer) ⇒ Object
Parse the body (variable header and payload) of a packet.
-
#to_s ⇒ Object
Serialise the packet.
-
#type_id ⇒ Object
Get the identifer for this packet type.
-
#type_name ⇒ Object
Get the name of the packet type as a string in capitals (like the MQTT specification uses).
-
#update_attributes(attr = {}) ⇒ Object
Set packet attributes from a hash of attribute names and values.
-
#validate_flags ⇒ Object
Check that fixed header flags are valid for types that don’t use the flags.
Constructor Details
#initialize(args = {}) ⇒ Base
Create a new empty packet
135 136 137 138 139 |
# File 'lib/paho_mqtt/packet/base.rb', line 135 def initialize(args={}) # We must set flags before the other values @flags = [false, false, false, false] update_attributes(ATTR_DEFAULTS.merge(args)) end |
Instance Attribute Details
#body_length ⇒ Object
The length of the parsed packet body
35 36 37 |
# File 'lib/paho_mqtt/packet/base.rb', line 35 def body_length @body_length end |
#flags ⇒ Object
Array of 4 bits in the fixed header
32 33 34 |
# File 'lib/paho_mqtt/packet/base.rb', line 32 def flags @flags end |
#id ⇒ Object
Identifier to link related control packets together
29 30 31 |
# File 'lib/paho_mqtt/packet/base.rb', line 29 def id @id end |
#version ⇒ Object
The version number of the MQTT protocol to use (default 3.1.0)
26 27 28 |
# File 'lib/paho_mqtt/packet/base.rb', line 26 def version @version end |
Class Method Details
.create_from_header(byte) ⇒ Object
Create a new packet object from the first byte of a MQTT packet
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/paho_mqtt/packet/base.rb', line 117 def self.create_from_header(byte) unless byte.nil? # Work out the class type_id = ((byte & 0xF0) >> 4) packet_class = PahoMqtt::PACKET_TYPES[type_id] if packet_class.nil? raise "Invalid packet type identifier: #{type_id}" end # Convert the last 4 bits of byte into array of true/false flags = (0..3).map { |i| byte & (2 ** i) != 0 } # Create a new packet object packet_class.new(:flags => flags) end end |
.parse(buffer) ⇒ Object
Parse buffer into new packet object
74 75 76 77 78 |
# File 'lib/paho_mqtt/packet/base.rb', line 74 def self.parse(buffer) packet = parse_header(buffer) packet.parse_body(buffer) return packet end |
.parse_header(buffer) ⇒ Object
Parse the header and create a new packet object of the correct type The header is removed from the buffer passed into this function
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/paho_mqtt/packet/base.rb', line 82 def self.parse_header(buffer) # Check that the packet is a long as the minimum packet size if buffer.bytesize < 2 raise "Invalid packet: less than 2 bytes long" end # Create a new packet object bytes = buffer.unpack("C5") packet = create_from_header(bytes.first) packet.validate_flags # Parse the packet length body_length = 0 multiplier = 1 pos = 1 begin if buffer.bytesize <= pos raise "The packet length header is incomplete" end digit = bytes[pos] body_length += ((digit & 0x7F) * multiplier) multiplier *= 0x80 pos += 1 end while ((digit & 0x80) != 0x00) and pos <= 4 # Store the expected body length in the packet packet.instance_variable_set('@body_length', body_length) # Delete the fixed header from the raw packet passed in buffer.slice!(0...pos) return packet end |
.read(socket) ⇒ Object
Read in a packet from a socket
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/paho_mqtt/packet/base.rb', line 45 def self.read(socket) # Read in the packet header and create a new packet object packet = create_from_header( read_byte(socket) ) unless packet.nil? packet.validate_flags # Read in the packet length multiplier = 1 body_length = 0 pos = 1 begin digit = read_byte(socket) body_length += ((digit & 0x7F) * multiplier) multiplier *= 0x80 pos += 1 end while ((digit & 0x80) != 0x00) and pos <= 4 # Store the expected body length in the packet packet.instance_variable_set('@body_length', body_length) # Read in the packet body packet.parse_body( socket.read(body_length) ) end return packet end |
Instance Method Details
#encode_body ⇒ Object
Get serialisation of packet’s body (variable header and payload)
187 188 189 |
# File 'lib/paho_mqtt/packet/base.rb', line 187 def encode_body '' # No body by default end |
#inspect ⇒ Object
Returns a human readable string
233 234 235 |
# File 'lib/paho_mqtt/packet/base.rb', line 233 def inspect "\#<#{self.class}>" end |
#parse_body(buffer) ⇒ Object
Parse the body (variable header and payload) of a packet
180 181 182 183 184 |
# File 'lib/paho_mqtt/packet/base.rb', line 180 def parse_body(buffer) if buffer.bytesize != body_length raise "Failed to parse packet - input buffer (#{buffer.bytesize}) is not the same as the body length header (#{body_length})" end end |
#to_s ⇒ Object
Serialise the packet
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/paho_mqtt/packet/base.rb', line 192 def to_s # Encode the fixed header header = [ ((type_id.to_i & 0x0F) << 4) | (flags[3] ? 0x8 : 0x0) | (flags[2] ? 0x4 : 0x0) | (flags[1] ? 0x2 : 0x0) | (flags[0] ? 0x1 : 0x0) ] # Get the packet's variable header and payload body = self.encode_body # Check that that packet isn't too big body_length = body.bytesize if body_length > 268435455 raise "Error serialising packet: body is more than 256MB" end # Build up the body length field bytes begin digit = (body_length % 128) body_length = (body_length / 128) # if there are more digits to encode, set the top bit of this digit digit |= 0x80 if (body_length > 0) header.push(digit) end while (body_length > 0) # Convert header to binary and add on body header.pack('C*') + body end |
#type_id ⇒ Object
Get the identifer for this packet type
153 154 155 156 157 158 159 |
# File 'lib/paho_mqtt/packet/base.rb', line 153 def type_id index = PahoMqtt::PACKET_TYPES.index(self.class) if index.nil? raise "Invalid packet type: #{self.class}" end return index end |
#type_name ⇒ Object
Get the name of the packet type as a string in capitals (like the MQTT specification uses)
Example: CONNACK
165 166 167 |
# File 'lib/paho_mqtt/packet/base.rb', line 165 def type_name self.class.name.split('::').last.upcase end |
#update_attributes(attr = {}) ⇒ Object
Set packet attributes from a hash of attribute names and values
142 143 144 145 146 147 148 149 150 |
# File 'lib/paho_mqtt/packet/base.rb', line 142 def update_attributes(attr={}) attr.each_pair do |k,v| if v.is_a?(Array) or v.is_a?(Hash) send("#{k}=", v.dup) else send("#{k}=", v) end end end |
#validate_flags ⇒ Object
Check that fixed header flags are valid for types that don’t use the flags
226 227 228 229 230 |
# File 'lib/paho_mqtt/packet/base.rb', line 226 def validate_flags if flags != [false, false, false, false] raise "Invalid flags in #{type_name} packet header" end end |