paho-mqtt 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/lib/paho-mqtt.rb +44 -62
- data/lib/paho_mqtt/client.rb +51 -43
- data/lib/paho_mqtt/connection_helper.rb +15 -15
- data/lib/paho_mqtt/exception.rb +43 -0
- data/lib/paho_mqtt/handler.rb +21 -33
- data/lib/paho_mqtt/packet/base.rb +27 -19
- data/lib/paho_mqtt/packet/connack.rb +9 -7
- data/lib/paho_mqtt/packet/connect.rb +24 -19
- data/lib/paho_mqtt/packet/disconnect.rb +2 -1
- data/lib/paho_mqtt/packet/pingresp.rb +2 -1
- data/lib/paho_mqtt/packet/puback.rb +2 -1
- data/lib/paho_mqtt/packet/pubcomp.rb +2 -1
- data/lib/paho_mqtt/packet/publish.rb +15 -11
- data/lib/paho_mqtt/packet/pubrec.rb +2 -1
- data/lib/paho_mqtt/packet/pubrel.rb +2 -1
- data/lib/paho_mqtt/packet/suback.rb +6 -4
- data/lib/paho_mqtt/packet/subscribe.rb +10 -7
- data/lib/paho_mqtt/packet/unsuback.rb +2 -1
- data/lib/paho_mqtt/packet/unsubscribe.rb +7 -5
- data/lib/paho_mqtt/publisher.rb +73 -62
- data/lib/paho_mqtt/sender.rb +18 -22
- data/lib/paho_mqtt/subscriber.rb +52 -41
- data/lib/paho_mqtt/version.rb +1 -1
- metadata +3 -2
@@ -30,7 +30,8 @@ module PahoMqtt
|
|
30
30
|
super(buffer)
|
31
31
|
@id = shift_short(buffer)
|
32
32
|
unless buffer.empty?
|
33
|
-
raise
|
33
|
+
raise PahoMqtt::PacketFormatException.new(
|
34
|
+
"Extra bytes at end of Publish Acknowledgment packet")
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -37,7 +37,7 @@ module PahoMqtt
|
|
37
37
|
|
38
38
|
# Default attribute values
|
39
39
|
ATTR_DEFAULTS = {
|
40
|
-
:topic
|
40
|
+
:topic => nil,
|
41
41
|
:payload => ''
|
42
42
|
}
|
43
43
|
|
@@ -79,8 +79,9 @@ module PahoMqtt
|
|
79
79
|
# Set the Quality of Service level (0/1/2)
|
80
80
|
def qos=(arg)
|
81
81
|
@qos = arg.to_i
|
82
|
-
if @qos < 0
|
83
|
-
raise
|
82
|
+
if @qos < 0 || @qos > 2
|
83
|
+
raise PahoMqtt::PacketFormatException.new(
|
84
|
+
"Invalid QoS value: #{@qos}")
|
84
85
|
else
|
85
86
|
@flags[1] = (arg & 0x01 == 0x01)
|
86
87
|
@flags[2] = (arg & 0x02 == 0x02)
|
@@ -90,8 +91,9 @@ module PahoMqtt
|
|
90
91
|
# Get serialisation of packet's body
|
91
92
|
def encode_body
|
92
93
|
body = ''
|
93
|
-
if @topic.nil?
|
94
|
-
raise
|
94
|
+
if @topic.nil? || @topic.to_s.empty?
|
95
|
+
raise PahoMqtt::PacketFormatException.new(
|
96
|
+
"Invalid topic name when serialising packet")
|
95
97
|
end
|
96
98
|
body += encode_string(@topic)
|
97
99
|
body += encode_short(@id) unless qos == 0
|
@@ -102,8 +104,8 @@ module PahoMqtt
|
|
102
104
|
# Parse the body (variable header and payload) of a Publish packet
|
103
105
|
def parse_body(buffer)
|
104
106
|
super(buffer)
|
105
|
-
@topic
|
106
|
-
@id
|
107
|
+
@topic = shift_string(buffer)
|
108
|
+
@id = shift_short(buffer) unless qos == 0
|
107
109
|
@payload = buffer
|
108
110
|
end
|
109
111
|
|
@@ -111,10 +113,12 @@ module PahoMqtt
|
|
111
113
|
# @private
|
112
114
|
def validate_flags
|
113
115
|
if qos == 3
|
114
|
-
raise
|
116
|
+
raise PahoMqtt::PacketFormatException.new(
|
117
|
+
"Invalid packet: QoS value of 3 is not allowed")
|
115
118
|
end
|
116
|
-
if qos == 0
|
117
|
-
raise
|
119
|
+
if qos == 0 && duplicate
|
120
|
+
raise PahoMqtt::PacketFormatException.new(
|
121
|
+
"Invalid packet: DUP cannot be set for QoS 0")
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
@@ -133,7 +137,7 @@ module PahoMqtt
|
|
133
137
|
|
134
138
|
def inspect_payload
|
135
139
|
str = payload.to_s
|
136
|
-
if str.bytesize < 16
|
140
|
+
if str.bytesize < 16 && str =~ /^[ -~]*$/
|
137
141
|
"'#{str}'"
|
138
142
|
else
|
139
143
|
"... (#{str.bytesize} bytes)"
|
@@ -41,14 +41,16 @@ module PahoMqtt
|
|
41
41
|
elsif value.is_a?(Integer)
|
42
42
|
@return_codes = [value]
|
43
43
|
else
|
44
|
-
raise
|
44
|
+
raise PahoMqtt::PacketFormatException.new(
|
45
|
+
"return_codes should be an integer or an array of return codes")
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
49
|
# Get serialisation of packet's body
|
49
50
|
def encode_body
|
50
51
|
if @return_codes.empty?
|
51
|
-
raise
|
52
|
+
raise PahoMqtt::PacketFormatException.new(
|
53
|
+
"No granted QoS given when serialising packet")
|
52
54
|
end
|
53
55
|
body = encode_short(@id)
|
54
56
|
return_codes.each { |qos| body += encode_bytes(qos) }
|
@@ -59,14 +61,14 @@ module PahoMqtt
|
|
59
61
|
def parse_body(buffer)
|
60
62
|
super(buffer)
|
61
63
|
@id = shift_short(buffer)
|
62
|
-
while
|
64
|
+
while buffer.bytesize > 0
|
63
65
|
@return_codes << shift_byte(buffer)
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
67
69
|
# Returns a human readable string, summarising the properties of the packet
|
68
70
|
def inspect
|
69
|
-
"\#<#{self.class}: 0x%2.2X, rc=%s>" % [id, return_codes.map{|rc| "0x%2.2X" % rc}.join(',')]
|
71
|
+
"\#<#{self.class}: 0x%2.2X, rc=%s>" % [id, return_codes.map { |rc| "0x%2.2X" % rc }.join(',')]
|
70
72
|
end
|
71
73
|
end
|
72
74
|
end
|
@@ -64,13 +64,14 @@ module PahoMqtt
|
|
64
64
|
# Peek at the next item in the array, and remove it if it is an integer
|
65
65
|
if input.first.is_a?(Integer)
|
66
66
|
qos = input.shift
|
67
|
-
@topics << [item,qos]
|
67
|
+
@topics << [item, qos]
|
68
68
|
else
|
69
|
-
@topics << [item,0]
|
69
|
+
@topics << [item, 0]
|
70
70
|
end
|
71
71
|
else
|
72
72
|
# Meh?
|
73
|
-
raise
|
73
|
+
raise PahoMqtt::PacketFormatException.new(
|
74
|
+
"Invalid topics input: #{value.inspect}")
|
74
75
|
end
|
75
76
|
end
|
76
77
|
@topics
|
@@ -79,7 +80,8 @@ module PahoMqtt
|
|
79
80
|
# Get serialisation of packet's body
|
80
81
|
def encode_body
|
81
82
|
if @topics.empty?
|
82
|
-
raise
|
83
|
+
raise PahoMqtt::PacketFormatException.new(
|
84
|
+
"No topics given when serialising packet")
|
83
85
|
end
|
84
86
|
body = encode_short(@id)
|
85
87
|
topics.each do |item|
|
@@ -97,7 +99,7 @@ module PahoMqtt
|
|
97
99
|
while(buffer.bytesize>0)
|
98
100
|
topic_name = shift_string(buffer)
|
99
101
|
topic_qos = shift_byte(buffer)
|
100
|
-
@topics << [topic_name,topic_qos]
|
102
|
+
@topics << [topic_name, topic_qos]
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
@@ -105,7 +107,8 @@ module PahoMqtt
|
|
105
107
|
# @private
|
106
108
|
def validate_flags
|
107
109
|
if @flags != [false, true, false, false]
|
108
|
-
raise
|
110
|
+
raise PahoMqtt::PacketFormatException.new(
|
111
|
+
"Invalid flags in SUBSCRIBE packet header")
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
@@ -113,7 +116,7 @@ module PahoMqtt
|
|
113
116
|
def inspect
|
114
117
|
_str = "\#<#{self.class}: 0x%2.2X, %s>" % [
|
115
118
|
id,
|
116
|
-
topics.map {|t| "'#{t[0]}':#{t[1]}"}.join(', ')
|
119
|
+
topics.map { |t| "'#{t[0]}':#{t[1]}" }.join(', ')
|
117
120
|
]
|
118
121
|
end
|
119
122
|
end
|
@@ -35,7 +35,8 @@ module PahoMqtt
|
|
35
35
|
super(buffer)
|
36
36
|
@id = shift_short(buffer)
|
37
37
|
unless buffer.empty?
|
38
|
-
raise
|
38
|
+
raise PahoMqtt::PacketFormatException.new(
|
39
|
+
"Extra bytes at end of Unsubscribe Acknowledgment packet")
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -26,7 +26,7 @@ module PahoMqtt
|
|
26
26
|
# Default attribute values
|
27
27
|
ATTR_DEFAULTS = {
|
28
28
|
:topics => [],
|
29
|
-
:flags
|
29
|
+
:flags => [false, true, false, false],
|
30
30
|
}
|
31
31
|
|
32
32
|
# Create a new Unsubscribe packet
|
@@ -46,7 +46,8 @@ module PahoMqtt
|
|
46
46
|
# Get serialisation of packet's body
|
47
47
|
def encode_body
|
48
48
|
if @topics.empty?
|
49
|
-
raise
|
49
|
+
raise PahoMqtt::PacketFormatException.new(
|
50
|
+
"No topics given when serialising packet")
|
50
51
|
end
|
51
52
|
body = encode_short(@id)
|
52
53
|
topics.each { |topic| body += encode_string(topic) }
|
@@ -57,7 +58,7 @@ module PahoMqtt
|
|
57
58
|
def parse_body(buffer)
|
58
59
|
super(buffer)
|
59
60
|
@id = shift_short(buffer)
|
60
|
-
while
|
61
|
+
while buffer.bytesize > 0
|
61
62
|
@topics << shift_string(buffer)
|
62
63
|
end
|
63
64
|
end
|
@@ -66,7 +67,8 @@ module PahoMqtt
|
|
66
67
|
# @private
|
67
68
|
def validate_flags
|
68
69
|
if @flags != [false, true, false, false]
|
69
|
-
raise
|
70
|
+
raise PahoMqtt::PacketFormatException.new(
|
71
|
+
"Invalid flags in UNSUBSCRIBE packet header")
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -74,7 +76,7 @@ module PahoMqtt
|
|
74
76
|
def inspect
|
75
77
|
"\#<#{self.class}: 0x%2.2X, %s>" % [
|
76
78
|
id,
|
77
|
-
topics.map {|t| "'#{t}'"}.join(', ')
|
79
|
+
topics.map { |t| "'#{t}'" }.join(', ')
|
78
80
|
]
|
79
81
|
end
|
80
82
|
end
|
data/lib/paho_mqtt/publisher.rb
CHANGED
@@ -16,15 +16,15 @@ module PahoMqtt
|
|
16
16
|
class Publisher
|
17
17
|
|
18
18
|
def initialize(sender)
|
19
|
-
@waiting_puback
|
20
|
-
@waiting_pubrec
|
21
|
-
@waiting_pubrel
|
19
|
+
@waiting_puback = []
|
20
|
+
@waiting_pubrec = []
|
21
|
+
@waiting_pubrel = []
|
22
22
|
@waiting_pubcomp = []
|
23
|
-
@puback_mutex
|
24
|
-
@pubrec_mutex
|
25
|
-
@pubrel_mutex
|
26
|
-
@pubcomp_mutex
|
27
|
-
@sender
|
23
|
+
@puback_mutex = Mutex.new
|
24
|
+
@pubrec_mutex = Mutex.new
|
25
|
+
@pubrel_mutex = Mutex.new
|
26
|
+
@pubcomp_mutex = Mutex.new
|
27
|
+
@sender = sender
|
28
28
|
end
|
29
29
|
|
30
30
|
def sender=(sender)
|
@@ -33,23 +33,31 @@ module PahoMqtt
|
|
33
33
|
|
34
34
|
def send_publish(topic, payload, retain, qos, new_id)
|
35
35
|
packet = PahoMqtt::Packet::Publish.new(
|
36
|
-
:id
|
37
|
-
:topic
|
36
|
+
:id => new_id,
|
37
|
+
:topic => topic,
|
38
38
|
:payload => payload,
|
39
|
-
:retain
|
40
|
-
:qos
|
39
|
+
:retain => retain,
|
40
|
+
:qos => qos
|
41
41
|
)
|
42
|
-
@sender.append_to_writing(packet)
|
43
42
|
case qos
|
44
43
|
when 1
|
45
|
-
@puback_mutex.synchronize
|
46
|
-
@waiting_puback.
|
47
|
-
|
44
|
+
@puback_mutex.synchronize do
|
45
|
+
if @waiting_puback.length >= MAX_PUBACK
|
46
|
+
PahoMqtt.logger.error('PUBACK queue is full, could not send with qos=1') if PahoMqtt.logger?
|
47
|
+
return MQTT_ERR_FAIL
|
48
|
+
end
|
49
|
+
@waiting_puback.push(:id => new_id, :packet => packet, :timestamp => Time.now)
|
50
|
+
end
|
48
51
|
when 2
|
49
|
-
@pubrec_mutex.synchronize
|
50
|
-
@waiting_pubrec.
|
51
|
-
|
52
|
+
@pubrec_mutex.synchronize do
|
53
|
+
if @waiting_pubrec.length >= MAX_PUBREC
|
54
|
+
PahoMqtt.logger.error('PUBREC queue is full, could not send with qos=2') if PahoMqtt.logger?
|
55
|
+
return MQTT_ERR_FAIL
|
56
|
+
end
|
57
|
+
@waiting_pubrec.push(:id => new_id, :packet => packet, :timestamp => Time.now)
|
58
|
+
end
|
52
59
|
end
|
60
|
+
@sender.append_to_writing(packet)
|
53
61
|
MQTT_ERR_SUCCESS
|
54
62
|
end
|
55
63
|
|
@@ -61,8 +69,8 @@ module PahoMqtt
|
|
61
69
|
when 2
|
62
70
|
send_pubrec(packet_id)
|
63
71
|
else
|
64
|
-
|
65
|
-
raise PacketException
|
72
|
+
PahoMqtt.logger.error("The packet QoS value is invalid in publish.") if PahoMqtt.logger?
|
73
|
+
raise PacketException.new('Invalid publish QoS value')
|
66
74
|
end
|
67
75
|
MQTT_ERR_SUCCESS
|
68
76
|
end
|
@@ -76,27 +84,31 @@ module PahoMqtt
|
|
76
84
|
end
|
77
85
|
|
78
86
|
def do_puback(packet_id)
|
79
|
-
@puback_mutex.synchronize
|
87
|
+
@puback_mutex.synchronize do
|
80
88
|
@waiting_puback.delete_if { |pck| pck[:id] == packet_id }
|
81
|
-
|
82
|
-
MQTT_ERR_SUCCESS
|
89
|
+
end
|
90
|
+
MQTT_ERR_SUCCESS
|
83
91
|
end
|
84
|
-
|
92
|
+
|
85
93
|
def send_pubrec(packet_id)
|
86
94
|
packet = PahoMqtt::Packet::Pubrec.new(
|
87
95
|
:id => packet_id
|
88
96
|
)
|
97
|
+
@pubrel_mutex.synchronize do
|
98
|
+
if @waiting_pubrel.length >= MAX_PUBREL
|
99
|
+
PahoMqtt.logger.error('PUBREL queue is full, could not acknowledge qos=2') if PahoMqtt.logger?
|
100
|
+
return MQTT_ERR_FAIL
|
101
|
+
end
|
102
|
+
@waiting_pubrel.push(:id => packet_id , :packet => packet, :timestamp => Time.now)
|
103
|
+
end
|
89
104
|
@sender.append_to_writing(packet)
|
90
|
-
@pubrel_mutex.synchronize{
|
91
|
-
@waiting_pubrel.push({:id => packet_id , :packet => packet, :timestamp => Time.now})
|
92
|
-
}
|
93
105
|
MQTT_ERR_SUCCESS
|
94
106
|
end
|
95
107
|
|
96
108
|
def do_pubrec(packet_id)
|
97
|
-
@pubrec_mutex.synchronize
|
109
|
+
@pubrec_mutex.synchronize do
|
98
110
|
@waiting_pubrec.delete_if { |pck| pck[:id] == packet_id }
|
99
|
-
|
111
|
+
end
|
100
112
|
send_pubrel(packet_id)
|
101
113
|
MQTT_ERR_SUCCESS
|
102
114
|
end
|
@@ -105,17 +117,21 @@ module PahoMqtt
|
|
105
117
|
packet = PahoMqtt::Packet::Pubrel.new(
|
106
118
|
:id => packet_id
|
107
119
|
)
|
120
|
+
@pubcomp_mutex.synchronize do
|
121
|
+
if @waiting_pubcomp.length >= MAX_PUBCOMP
|
122
|
+
PahoMqtt.logger.error('PUBCOMP queue is full, could not acknowledge qos=2') if PahoMqtt.logger?
|
123
|
+
return MQTT_ERR_FAIL
|
124
|
+
end
|
125
|
+
@waiting_pubcomp.push(:id => packet_id, :packet => packet, :timestamp => Time.now)
|
126
|
+
end
|
108
127
|
@sender.append_to_writing(packet)
|
109
|
-
@pubcomp_mutex.synchronize{
|
110
|
-
@waiting_pubcomp.push({:id => packet_id, :packet => packet, :timestamp => Time.now})
|
111
|
-
}
|
112
128
|
MQTT_ERR_SUCCESS
|
113
129
|
end
|
114
130
|
|
115
131
|
def do_pubrel(packet_id)
|
116
|
-
@pubrel_mutex.synchronize
|
132
|
+
@pubrel_mutex.synchronize do
|
117
133
|
@waiting_pubrel.delete_if { |pck| pck[:id] == packet_id }
|
118
|
-
|
134
|
+
end
|
119
135
|
send_pubcomp(packet_id)
|
120
136
|
MQTT_ERR_SUCCESS
|
121
137
|
end
|
@@ -129,52 +145,47 @@ module PahoMqtt
|
|
129
145
|
end
|
130
146
|
|
131
147
|
def do_pubcomp(packet_id)
|
132
|
-
@pubcomp_mutex.synchronize
|
148
|
+
@pubcomp_mutex.synchronize do
|
133
149
|
@waiting_pubcomp.delete_if { |pck| pck[:id] == packet_id }
|
134
|
-
|
150
|
+
end
|
135
151
|
MQTT_ERR_SUCCESS
|
136
152
|
end
|
137
153
|
|
138
154
|
def config_all_message_queue
|
139
|
-
config_message_queue(@waiting_puback, @puback_mutex
|
140
|
-
config_message_queue(@waiting_pubrec, @pubrec_mutex
|
141
|
-
config_message_queue(@waiting_pubrel, @pubrel_mutex
|
142
|
-
config_message_queue(@waiting_pubcomp, @pubcomp_mutex
|
155
|
+
config_message_queue(@waiting_puback, @puback_mutex)
|
156
|
+
config_message_queue(@waiting_pubrec, @pubrec_mutex)
|
157
|
+
config_message_queue(@waiting_pubrel, @pubrel_mutex)
|
158
|
+
config_message_queue(@waiting_pubcomp, @pubcomp_mutex)
|
143
159
|
end
|
144
160
|
|
145
|
-
def config_message_queue(queue, mutex
|
146
|
-
mutex.synchronize
|
147
|
-
cnt = 0
|
161
|
+
def config_message_queue(queue, mutex)
|
162
|
+
mutex.synchronize do
|
148
163
|
queue.each do |pck|
|
149
|
-
pck[:
|
150
|
-
if cnt <= max_packet
|
151
|
-
@sender.append_to_writing(pck[:packet])
|
152
|
-
cnt += 1
|
153
|
-
end
|
164
|
+
pck[:timestamp] = Time.now
|
154
165
|
end
|
155
|
-
|
166
|
+
end
|
156
167
|
end
|
157
168
|
|
158
169
|
def check_waiting_publisher
|
159
|
-
@sender.check_ack_alive(@waiting_puback, @puback_mutex
|
160
|
-
@sender.check_ack_alive(@waiting_pubrec, @pubrec_mutex
|
161
|
-
@sender.check_ack_alive(@waiting_pubrel, @pubrel_mutex
|
162
|
-
@sender.check_ack_alive(@waiting_pubcomp, @pubcomp_mutex
|
170
|
+
@sender.check_ack_alive(@waiting_puback, @puback_mutex)
|
171
|
+
@sender.check_ack_alive(@waiting_pubrec, @pubrec_mutex)
|
172
|
+
@sender.check_ack_alive(@waiting_pubrel, @pubrel_mutex)
|
173
|
+
@sender.check_ack_alive(@waiting_pubcomp, @pubcomp_mutex)
|
163
174
|
end
|
164
175
|
|
165
176
|
def flush_publisher
|
166
|
-
@puback_mutex.synchronize
|
177
|
+
@puback_mutex.synchronize do
|
167
178
|
@waiting_puback = []
|
168
|
-
|
169
|
-
@pubrec_mutex.synchronize
|
179
|
+
end
|
180
|
+
@pubrec_mutex.synchronize do
|
170
181
|
@waiting_pubrec = []
|
171
|
-
|
172
|
-
@pubrel_mutex.synchronize
|
182
|
+
end
|
183
|
+
@pubrel_mutex.synchronize do
|
173
184
|
@waiting_pubrel = []
|
174
|
-
|
175
|
-
@pubcomp_mutex.synchronize
|
185
|
+
end
|
186
|
+
@pubcomp_mutex.synchronize do
|
176
187
|
@waiting_pubcomp = []
|
177
|
-
|
188
|
+
end
|
178
189
|
end
|
179
190
|
end
|
180
191
|
end
|