apiotics-paho-mqtt 1.0.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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/README.md +322 -0
- data/Rakefile +6 -0
- data/apiotics-paho-mqtt.gemspec +33 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/paho-mqtt.rb +165 -0
- data/lib/paho_mqtt/client.rb +417 -0
- data/lib/paho_mqtt/connection_helper.rb +169 -0
- data/lib/paho_mqtt/exception.rb +43 -0
- data/lib/paho_mqtt/handler.rb +273 -0
- data/lib/paho_mqtt/packet/base.rb +315 -0
- data/lib/paho_mqtt/packet/connack.rb +102 -0
- data/lib/paho_mqtt/packet/connect.rb +183 -0
- data/lib/paho_mqtt/packet/disconnect.rb +38 -0
- data/lib/paho_mqtt/packet/pingreq.rb +29 -0
- data/lib/paho_mqtt/packet/pingresp.rb +38 -0
- data/lib/paho_mqtt/packet/puback.rb +44 -0
- data/lib/paho_mqtt/packet/pubcomp.rb +44 -0
- data/lib/paho_mqtt/packet/publish.rb +148 -0
- data/lib/paho_mqtt/packet/pubrec.rb +44 -0
- data/lib/paho_mqtt/packet/pubrel.rb +62 -0
- data/lib/paho_mqtt/packet/suback.rb +75 -0
- data/lib/paho_mqtt/packet/subscribe.rb +124 -0
- data/lib/paho_mqtt/packet/unsuback.rb +49 -0
- data/lib/paho_mqtt/packet/unsubscribe.rb +84 -0
- data/lib/paho_mqtt/packet.rb +33 -0
- data/lib/paho_mqtt/publisher.rb +191 -0
- data/lib/paho_mqtt/sender.rb +86 -0
- data/lib/paho_mqtt/ssl_helper.rb +42 -0
- data/lib/paho_mqtt/subscriber.rb +163 -0
- data/lib/paho_mqtt/version.rb +3 -0
- data/samples/client_blocking(reading).rb +30 -0
- data/samples/client_blocking(writing).rb +18 -0
- data/samples/getting_started.rb +49 -0
- data/samples/test_client.rb +70 -0
- metadata +127 -0
@@ -0,0 +1,417 @@
|
|
1
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
2
|
+
#
|
3
|
+
# All rights reserved. This program and the accompanying materials
|
4
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
5
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
6
|
+
#
|
7
|
+
# The Eclipse Public License is available at
|
8
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
9
|
+
# and the Eclipse Distribution License is available at
|
10
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
11
|
+
#
|
12
|
+
# Contributors:
|
13
|
+
# Pierre Goudet - initial committer
|
14
|
+
|
15
|
+
require 'paho_mqtt/handler'
|
16
|
+
require 'paho_mqtt/connection_helper'
|
17
|
+
require 'paho_mqtt/sender'
|
18
|
+
require 'paho_mqtt/publisher'
|
19
|
+
require 'paho_mqtt/subscriber'
|
20
|
+
require 'paho_mqtt/ssl_helper'
|
21
|
+
|
22
|
+
module PahoMqtt
|
23
|
+
class Client
|
24
|
+
# Connection related attributes:
|
25
|
+
attr_accessor :host
|
26
|
+
attr_accessor :port
|
27
|
+
attr_accessor :mqtt_version
|
28
|
+
attr_accessor :clean_session
|
29
|
+
attr_accessor :persistent
|
30
|
+
attr_accessor :reconnect_limit
|
31
|
+
attr_accessor :reconnect_delay
|
32
|
+
attr_accessor :blocking
|
33
|
+
attr_accessor :client_id
|
34
|
+
attr_accessor :username
|
35
|
+
attr_accessor :password
|
36
|
+
attr_accessor :ssl
|
37
|
+
|
38
|
+
# Last will attributes:
|
39
|
+
attr_accessor :will_topic
|
40
|
+
attr_accessor :will_payload
|
41
|
+
attr_accessor :will_qos
|
42
|
+
attr_accessor :will_retain
|
43
|
+
|
44
|
+
# Timeout attributes:
|
45
|
+
attr_accessor :keep_alive
|
46
|
+
attr_accessor :ack_timeout
|
47
|
+
|
48
|
+
#Read Only attribute
|
49
|
+
attr_reader :connection_state
|
50
|
+
attr_reader :ssl_context
|
51
|
+
|
52
|
+
def initialize(*args)
|
53
|
+
@last_ping_resp = Time.now
|
54
|
+
@last_packet_id = 0
|
55
|
+
@ssl_context = nil
|
56
|
+
@sender = nil
|
57
|
+
@handler = Handler.new
|
58
|
+
@connection_helper = nil
|
59
|
+
@connection_state = MQTT_CS_DISCONNECT
|
60
|
+
@connection_state_mutex = Mutex.new
|
61
|
+
@mqtt_thread = nil
|
62
|
+
@reconnect_thread = nil
|
63
|
+
@id_mutex = Mutex.new
|
64
|
+
@reconnect_limit = 3
|
65
|
+
@reconnect_delay = 5
|
66
|
+
|
67
|
+
if args.last.is_a?(Hash)
|
68
|
+
attr = args.pop
|
69
|
+
else
|
70
|
+
attr = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
CLIENT_ATTR_DEFAULTS.merge(attr).each_pair do |k,v|
|
74
|
+
self.send("#{k}=", v)
|
75
|
+
end
|
76
|
+
|
77
|
+
if @ssl
|
78
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
79
|
+
end
|
80
|
+
|
81
|
+
if @port.nil?
|
82
|
+
if @ssl
|
83
|
+
@port = DEFAULT_SSL_PORT
|
84
|
+
else
|
85
|
+
@port = DEFAULT_PORT
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if @client_id.nil? || @client_id == ""
|
90
|
+
@client_id = generate_client_id
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def generate_client_id(prefix='paho_ruby', lenght=16)
|
95
|
+
charset = Array('A'..'Z') + Array('a'..'z') + Array('0'..'9')
|
96
|
+
@client_id = prefix << Array.new(lenght) { charset.sample }.join
|
97
|
+
end
|
98
|
+
|
99
|
+
def config_ssl_context(cert_path, key_path, ca_path=nil)
|
100
|
+
@ssl ||= true
|
101
|
+
@ssl_context = SSLHelper.config_ssl_context(cert_path, key_path, ca_path)
|
102
|
+
end
|
103
|
+
|
104
|
+
def connect(host=@host, port=@port, keep_alive=@keep_alive, persistent=@persistent, blocking=@blocking)
|
105
|
+
@persistent = persistent
|
106
|
+
@blocking = blocking
|
107
|
+
@host = host
|
108
|
+
@port = port.to_i
|
109
|
+
@keep_alive = keep_alive
|
110
|
+
@connection_state_mutex.synchronize do
|
111
|
+
@connection_state = MQTT_CS_NEW
|
112
|
+
end
|
113
|
+
@mqtt_thread.kill unless @mqtt_thread.nil?
|
114
|
+
|
115
|
+
init_connection
|
116
|
+
@connection_helper.send_connect(session_params)
|
117
|
+
begin
|
118
|
+
@connection_state = @connection_helper.do_connect(reconnect?)
|
119
|
+
if connected?
|
120
|
+
build_pubsub
|
121
|
+
daemon_mode unless @blocking
|
122
|
+
end
|
123
|
+
rescue LowVersionException
|
124
|
+
downgrade_version
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def daemon_mode
|
129
|
+
@mqtt_thread = Thread.new do
|
130
|
+
@reconnect_thread.kill unless @reconnect_thread.nil? || !@reconnect_thread.alive?
|
131
|
+
begin
|
132
|
+
while connected? do
|
133
|
+
mqtt_loop
|
134
|
+
end
|
135
|
+
rescue SystemCallError => e
|
136
|
+
if @persistent
|
137
|
+
reconnect
|
138
|
+
else
|
139
|
+
raise e
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def connected?
|
146
|
+
@connection_state == MQTT_CS_CONNECTED
|
147
|
+
end
|
148
|
+
|
149
|
+
def reconnect?
|
150
|
+
Thread.current == @reconnect_thread
|
151
|
+
end
|
152
|
+
|
153
|
+
def loop_write(max_packet=MAX_WRITING)
|
154
|
+
begin
|
155
|
+
@sender.writing_loop(max_packet)
|
156
|
+
rescue WritingException
|
157
|
+
if check_persistence
|
158
|
+
reconnect
|
159
|
+
else
|
160
|
+
raise WritingException
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def loop_read(max_packet=MAX_READ)
|
166
|
+
max_packet.times do
|
167
|
+
begin
|
168
|
+
@handler.receive_packet
|
169
|
+
rescue ReadingException
|
170
|
+
if check_persistence
|
171
|
+
reconnect
|
172
|
+
else
|
173
|
+
raise ReadingException
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def mqtt_loop
|
180
|
+
loop_read
|
181
|
+
loop_write
|
182
|
+
loop_misc
|
183
|
+
sleep LOOP_TEMPO
|
184
|
+
end
|
185
|
+
|
186
|
+
def loop_misc
|
187
|
+
if @connection_helper.check_keep_alive(@persistent, @handler.last_ping_resp, @keep_alive) == MQTT_CS_DISCONNECT
|
188
|
+
reconnect if check_persistence
|
189
|
+
end
|
190
|
+
@publisher.check_waiting_publisher
|
191
|
+
@subscriber.check_waiting_subscriber
|
192
|
+
end
|
193
|
+
|
194
|
+
def reconnect
|
195
|
+
@reconnect_thread = Thread.new do
|
196
|
+
counter = 0
|
197
|
+
while (@reconnect_limit >= counter || @reconnect_limit == -1) do
|
198
|
+
counter += 1
|
199
|
+
PahoMqtt.logger.debug("New reconnect attempt...") if PahoMqtt.logger?
|
200
|
+
connect
|
201
|
+
if connected?
|
202
|
+
break
|
203
|
+
else
|
204
|
+
sleep @reconnect_delay
|
205
|
+
end
|
206
|
+
end
|
207
|
+
unless connected?
|
208
|
+
PahoMqtt.logger.error("Reconnection attempt counter is over. (#{@reconnect_limit} times)") if PahoMqtt.logger?
|
209
|
+
disconnect(false)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def disconnect(explicit=true)
|
215
|
+
@last_packet_id = 0 if explicit
|
216
|
+
@connection_helper.do_disconnect(@publisher, explicit, @mqtt_thread)
|
217
|
+
@connection_state_mutex.synchronize do
|
218
|
+
@connection_state = MQTT_CS_DISCONNECT
|
219
|
+
end
|
220
|
+
MQTT_ERR_SUCCESS
|
221
|
+
end
|
222
|
+
|
223
|
+
def publish(topic, payload="", retain=false, qos=0)
|
224
|
+
if topic == "" || !topic.is_a?(String)
|
225
|
+
PahoMqtt.logger.error("Publish topics is invalid, not a string or empty.") if PahoMqtt.logger?
|
226
|
+
raise ArgumentError
|
227
|
+
end
|
228
|
+
id = next_packet_id
|
229
|
+
@publisher.send_publish(topic, payload, retain, qos, id)
|
230
|
+
end
|
231
|
+
|
232
|
+
def subscribe(*topics)
|
233
|
+
begin
|
234
|
+
id = next_packet_id
|
235
|
+
unless @subscriber.send_subscribe(topics, id) == PahoMqtt::MQTT_ERR_SUCCESS
|
236
|
+
reconnect if check_persistence
|
237
|
+
end
|
238
|
+
MQTT_ERR_SUCCESS
|
239
|
+
rescue ProtocolViolation
|
240
|
+
PahoMqtt.logger.error("Subscribe topics need one topic or a list of topics.") if PahoMqtt.logger?
|
241
|
+
disconnect(false)
|
242
|
+
raise ProtocolViolation
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def unsubscribe(*topics)
|
247
|
+
begin
|
248
|
+
id = next_packet_id
|
249
|
+
unless @subscriber.send_unsubscribe(topics, id) == MQTT_ERR_SUCCESS
|
250
|
+
reconnect if check_persistence
|
251
|
+
end
|
252
|
+
MQTT_ERR_SUCCESS
|
253
|
+
rescue ProtocolViolation
|
254
|
+
PahoMqtt.logger.error("Unsubscribe need at least one topic.") if PahoMqtt.logger?
|
255
|
+
disconnect(false)
|
256
|
+
raise ProtocolViolation
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def ping_host
|
261
|
+
@sender.send_pingreq
|
262
|
+
end
|
263
|
+
|
264
|
+
def add_topic_callback(topic, callback=nil, &block)
|
265
|
+
@handler.register_topic_callback(topic, callback, &block)
|
266
|
+
end
|
267
|
+
|
268
|
+
def remove_topic_callback(topic)
|
269
|
+
@handler.clear_topic_callback(topic)
|
270
|
+
end
|
271
|
+
|
272
|
+
def on_connack(&block)
|
273
|
+
@handler.on_connack = block if block_given?
|
274
|
+
@handler.on_connack
|
275
|
+
end
|
276
|
+
|
277
|
+
def on_suback(&block)
|
278
|
+
@handler.on_suback = block if block_given?
|
279
|
+
@handler.on_suback
|
280
|
+
end
|
281
|
+
|
282
|
+
def on_unsuback(&block)
|
283
|
+
@handler.on_unsuback = block if block_given?
|
284
|
+
@handler.on_unsuback
|
285
|
+
end
|
286
|
+
|
287
|
+
def on_puback(&block)
|
288
|
+
@handler.on_puback = block if block_given?
|
289
|
+
@handler.on_puback
|
290
|
+
end
|
291
|
+
|
292
|
+
def on_pubrec(&block)
|
293
|
+
@handler.on_pubrec = block if block_given?
|
294
|
+
@handler.on_pubrec
|
295
|
+
end
|
296
|
+
|
297
|
+
def on_pubrel(&block)
|
298
|
+
@handler.on_pubrel = block if block_given?
|
299
|
+
@handler.on_pubrel
|
300
|
+
end
|
301
|
+
|
302
|
+
def on_pubcomp(&block)
|
303
|
+
@handler.on_pubcomp = block if block_given?
|
304
|
+
@handler.on_pubcomp
|
305
|
+
end
|
306
|
+
|
307
|
+
def on_message(&block)
|
308
|
+
@handler.on_message = block if block_given?
|
309
|
+
@handler.on_message
|
310
|
+
end
|
311
|
+
|
312
|
+
def on_connack=(callback)
|
313
|
+
@handler.on_connack = callback if callback.is_a?(Proc)
|
314
|
+
end
|
315
|
+
|
316
|
+
def on_suback=(callback)
|
317
|
+
@handler.on_suback = callback if callback.is_a?(Proc)
|
318
|
+
end
|
319
|
+
|
320
|
+
def on_unsuback=(callback)
|
321
|
+
@handler.on_unsuback = callback if callback.is_a?(Proc)
|
322
|
+
end
|
323
|
+
|
324
|
+
def on_puback=(callback)
|
325
|
+
@handler.on_puback = callback if callback.is_a?(Proc)
|
326
|
+
end
|
327
|
+
|
328
|
+
def on_pubrec=(callback)
|
329
|
+
@handler.on_pubrec = callback if callback.is_a?(Proc)
|
330
|
+
end
|
331
|
+
|
332
|
+
def on_pubrel=(callback)
|
333
|
+
@handler.on_pubrel = callback if callback.is_a?(Proc)
|
334
|
+
end
|
335
|
+
|
336
|
+
def on_pubcomp=(callback)
|
337
|
+
@handler.on_pubcomp = callback if callback.is_a?(Proc)
|
338
|
+
end
|
339
|
+
|
340
|
+
def on_message=(callback)
|
341
|
+
@handler.on_message = callback if callback.is_a?(Proc)
|
342
|
+
end
|
343
|
+
|
344
|
+
def registered_callback
|
345
|
+
@handler.registered_callback
|
346
|
+
end
|
347
|
+
|
348
|
+
def subscribed_topics
|
349
|
+
@subscriber.subscribed_topics
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
private
|
354
|
+
|
355
|
+
def next_packet_id
|
356
|
+
@id_mutex.synchronize do
|
357
|
+
@last_packet_id = (@last_packet_id || 0).next
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def downgrade_version
|
362
|
+
PahoMqtt.logger.debug("Connection refused: unacceptable protocol version #{@mqtt_version}, trying 3.1") if PahoMqtt.logger?
|
363
|
+
if @mqtt_version != "3.1"
|
364
|
+
@mqtt_version = "3.1"
|
365
|
+
connect(@host, @port, @keep_alive)
|
366
|
+
else
|
367
|
+
raise ProtocolVersionException.new("Unsupported MQTT version")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def build_pubsub
|
372
|
+
if @subscriber.nil?
|
373
|
+
@subscriber = Subscriber.new(@sender)
|
374
|
+
else
|
375
|
+
@subscriber.sender = @sender
|
376
|
+
@subscriber.config_subscription(next_packet_id)
|
377
|
+
end
|
378
|
+
if @publisher.nil?
|
379
|
+
@publisher = Publisher.new(@sender)
|
380
|
+
else
|
381
|
+
@publisher.sender = @sender
|
382
|
+
@sender.flush_waiting_packet
|
383
|
+
@publisher.config_all_message_queue
|
384
|
+
end
|
385
|
+
@handler.config_pubsub(@publisher, @subscriber)
|
386
|
+
end
|
387
|
+
|
388
|
+
def init_connection
|
389
|
+
unless reconnect?
|
390
|
+
@connection_helper = ConnectionHelper.new(@host, @port, @ssl, @ssl_context, @ack_timeout)
|
391
|
+
@connection_helper.handler = @handler
|
392
|
+
@sender = @connection_helper.sender
|
393
|
+
end
|
394
|
+
@connection_helper.setup_connection
|
395
|
+
end
|
396
|
+
|
397
|
+
def session_params
|
398
|
+
{
|
399
|
+
:version => @mqtt_version,
|
400
|
+
:clean_session => @clean_session,
|
401
|
+
:keep_alive => @keep_alive,
|
402
|
+
:client_id => @client_id,
|
403
|
+
:username => @username,
|
404
|
+
:password => @password,
|
405
|
+
:will_topic => @will_topic,
|
406
|
+
:will_payload => @will_payload,
|
407
|
+
:will_qos => @will_qos,
|
408
|
+
:will_retain => @will_retain
|
409
|
+
}
|
410
|
+
end
|
411
|
+
|
412
|
+
def check_persistence
|
413
|
+
disconnect(false)
|
414
|
+
@persistent
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
2
|
+
#
|
3
|
+
# All rights reserved. This program and the accompanying materials
|
4
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
5
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
6
|
+
#
|
7
|
+
# The Eclipse Public License is available at
|
8
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
9
|
+
# and the Eclipse Distribution License is available at
|
10
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
11
|
+
#
|
12
|
+
# Contributors:
|
13
|
+
# Pierre Goudet - initial committer
|
14
|
+
|
15
|
+
require 'socket'
|
16
|
+
|
17
|
+
module PahoMqtt
|
18
|
+
class ConnectionHelper
|
19
|
+
|
20
|
+
attr_accessor :sender
|
21
|
+
|
22
|
+
def initialize(host, port, ssl, ssl_context, ack_timeout)
|
23
|
+
@cs = MQTT_CS_DISCONNECT
|
24
|
+
@socket = nil
|
25
|
+
@host = host
|
26
|
+
@port = port
|
27
|
+
@ssl = ssl
|
28
|
+
@ssl_context = ssl_context
|
29
|
+
@ack_timeout = ack_timeout
|
30
|
+
@sender = Sender.new(ack_timeout)
|
31
|
+
end
|
32
|
+
|
33
|
+
def handler=(handler)
|
34
|
+
@handler = handler
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_connect(reconnection=false)
|
38
|
+
@cs = MQTT_CS_NEW
|
39
|
+
@handler.socket = @socket
|
40
|
+
# Waiting a Connack packet for "ack_timeout" second from the remote
|
41
|
+
connect_timeout = Time.now + @ack_timeout
|
42
|
+
while (Time.now <= connect_timeout) && !is_connected? do
|
43
|
+
@cs = @handler.receive_packet
|
44
|
+
sleep 0.0001
|
45
|
+
end
|
46
|
+
unless is_connected?
|
47
|
+
PahoMqtt.logger.warn("Connection failed. Couldn't recieve a Connack packet from: #{@host}.") if PahoMqtt.logger?
|
48
|
+
raise Exception.new("Connection failed. Check log for more details.") unless reconnection
|
49
|
+
end
|
50
|
+
@cs
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_connected?
|
54
|
+
@cs == MQTT_CS_CONNECTED
|
55
|
+
end
|
56
|
+
|
57
|
+
def do_disconnect(publisher, explicit, mqtt_thread)
|
58
|
+
PahoMqtt.logger.debug("Disconnecting from #{@host}.") if PahoMqtt.logger?
|
59
|
+
if explicit
|
60
|
+
explicit_disconnect(publisher, mqtt_thread)
|
61
|
+
end
|
62
|
+
@socket.close unless @socket.nil? || @socket.closed?
|
63
|
+
@socket = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def explicit_disconnect(publisher, mqtt_thread)
|
67
|
+
@sender.flush_waiting_packet
|
68
|
+
send_disconnect
|
69
|
+
mqtt_thread.kill if mqtt_thread && mqtt_thread.alive?
|
70
|
+
publisher.flush_publisher unless publisher.nil?
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup_connection
|
74
|
+
clean_start(@host, @port)
|
75
|
+
config_socket
|
76
|
+
unless @socket.nil?
|
77
|
+
@sender.socket = @socket
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def config_socket
|
82
|
+
PahoMqtt.logger.debug("Attempt to connect to host: #{@host}...") if PahoMqtt.logger?
|
83
|
+
begin
|
84
|
+
tcp_socket = TCPSocket.new(@host, @port)
|
85
|
+
rescue StandardError
|
86
|
+
PahoMqtt.logger.warn("Could not open a socket with #{@host} on port #{@port}.") if PahoMqtt.logger?
|
87
|
+
end
|
88
|
+
if @ssl
|
89
|
+
encrypted_socket(tcp_socket, @ssl_context)
|
90
|
+
else
|
91
|
+
@socket = tcp_socket
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def encrypted_socket(tcp_socket, ssl_context)
|
96
|
+
unless ssl_context.nil?
|
97
|
+
@socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
98
|
+
@socket.sync_close = true
|
99
|
+
@socket.connect
|
100
|
+
else
|
101
|
+
PahoMqtt.logger.error("The SSL context was found as nil while the socket's opening.") if PahoMqtt.logger?
|
102
|
+
raise Exception
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def clean_start(host, port)
|
107
|
+
self.host = host
|
108
|
+
self.port = port
|
109
|
+
unless @socket.nil?
|
110
|
+
@socket.close unless @socket.closed?
|
111
|
+
@socket = nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def host=(host)
|
116
|
+
if host.nil? || host == ""
|
117
|
+
PahoMqtt.logger.error("The host was found as nil while the connection setup.") if PahoMqtt.logger?
|
118
|
+
raise ArgumentError
|
119
|
+
else
|
120
|
+
@host = host
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def port=(port)
|
125
|
+
if port.to_i <= 0
|
126
|
+
PahoMqtt.logger.error("The port value is invalid (<= 0). Could not setup the connection.") if PahoMqtt.logger?
|
127
|
+
raise ArgumentError
|
128
|
+
else
|
129
|
+
@port = port
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def send_connect(session_params)
|
134
|
+
setup_connection
|
135
|
+
packet = PahoMqtt::Packet::Connect.new(session_params)
|
136
|
+
@handler.clean_session = session_params[:clean_session]
|
137
|
+
@sender.send_packet(packet)
|
138
|
+
MQTT_ERR_SUCCESS
|
139
|
+
end
|
140
|
+
|
141
|
+
def send_disconnect
|
142
|
+
packet = PahoMqtt::Packet::Disconnect.new
|
143
|
+
@sender.send_packet(packet)
|
144
|
+
MQTT_ERR_SUCCESS
|
145
|
+
end
|
146
|
+
|
147
|
+
def send_pingreq
|
148
|
+
packet = PahoMqtt::Packet::Pingreq.new
|
149
|
+
@sender.send_packet(packet)
|
150
|
+
MQTT_ERR_SUCCESS
|
151
|
+
end
|
152
|
+
|
153
|
+
def check_keep_alive(persistent, last_ping_resp, keep_alive)
|
154
|
+
now = Time.now
|
155
|
+
timeout_req = (@sender.last_ping_req + (keep_alive * 0.7).ceil)
|
156
|
+
if timeout_req <= now && persistent
|
157
|
+
PahoMqtt.logger.debug("Checking if server is still alive...") if PahoMqtt.logger?
|
158
|
+
send_pingreq
|
159
|
+
end
|
160
|
+
timeout_resp = last_ping_resp + (keep_alive * 1.1).ceil
|
161
|
+
#if timeout_resp <= now
|
162
|
+
if false #dirty hack to disable the ping timeout. we are using a ping to a topic every 30 secs instead of this.
|
163
|
+
PahoMqtt.logger.debug("No activity period over timeout, disconnecting from #{@host}.") if PahoMqtt.logger?
|
164
|
+
@cs = MQTT_CS_DISCONNECT
|
165
|
+
end
|
166
|
+
@cs
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright (c) 2016-2018 Pierre Goudet <p-goudet@ruby-dev.jp>
|
2
|
+
#
|
3
|
+
# All rights reserved. This program and the accompanying materials
|
4
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
5
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
6
|
+
#
|
7
|
+
# The Eclipse Public License is available at
|
8
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
9
|
+
# and the Eclipse Distribution License is available at
|
10
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
11
|
+
#
|
12
|
+
# Contributors:
|
13
|
+
# Pierre Goudet - initial committer
|
14
|
+
|
15
|
+
|
16
|
+
module PahoMqtt
|
17
|
+
class Exception < ::StandardError
|
18
|
+
def initialize(msg="")
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ProtocolViolation < Exception
|
24
|
+
end
|
25
|
+
|
26
|
+
class WritingException < Exception
|
27
|
+
end
|
28
|
+
|
29
|
+
class ReadingException < Exception
|
30
|
+
end
|
31
|
+
|
32
|
+
class PacketException < Exception
|
33
|
+
end
|
34
|
+
|
35
|
+
class PacketFormatException < Exception
|
36
|
+
end
|
37
|
+
|
38
|
+
class ProtocolVersionException < Exception
|
39
|
+
end
|
40
|
+
|
41
|
+
class LowVersionException < Exception
|
42
|
+
end
|
43
|
+
end
|