mqtt 0.3.1 → 0.4.0
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 +15 -0
- data/NEWS.md +13 -0
- data/README.md +99 -49
- data/lib/mqtt.rb +14 -1
- data/lib/mqtt/client.rb +93 -53
- data/lib/mqtt/packet.rb +6 -6
- data/lib/mqtt/patches/string_encoding.rb +4 -0
- data/lib/mqtt/sn/packet.rb +763 -0
- data/lib/mqtt/version.rb +1 -1
- data/spec/mqtt_client_spec.rb +147 -51
- data/spec/mqtt_packet_spec.rb +67 -68
- data/spec/mqtt_sn_packet_spec.rb +1721 -0
- data/spec/zz_client_integration_spec.rb +22 -1
- metadata +22 -31
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Y2MwODVmNmViNWEyM2ViM2NkMDk1ODIzNzg3ZGJiM2EyYTdlZTJlMw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWI1ZGM5Yzk4OWZiZDBkMDY5ZDM5NTllMWQ3YzRhYTk3NThmNDY3Ng==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDg1ZTMxZTdkNjM2ZDk2ZmU0ZGRiYzcyNWI0ZDk1MWI1MGU3OTRmMmI3Yzkx
|
10
|
+
NmRiYzQ0NmE3NDlhNDQ1MDExNmY2OGM2NzNjYWNlMTAwODc0NDRiNzM3MDU1
|
11
|
+
YWYxYTYyNDdmZTUxNjI2YjM2ODU2ZTgxMGVhNjM1NjAwOWViY2I=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzkwNjYyYzYxODgyYzZjZWU2MGZhMzQ0YWZhNWM3MTVhNzdjNTFjMjEzYWFj
|
14
|
+
OGMzN2NlYjNmYTdjYzVmODNhZDZmZGIzMDg4ZjBjYmY5MzljNzRlODljMjI0
|
15
|
+
NTI3OGRmZDhhODA0NDA2NDI5ZTBlYzhjZWE3MWJhNGQwYzE4OWQ=
|
data/NEWS.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
Ruby MQTT NEWS
|
2
2
|
==============
|
3
3
|
|
4
|
+
Ruby MQTT Version 0.4.0 (2016-06-27)
|
5
|
+
------------------------------------
|
6
|
+
|
7
|
+
* Added puback handling for QoS level 1
|
8
|
+
* Low-level MQTT-SN packet parsing support
|
9
|
+
* Allow certs to be set directly instead of just by file
|
10
|
+
* Allow keyphrase for certs to be passed through
|
11
|
+
* Put 'disconnect' inside an 'ensure' block
|
12
|
+
* Fix for error on publish with frozen payload
|
13
|
+
* Fix for packets always getting id 1
|
14
|
+
* Improvements to tests
|
15
|
+
|
16
|
+
|
4
17
|
Ruby MQTT Version 0.3.1 (2014-10-10)
|
5
18
|
------------------------------------
|
6
19
|
|
data/README.md
CHANGED
@@ -5,6 +5,8 @@ ruby-mqtt
|
|
5
5
|
|
6
6
|
Pure Ruby gem that implements the [MQTT] protocol, a lightweight protocol for publish/subscribe messaging.
|
7
7
|
|
8
|
+
Also includes a class for parsing and generating [MQTT-SN] packets.
|
9
|
+
|
8
10
|
|
9
11
|
Table of Contents
|
10
12
|
-----------------
|
@@ -31,22 +33,23 @@ Alternatively, to use a development snapshot from GitHub using [Bundler]:
|
|
31
33
|
Quick Start
|
32
34
|
-----------
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
# Publish example
|
38
|
-
MQTT::Client.connect('test.mosquitto.org') do |c|
|
39
|
-
c.publish('topic', 'message')
|
40
|
-
end
|
41
|
-
|
42
|
-
# Subscribe example
|
43
|
-
MQTT::Client.connect('test.mosquitto.org') do |c|
|
44
|
-
# If you pass a block to the get method, then it will loop
|
45
|
-
c.get('test') do |topic,message|
|
46
|
-
puts "#{topic}: #{message}"
|
47
|
-
end
|
48
|
-
end
|
36
|
+
~~~ ruby
|
37
|
+
require 'rubygems'
|
38
|
+
require 'mqtt'
|
49
39
|
|
40
|
+
# Publish example
|
41
|
+
MQTT::Client.connect('test.mosquitto.org') do |c|
|
42
|
+
c.publish('test', 'message')
|
43
|
+
end
|
44
|
+
|
45
|
+
# Subscribe example
|
46
|
+
MQTT::Client.connect('test.mosquitto.org') do |c|
|
47
|
+
# If you pass a block to the get method, then it will loop
|
48
|
+
c.get('test') do |topic,message|
|
49
|
+
puts "#{topic}: #{message}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
~~~
|
50
53
|
|
51
54
|
|
52
55
|
Library Overview
|
@@ -56,42 +59,52 @@ Library Overview
|
|
56
59
|
|
57
60
|
A new client connection can be created by passing either a [MQTT URI], a host and port or by passing a hash of attributes.
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
~~~ ruby
|
63
|
+
client = MQTT::Client.connect('mqtt://myserver.example.com')
|
64
|
+
client = MQTT::Client.connect('mqtts://user:pass@myserver.example.com')
|
65
|
+
client = MQTT::Client.connect('myserver.example.com')
|
66
|
+
client = MQTT::Client.connect('myserver.example.com', 18830)
|
67
|
+
client = MQTT::Client.connect(:host => 'myserver.example.com', :port => 1883 ... )
|
68
|
+
~~~
|
64
69
|
|
65
70
|
TLS/SSL is not enabled by default, to enabled it, pass ```:ssl => true```:
|
66
71
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
~~~ ruby
|
73
|
+
client = MQTT::Client.connect(
|
74
|
+
:host => 'test.mosquitto.org',
|
75
|
+
:port => 8883,
|
76
|
+
:ssl => true
|
77
|
+
)
|
78
|
+
~~~
|
72
79
|
|
73
80
|
Alternatively you can create a new Client object and then configure it by setting attributes. This example shows setting up client certificate based authentication:
|
74
81
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
+
~~~ ruby
|
83
|
+
client = MQTT::Client.new
|
84
|
+
client.host = 'myserver.example.com'
|
85
|
+
client.ssl = true
|
86
|
+
client.cert_file = path_to('client.pem')
|
87
|
+
client.key_file = path_to('client.key')
|
88
|
+
client.ca_file = path_to('root-ca.pem')
|
89
|
+
client.connect()
|
90
|
+
~~~
|
82
91
|
|
83
92
|
The connection can either be made without the use of a block:
|
84
93
|
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
~~~ ruby
|
95
|
+
client = MQTT::Client.connect('test.mosquitto.org')
|
96
|
+
# perform operations
|
97
|
+
client.disconnect()
|
98
|
+
~~~
|
88
99
|
|
89
100
|
Or, if using a block, with an implicit disconnection at the end of the block.
|
90
101
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
102
|
+
~~~ ruby
|
103
|
+
MQTT::Client.connect('test.mosquitto.org') do |client|
|
104
|
+
# perform operations
|
105
|
+
end
|
106
|
+
~~~
|
107
|
+
|
95
108
|
For more information, see and list of attributes for the [MQTT::Client] class and the [MQTT::Client.connect] method.
|
96
109
|
|
97
110
|
|
@@ -99,7 +112,9 @@ For more information, see and list of attributes for the [MQTT::Client] class an
|
|
99
112
|
|
100
113
|
To send a message to a topic, use the ```publish``` method:
|
101
114
|
|
102
|
-
|
115
|
+
~~~ ruby
|
116
|
+
client.publish(topic, payload, retain=false)
|
117
|
+
~~~
|
103
118
|
|
104
119
|
The method will return once the message has been sent to the MQTT server.
|
105
120
|
|
@@ -110,9 +125,11 @@ For more information see the [MQTT::Client#publish] method.
|
|
110
125
|
|
111
126
|
You can send a subscription request to the MQTT server using the subscribe method. One or more [Topic Filters] may be passed in:
|
112
127
|
|
113
|
-
|
114
|
-
|
115
|
-
|
128
|
+
~~~ ruby
|
129
|
+
client.subscribe( 'topic1' )
|
130
|
+
client.subscribe( 'topic1', 'topic2' )
|
131
|
+
client.subscribe( 'foo/#' )
|
132
|
+
~~~
|
116
133
|
|
117
134
|
For more information see the [MQTT::Client#subscribe] method.
|
118
135
|
|
@@ -121,23 +138,52 @@ For more information see the [MQTT::Client#subscribe] method.
|
|
121
138
|
|
122
139
|
To receive a message, use the get method. This method will block until a message is available. The topic is the name of the topic the message was sent to. The message is a string:
|
123
140
|
|
124
|
-
|
141
|
+
~~~ ruby
|
142
|
+
topic,message = client.get
|
143
|
+
~~~
|
125
144
|
|
126
145
|
Alternatively, you can give the get method a block, which will be called for every message received and loop forever:
|
127
146
|
|
128
|
-
|
129
|
-
|
130
|
-
|
147
|
+
~~~ ruby
|
148
|
+
client.get do |topic,message|
|
149
|
+
# Block is executed for every message received
|
150
|
+
end
|
151
|
+
~~~
|
131
152
|
|
132
153
|
For more information see the [MQTT::Client#get] method.
|
133
154
|
|
134
155
|
|
156
|
+
### Parsing and serialising of packets ###
|
157
|
+
|
158
|
+
The parsing and serialising of MQTT and MQTT-SN packets is a separate lower-level API.
|
159
|
+
You can use it to build your own clients and servers, without using any of the rest of the
|
160
|
+
code in this gem.
|
161
|
+
|
162
|
+
~~~ ruby
|
163
|
+
# Parse a string containing a binary packet into an object
|
164
|
+
packet_obj = MQTT::Packet.parse(binary_packet)
|
165
|
+
|
166
|
+
# Write a PUBACK packet to an IO handle
|
167
|
+
ios << MQTT::Packet::Puback(:id => 20)
|
168
|
+
|
169
|
+
# Write an MQTT-SN Publish packet with QoS -1 to a UDP socket
|
170
|
+
socket = UDPSocket.new
|
171
|
+
socket.connect('localhost', MQTT::SN::DEFAULT_PORT)
|
172
|
+
socket << MQTT::SN::Packet::Publish.new(
|
173
|
+
:topic_id => 'TT',
|
174
|
+
:topic_id_type => :short,
|
175
|
+
:data => "The time is: #{Time.now}",
|
176
|
+
:qos => -1
|
177
|
+
)
|
178
|
+
socket.close
|
179
|
+
~~~
|
135
180
|
|
136
181
|
Limitations
|
137
182
|
-----------
|
138
183
|
|
139
|
-
*
|
184
|
+
* QoS 2 is not currently supported by client
|
140
185
|
* Automatic re-connects to the server are not supported
|
186
|
+
* No local persistence for packets
|
141
187
|
|
142
188
|
|
143
189
|
Resources
|
@@ -146,6 +192,7 @@ Resources
|
|
146
192
|
* API Documentation: http://rubydoc.info/gems/mqtt
|
147
193
|
* Protocol Specification v3.1.1: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html
|
148
194
|
* Protocol Specification v3.1: http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
|
195
|
+
* MQTT-SN Protocol Specification v1.2: http://mqtt.org/new/wp-content/uploads/2009/06/MQTT-SN_spec_v1.2.pdf
|
149
196
|
* MQTT Homepage: http://www.mqtt.org/
|
150
197
|
* GitHub Project: http://github.com/njh/ruby-mqtt
|
151
198
|
|
@@ -153,7 +200,7 @@ Resources
|
|
153
200
|
License
|
154
201
|
-------
|
155
202
|
|
156
|
-
The
|
203
|
+
The mqtt ruby gem is licensed under the terms of the MIT license.
|
157
204
|
See the file LICENSE for details.
|
158
205
|
|
159
206
|
|
@@ -162,11 +209,14 @@ Contact
|
|
162
209
|
|
163
210
|
* Author: Nicholas J Humfrey
|
164
211
|
* Email: njh@aelius.com
|
212
|
+
* Twitter: [@njh]
|
165
213
|
* Home Page: http://www.aelius.com/njh/
|
166
214
|
|
167
215
|
|
168
216
|
|
217
|
+
[@njh]: http://twitter.com/njh
|
169
218
|
[MQTT]: http://www.mqtt.org/
|
219
|
+
[MQTT-SN]: http://mqtt.org/2013/12/mqtt-for-sensor-networks-mqtt-sn
|
170
220
|
[Rubygems]: http://rubygems.org/
|
171
221
|
[Bundler]: http://bundler.io/
|
172
222
|
[MQTT URI]: https://github.com/mqtt/mqtt.github.io/wiki/URI-Scheme
|
data/lib/mqtt.rb
CHANGED
@@ -21,7 +21,7 @@ module MQTT
|
|
21
21
|
DEFAULT_SSL_PORT = 8883
|
22
22
|
|
23
23
|
# Super-class for other MQTT related exceptions
|
24
|
-
class Exception < Exception
|
24
|
+
class Exception < ::Exception
|
25
25
|
end
|
26
26
|
|
27
27
|
# A ProtocolException will be raised if there is a
|
@@ -39,4 +39,17 @@ module MQTT
|
|
39
39
|
autoload :Packet, 'mqtt/packet'
|
40
40
|
autoload :Proxy, 'mqtt/proxy'
|
41
41
|
|
42
|
+
# MQTT-SN
|
43
|
+
module SN
|
44
|
+
|
45
|
+
# Default port number for unencrypted connections
|
46
|
+
DEFAULT_PORT = 1883
|
47
|
+
|
48
|
+
# A ProtocolException will be raised if there is a
|
49
|
+
# problem with data received from a remote host
|
50
|
+
class ProtocolException < MQTT::Exception
|
51
|
+
end
|
52
|
+
|
53
|
+
autoload :Packet, 'mqtt/sn/packet'
|
54
|
+
end
|
42
55
|
end
|
data/lib/mqtt/client.rb
CHANGED
@@ -53,7 +53,7 @@ class MQTT::Client
|
|
53
53
|
# If the Will message should be retain by the server after it is sent
|
54
54
|
attr_accessor :will_retain
|
55
55
|
|
56
|
-
#Last ping response time
|
56
|
+
# Last ping response time
|
57
57
|
attr_reader :last_ping_response
|
58
58
|
|
59
59
|
|
@@ -174,13 +174,14 @@ class MQTT::Client
|
|
174
174
|
end
|
175
175
|
|
176
176
|
# Initialise private instance variables
|
177
|
-
@
|
178
|
-
@last_pingreq = Time.now
|
177
|
+
@last_ping_request = Time.now
|
179
178
|
@last_ping_response = Time.now
|
180
179
|
@socket = nil
|
181
180
|
@read_queue = Queue.new
|
181
|
+
@pubacks = {}
|
182
182
|
@read_thread = nil
|
183
183
|
@write_semaphore = Mutex.new
|
184
|
+
@pubacks_semaphore = Mutex.new
|
184
185
|
end
|
185
186
|
|
186
187
|
# Get the OpenSSL context, that is used if SSL/TLS is enabled
|
@@ -190,12 +191,24 @@ class MQTT::Client
|
|
190
191
|
|
191
192
|
# Set a path to a file containing a PEM-format client certificate
|
192
193
|
def cert_file=(path)
|
193
|
-
|
194
|
+
self.cert = File.read(path)
|
195
|
+
end
|
196
|
+
|
197
|
+
# PEM-format client certificate
|
198
|
+
def cert=(cert)
|
199
|
+
ssl_context.cert = OpenSSL::X509::Certificate.new(cert)
|
194
200
|
end
|
195
201
|
|
196
202
|
# Set a path to a file containing a PEM-format client private key
|
197
|
-
def key_file=(
|
198
|
-
|
203
|
+
def key_file=(*args)
|
204
|
+
path, passphrase = args.flatten
|
205
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(File.open(path), passphrase)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Set to a PEM-format client private key
|
209
|
+
def key=(*args)
|
210
|
+
cert, passphrase = args.flatten
|
211
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(cert, passphrase)
|
199
212
|
end
|
200
213
|
|
201
214
|
# Set a path to a file containing a PEM-format CA certificate and enable peer verification
|
@@ -287,8 +300,11 @@ class MQTT::Client
|
|
287
300
|
|
288
301
|
# If a block is given, then yield and disconnect
|
289
302
|
if block_given?
|
290
|
-
|
291
|
-
|
303
|
+
begin
|
304
|
+
yield(self)
|
305
|
+
ensure
|
306
|
+
disconnect
|
307
|
+
end
|
292
308
|
end
|
293
309
|
end
|
294
310
|
|
@@ -315,23 +331,13 @@ class MQTT::Client
|
|
315
331
|
(not @socket.nil?) and (not @socket.closed?)
|
316
332
|
end
|
317
333
|
|
318
|
-
# Send a MQTT ping message to indicate that the MQTT client is alive.
|
319
|
-
#
|
320
|
-
# Note that you will not normally need to call this method
|
321
|
-
# as it is called automatically
|
322
|
-
def ping
|
323
|
-
packet = MQTT::Packet::Pingreq.new
|
324
|
-
send_packet(packet)
|
325
|
-
@last_pingreq = Time.now
|
326
|
-
end
|
327
|
-
|
328
334
|
# Publish a message on a particular topic to the MQTT server.
|
329
335
|
def publish(topic, payload='', retain=false, qos=0)
|
330
336
|
raise ArgumentError.new("Topic name cannot be nil") if topic.nil?
|
331
337
|
raise ArgumentError.new("Topic name cannot be empty") if topic.empty?
|
332
338
|
|
333
339
|
packet = MQTT::Packet::Publish.new(
|
334
|
-
:id =>
|
340
|
+
:id => next_packet_id,
|
335
341
|
:qos => qos,
|
336
342
|
:retain => retain,
|
337
343
|
:topic => topic,
|
@@ -339,14 +345,28 @@ class MQTT::Client
|
|
339
345
|
)
|
340
346
|
|
341
347
|
# Send the packet
|
342
|
-
send_packet(packet)
|
348
|
+
res = send_packet(packet)
|
349
|
+
|
350
|
+
if packet.qos > 0
|
351
|
+
Timeout.timeout(@ack_timeout) do
|
352
|
+
while connected? do
|
353
|
+
@pubacks_semaphore.synchronize do
|
354
|
+
return res if @pubacks.delete(packet.id)
|
355
|
+
end
|
356
|
+
# FIXME: make threads communicate with each other, instead of polling
|
357
|
+
# (using a pipe and select ?)
|
358
|
+
sleep 0.01
|
359
|
+
end
|
360
|
+
end
|
361
|
+
return -1
|
362
|
+
end
|
343
363
|
end
|
344
364
|
|
345
365
|
# Send a subscribe message for one or more topics on the MQTT server.
|
346
366
|
# The topics parameter should be one of the following:
|
347
|
-
# * String: subscribe to one topic with
|
348
|
-
# * Array: subscribe to multiple topics with
|
349
|
-
# * Hash: subscribe to multiple topics where the key is the topic and the value is the
|
367
|
+
# * String: subscribe to one topic with QoS 0
|
368
|
+
# * Array: subscribe to multiple topics with QoS 0
|
369
|
+
# * Hash: subscribe to multiple topics where the key is the topic and the value is the QoS level
|
350
370
|
#
|
351
371
|
# For example:
|
352
372
|
# client.subscribe( 'a/b' )
|
@@ -356,7 +376,7 @@ class MQTT::Client
|
|
356
376
|
#
|
357
377
|
def subscribe(*topics)
|
358
378
|
packet = MQTT::Packet::Subscribe.new(
|
359
|
-
:id =>
|
379
|
+
:id => next_packet_id,
|
360
380
|
:topics => topics
|
361
381
|
)
|
362
382
|
send_packet(packet)
|
@@ -374,18 +394,13 @@ class MQTT::Client
|
|
374
394
|
# end
|
375
395
|
#
|
376
396
|
def get(topic=nil)
|
377
|
-
# Subscribe to a topic, if an argument is given
|
378
|
-
subscribe(topic) unless topic.nil?
|
379
|
-
|
380
397
|
if block_given?
|
381
|
-
|
382
|
-
loop do
|
383
|
-
packet = @read_queue.pop
|
398
|
+
get_packet(topic) do |packet|
|
384
399
|
yield(packet.topic, packet.payload)
|
385
400
|
end
|
386
401
|
else
|
387
402
|
# Wait for one packet to be available
|
388
|
-
packet =
|
403
|
+
packet = get_packet(topic)
|
389
404
|
return packet.topic, packet.payload
|
390
405
|
end
|
391
406
|
end
|
@@ -410,11 +425,15 @@ class MQTT::Client
|
|
410
425
|
if block_given?
|
411
426
|
# Loop forever!
|
412
427
|
loop do
|
413
|
-
|
428
|
+
packet = @read_queue.pop
|
429
|
+
yield(packet)
|
430
|
+
puback_packet(packet) if packet.qos > 0
|
414
431
|
end
|
415
432
|
else
|
416
433
|
# Wait for one packet to be available
|
417
|
-
|
434
|
+
packet = @read_queue.pop
|
435
|
+
puback_packet(packet) if packet.qos > 0
|
436
|
+
return packet
|
418
437
|
end
|
419
438
|
end
|
420
439
|
|
@@ -436,7 +455,7 @@ class MQTT::Client
|
|
436
455
|
|
437
456
|
packet = MQTT::Packet::Unsubscribe.new(
|
438
457
|
:topics => topics,
|
439
|
-
:id =>
|
458
|
+
:id => next_packet_id
|
440
459
|
)
|
441
460
|
send_packet(packet)
|
442
461
|
end
|
@@ -452,25 +471,9 @@ private
|
|
452
471
|
unless result.nil?
|
453
472
|
# Yes - read in the packet
|
454
473
|
packet = MQTT::Packet.read(@socket)
|
455
|
-
|
456
|
-
# Add to queue
|
457
|
-
@read_queue.push(packet)
|
458
|
-
elsif packet.class == MQTT::Packet::Pingresp
|
459
|
-
@last_ping_response = Time.now
|
460
|
-
else
|
461
|
-
# Ignore all other packets
|
462
|
-
nil
|
463
|
-
# FIXME: implement responses for QOS 1 and 2
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
# Time to send a keep-alive ping request?
|
468
|
-
if @keep_alive > 0 and Time.now > @last_pingreq + @keep_alive
|
469
|
-
ping
|
474
|
+
handle_packet packet
|
470
475
|
end
|
471
|
-
|
472
|
-
# FIXME: check we received a ping response recently?
|
473
|
-
|
476
|
+
keep_alive!
|
474
477
|
# Pass exceptions up to parent thread
|
475
478
|
rescue Exception => exp
|
476
479
|
unless @socket.nil?
|
@@ -481,6 +484,40 @@ private
|
|
481
484
|
end
|
482
485
|
end
|
483
486
|
|
487
|
+
def handle_packet(packet)
|
488
|
+
if packet.class == MQTT::Packet::Publish
|
489
|
+
# Add to queue
|
490
|
+
@read_queue.push(packet)
|
491
|
+
elsif packet.class == MQTT::Packet::Pingresp
|
492
|
+
@last_ping_response = Time.now
|
493
|
+
elsif packet.class == MQTT::Packet::Puback
|
494
|
+
@pubacks_semaphore.synchronize do
|
495
|
+
@pubacks[packet.id] = packet
|
496
|
+
end
|
497
|
+
end
|
498
|
+
# Ignore all other packets
|
499
|
+
# FIXME: implement responses for QoS 2
|
500
|
+
end
|
501
|
+
|
502
|
+
def keep_alive!
|
503
|
+
if @keep_alive > 0
|
504
|
+
response_timeout = (@keep_alive * 1.5).ceil
|
505
|
+
if Time.now >= @last_ping_request + @keep_alive
|
506
|
+
packet = MQTT::Packet::Pingreq.new
|
507
|
+
send_packet(packet)
|
508
|
+
@last_ping_request = Time.now
|
509
|
+
elsif Time.now > @last_ping_response + response_timeout
|
510
|
+
raise MQTT::ProtocolException.new(
|
511
|
+
"No Ping Response received for #{response_timeout} seconds"
|
512
|
+
)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
def puback_packet(packet)
|
518
|
+
send_packet(MQTT::Packet::Puback.new :id => packet.id)
|
519
|
+
end
|
520
|
+
|
484
521
|
# Read and check a connection acknowledgement packet
|
485
522
|
def receive_connack
|
486
523
|
Timeout.timeout(@ack_timeout) do
|
@@ -500,7 +537,7 @@ private
|
|
500
537
|
|
501
538
|
# Send a packet to server
|
502
539
|
def send_packet(data)
|
503
|
-
#
|
540
|
+
# Raise exception if we aren't connected
|
504
541
|
raise MQTT::NotConnectedException if not connected?
|
505
542
|
|
506
543
|
# Only allow one thread to write to socket at a time
|
@@ -529,6 +566,9 @@ private
|
|
529
566
|
}
|
530
567
|
end
|
531
568
|
|
569
|
+
def next_packet_id
|
570
|
+
@last_packet_id = ( @last_packet_id || 0 ).next
|
571
|
+
end
|
532
572
|
|
533
573
|
# ---- Deprecated attributes and methods ---- #
|
534
574
|
public
|