paho-mqtt 1.0.0 → 1.0.1
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/lib/paho-mqtt.rb +72 -1
- data/lib/paho_mqtt/client.rb +182 -708
- data/lib/paho_mqtt/connection_helper.rb +167 -0
- data/lib/paho_mqtt/handler.rb +271 -0
- data/lib/paho_mqtt/packet.rb +14 -0
- data/lib/paho_mqtt/packet/base.rb +17 -0
- data/lib/paho_mqtt/packet/connack.rb +19 -3
- data/lib/paho_mqtt/packet/connect.rb +50 -21
- data/lib/paho_mqtt/packet/disconnect.rb +18 -1
- data/lib/paho_mqtt/packet/pingreq.rb +17 -0
- data/lib/paho_mqtt/packet/pingresp.rb +17 -0
- data/lib/paho_mqtt/packet/puback.rb +17 -1
- data/lib/paho_mqtt/packet/pubcomp.rb +17 -0
- data/lib/paho_mqtt/packet/publish.rb +17 -0
- data/lib/paho_mqtt/packet/pubrec.rb +17 -0
- data/lib/paho_mqtt/packet/pubrel.rb +17 -0
- data/lib/paho_mqtt/packet/suback.rb +17 -0
- data/lib/paho_mqtt/packet/subscribe.rb +17 -0
- data/lib/paho_mqtt/packet/unsuback.rb +17 -0
- data/lib/paho_mqtt/packet/unsubscribe.rb +17 -0
- data/lib/paho_mqtt/publisher.rb +180 -0
- data/lib/paho_mqtt/sender.rb +90 -0
- data/lib/paho_mqtt/ssl_helper.rb +42 -0
- data/lib/paho_mqtt/subscriber.rb +195 -0
- data/lib/paho_mqtt/version.rb +1 -1
- metadata +8 -3
- data/LICENSE.txt +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81783208a50d429eede136e757bddf982ed2fd83
|
4
|
+
data.tar.gz: 4d1c34982623e35713e8af79da00cc6bf14d91eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02f36654df8e3f0ae3a3e47f64708ca0f770076766c7e593755d8d55dc14950e40b1eab91631f4aab7815e83653f83e2ca05dd02f8565820a3d2b089a2652cee
|
7
|
+
data.tar.gz: 50456a5604f7318622cd1809b8859db2845c7c5a0b7b4bae15d09333d957248c40cced139c7c54ac6efff9efda6985aad4c84b50de33880491ad4a369a247ff4
|
data/lib/paho-mqtt.rb
CHANGED
@@ -1,8 +1,27 @@
|
|
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
|
+
|
1
15
|
require "paho_mqtt/version"
|
2
16
|
require "paho_mqtt/client"
|
3
17
|
require "paho_mqtt/packet"
|
18
|
+
require 'logger'
|
4
19
|
|
5
20
|
module PahoMqtt
|
21
|
+
extend self
|
22
|
+
|
23
|
+
attr_accessor :logger
|
24
|
+
|
6
25
|
# Default connection setup
|
7
26
|
DEFAULT_SSL_PORT = 8883
|
8
27
|
DEFAULT_PORT = 1883
|
@@ -47,15 +66,67 @@ module PahoMqtt
|
|
47
66
|
nil
|
48
67
|
]
|
49
68
|
|
69
|
+
CONNACK_ERROR_MESSAGE = {
|
70
|
+
0x02 => "Client Identifier is correct but not allowed by remote server.",
|
71
|
+
0x03 => "Connection established but MQTT service unvailable on remote server.",
|
72
|
+
0x04 => "User name or user password is malformed.",
|
73
|
+
0x05 => "Client is not authorized to connect to the server."
|
74
|
+
}
|
75
|
+
|
76
|
+
CLIENT_ATTR_DEFAULTS = {
|
77
|
+
:host => "",
|
78
|
+
:port => nil,
|
79
|
+
:mqtt_version => '3.1.1',
|
80
|
+
:clean_session => true,
|
81
|
+
:persistent => false,
|
82
|
+
:blocking => false,
|
83
|
+
:client_id => nil,
|
84
|
+
:username => nil,
|
85
|
+
:password => nil,
|
86
|
+
:ssl => false,
|
87
|
+
:will_topic => nil,
|
88
|
+
:will_payload => nil,
|
89
|
+
:will_qos => 0,
|
90
|
+
:will_retain => false,
|
91
|
+
:keep_alive => 60,
|
92
|
+
:ack_timeout => 5,
|
93
|
+
:on_connack => nil,
|
94
|
+
:on_suback => nil,
|
95
|
+
:on_unsuback => nil,
|
96
|
+
:on_puback => nil,
|
97
|
+
:on_pubrel => nil,
|
98
|
+
:on_pubrec => nil,
|
99
|
+
:on_pubcomp => nil,
|
100
|
+
:on_message => nil,
|
101
|
+
}
|
102
|
+
|
50
103
|
Thread.abort_on_exception = true
|
51
104
|
|
105
|
+
def logger=(logger_path)
|
106
|
+
file = File.open(logger_path, "a+")
|
107
|
+
log_file = Logger.new(file)
|
108
|
+
log_file.level = Logger::DEBUG
|
109
|
+
@action_manager.logger = log_file
|
110
|
+
end
|
111
|
+
|
112
|
+
def logger
|
113
|
+
@logger
|
114
|
+
end
|
115
|
+
|
116
|
+
def logger?
|
117
|
+
@logger.is_a?(Logger)
|
118
|
+
end
|
119
|
+
|
52
120
|
class Exception < ::Exception
|
53
121
|
end
|
54
122
|
|
55
123
|
class ProtocolViolation < PahoMqtt::Exception
|
56
124
|
end
|
57
125
|
|
58
|
-
class
|
126
|
+
class WritingException < PahoMqtt::Exception
|
127
|
+
end
|
128
|
+
|
129
|
+
class ReadingException < PahoMqtt::Exception
|
59
130
|
end
|
60
131
|
|
61
132
|
class PacketException < PahoMqtt::Exception
|
data/lib/paho_mqtt/client.rb
CHANGED
@@ -1,12 +1,26 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
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'
|
4
21
|
|
5
22
|
module PahoMqtt
|
6
|
-
class Client
|
7
|
-
# Log file
|
8
|
-
attr_accessor :logger
|
9
|
-
|
23
|
+
class Client
|
10
24
|
# Connection related attributes:
|
11
25
|
attr_accessor :host
|
12
26
|
attr_accessor :port
|
@@ -18,7 +32,7 @@ module PahoMqtt
|
|
18
32
|
attr_accessor :username
|
19
33
|
attr_accessor :password
|
20
34
|
attr_accessor :ssl
|
21
|
-
|
35
|
+
|
22
36
|
# Last will attributes:
|
23
37
|
attr_accessor :will_topic
|
24
38
|
attr_accessor :will_payload
|
@@ -29,100 +43,45 @@ module PahoMqtt
|
|
29
43
|
attr_accessor :keep_alive
|
30
44
|
attr_accessor :ack_timeout
|
31
45
|
|
32
|
-
#Callback attributes
|
33
|
-
attr_accessor :on_message
|
34
|
-
attr_accessor :on_connack
|
35
|
-
attr_accessor :on_suback
|
36
|
-
attr_accessor :on_unsuback
|
37
|
-
attr_accessor :on_puback
|
38
|
-
attr_accessor :on_pubrel
|
39
|
-
attr_accessor :on_pubrec
|
40
|
-
attr_accessor :on_pubcomp
|
41
|
-
|
42
46
|
#Read Only attribute
|
43
|
-
attr_reader :registered_callback
|
44
|
-
attr_reader :subscribed_topics
|
45
47
|
attr_reader :connection_state
|
48
|
+
attr_reader :ssl_context
|
46
49
|
|
47
|
-
ATTR_DEFAULTS = {
|
48
|
-
:logger => nil,
|
49
|
-
:host => "",
|
50
|
-
:port => nil,
|
51
|
-
:mqtt_version => '3.1.1',
|
52
|
-
:clean_session => true,
|
53
|
-
:persistent => false,
|
54
|
-
:blocking => false,
|
55
|
-
:client_id => nil,
|
56
|
-
:username => nil,
|
57
|
-
:password => nil,
|
58
|
-
:ssl => false,
|
59
|
-
:will_topic => nil,
|
60
|
-
:will_payload => nil,
|
61
|
-
:will_qos => 0,
|
62
|
-
:will_retain => false,
|
63
|
-
:keep_alive => 60,
|
64
|
-
:ack_timeout => 5,
|
65
|
-
:on_connack => nil,
|
66
|
-
:on_suback => nil,
|
67
|
-
:on_unsuback => nil,
|
68
|
-
:on_puback => nil,
|
69
|
-
:on_pubrel => nil,
|
70
|
-
:on_pubrec => nil,
|
71
|
-
:on_pubcomp => nil,
|
72
|
-
:on_message => nil,
|
73
|
-
}
|
74
|
-
|
75
50
|
def initialize(*args)
|
51
|
+
@last_ping_resp = Time.now
|
52
|
+
@last_packet_id = 0
|
53
|
+
@ssl_context = nil
|
54
|
+
@sender = nil
|
55
|
+
@handler = Handler.new
|
56
|
+
@connection_helper = nil
|
57
|
+
@connection_state = MQTT_CS_DISCONNECT
|
58
|
+
@connection_state_mutex = Mutex.new
|
59
|
+
@mqtt_thread = nil
|
60
|
+
@reconnect_thread = nil
|
61
|
+
@id_mutex = Mutex.new
|
62
|
+
|
76
63
|
if args.last.is_a?(Hash)
|
77
64
|
attr = args.pop
|
78
65
|
else
|
79
66
|
attr = {}
|
80
67
|
end
|
81
68
|
|
82
|
-
|
69
|
+
CLIENT_ATTR_DEFAULTS.merge(attr).each_pair do |k,v|
|
83
70
|
self.send("#{k}=", v)
|
84
71
|
end
|
85
72
|
|
86
73
|
if @port.nil?
|
87
74
|
@port
|
88
75
|
if @ssl
|
89
|
-
@port =
|
76
|
+
@port = DEFAULT_SSL_PORT
|
90
77
|
else
|
91
|
-
@port =
|
78
|
+
@port = DEFAULT_PORT
|
92
79
|
end
|
93
80
|
end
|
94
81
|
|
95
82
|
if @client_id.nil? || @client_id == ""
|
96
83
|
@client_id = generate_client_id
|
97
84
|
end
|
98
|
-
|
99
|
-
@last_ping_req = Time.now
|
100
|
-
@last_ping_resp = Time.now
|
101
|
-
@last_packet_id = 0
|
102
|
-
@socket = nil
|
103
|
-
@ssl_context = nil
|
104
|
-
@writing_mutex = Mutex.new
|
105
|
-
@writing_queue = []
|
106
|
-
@connection_state = MQTT_CS_DISCONNECT
|
107
|
-
@connection_state_mutex = Mutex.new
|
108
|
-
@subscribed_mutex = Mutex.new
|
109
|
-
@subscribed_topics = []
|
110
|
-
@registered_callback = []
|
111
|
-
@waiting_suback = []
|
112
|
-
@suback_mutex = Mutex.new
|
113
|
-
@waiting_unsuback = []
|
114
|
-
@unsuback_mutex = Mutex.new
|
115
|
-
@mqtt_thread = nil
|
116
|
-
@reconnect_thread = nil
|
117
|
-
|
118
|
-
@puback_mutex = Mutex.new
|
119
|
-
@pubrec_mutex = Mutex.new
|
120
|
-
@pubrel_mutex = Mutex.new
|
121
|
-
@pubcomp_mutex = Mutex.new
|
122
|
-
@waiting_puback = []
|
123
|
-
@waiting_pubrec = []
|
124
|
-
@waiting_pubrel = []
|
125
|
-
@waiting_pubcomp = []
|
126
85
|
end
|
127
86
|
|
128
87
|
def generate_client_id(prefix='paho_ruby', lenght=16)
|
@@ -130,25 +89,11 @@ module PahoMqtt
|
|
130
89
|
@client_id = prefix << Array.new(lenght) { charset.sample }.join
|
131
90
|
end
|
132
91
|
|
133
|
-
def ssl_context
|
134
|
-
@ssl_context ||= OpenSSL::SSL::SSLContext.new
|
135
|
-
end
|
136
|
-
|
137
92
|
def config_ssl_context(cert_path, key_path, ca_path=nil)
|
138
93
|
@ssl ||= true
|
139
|
-
@ssl_context =
|
140
|
-
self.cert = cert_path
|
141
|
-
self.key = key_path
|
142
|
-
self.root_ca = ca_path
|
94
|
+
@ssl_context = SSLHelper.config_ssl_context(cert_path, key_path, ca_path)
|
143
95
|
end
|
144
96
|
|
145
|
-
def config_will(topic, payload="", retain=false, qos=0)
|
146
|
-
@will_topic = topic
|
147
|
-
@will_payload = payload
|
148
|
-
@will_retain = retain
|
149
|
-
@will_qos = qos
|
150
|
-
end
|
151
|
-
|
152
97
|
def connect(host=@host, port=@port, keep_alive=@keep_alive, persistent=@persistent, blocking=@blocking)
|
153
98
|
@persistent = persistent
|
154
99
|
@blocking = blocking
|
@@ -158,11 +103,19 @@ module PahoMqtt
|
|
158
103
|
@connection_state_mutex.synchronize {
|
159
104
|
@connection_state = MQTT_CS_NEW
|
160
105
|
}
|
161
|
-
|
162
|
-
|
106
|
+
@mqtt_thread.kill unless @mqtt_thread.nil?
|
107
|
+
init_connection
|
108
|
+
@connection_helper.send_connect(session_params)
|
109
|
+
begin
|
110
|
+
@connection_state = @connection_helper.do_connect(reconnect?)
|
111
|
+
rescue LowVersionException
|
112
|
+
downgrade_version
|
113
|
+
end
|
114
|
+
build_pubsub
|
115
|
+
daemon_mode unless @blocking || !connected?
|
163
116
|
end
|
164
117
|
|
165
|
-
def
|
118
|
+
def daemon_mode
|
166
119
|
@mqtt_thread = Thread.new do
|
167
120
|
@reconnect_thread.kill unless @reconnect_thread.nil? || !@reconnect_thread.alive?
|
168
121
|
while connected? do
|
@@ -174,20 +127,34 @@ module PahoMqtt
|
|
174
127
|
def connected?
|
175
128
|
@connection_state == MQTT_CS_CONNECTED
|
176
129
|
end
|
177
|
-
|
130
|
+
|
131
|
+
def reconnect?
|
132
|
+
Thread.current == @reconnect_thread
|
133
|
+
end
|
134
|
+
|
178
135
|
def loop_write(max_packet=MAX_WRITING)
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
136
|
+
begin
|
137
|
+
@sender.writing_loop(max_packet)
|
138
|
+
rescue WritingException
|
139
|
+
if check_persistence
|
140
|
+
reconnect
|
141
|
+
else
|
142
|
+
raise WritingException
|
184
143
|
end
|
185
|
-
|
144
|
+
end
|
186
145
|
end
|
187
146
|
|
188
147
|
def loop_read(max_packet=MAX_READ)
|
189
148
|
max_packet.times do
|
190
|
-
|
149
|
+
begin
|
150
|
+
@handler.receive_packet
|
151
|
+
rescue ReadingException
|
152
|
+
if check_persistence
|
153
|
+
reconnect
|
154
|
+
else
|
155
|
+
raise ReadingException
|
156
|
+
end
|
157
|
+
end
|
191
158
|
end
|
192
159
|
end
|
193
160
|
|
@@ -199,19 +166,17 @@ module PahoMqtt
|
|
199
166
|
end
|
200
167
|
|
201
168
|
def loop_misc
|
202
|
-
check_keep_alive
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
check_ack_alive(@waiting_suback, @suback_mutex, @waiting_suback.length)
|
208
|
-
check_ack_alive(@waiting_unsuback, @unsuback_mutex, @waiting_unsuback.length)
|
169
|
+
if @connection_helper.check_keep_alive(@persistent, @handler.last_ping_resp, @keep_alive) == MQTT_CS_DISCONNECT
|
170
|
+
reconnect if check_persistence
|
171
|
+
end
|
172
|
+
@publisher.check_waiting_publisher
|
173
|
+
@subscriber.check_waiting_subscriber
|
209
174
|
end
|
210
175
|
|
211
176
|
def reconnect(retry_time=RECONNECT_RETRY_TIME, retry_tempo=RECONNECT_RETRY_TEMPO)
|
212
177
|
@reconnect_thread = Thread.new do
|
213
178
|
retry_time.times do
|
214
|
-
|
179
|
+
PahoMqtt.logger.debug("New reconnect atempt...") if PahoMqtt.logger?
|
215
180
|
connect
|
216
181
|
if connected?
|
217
182
|
break
|
@@ -220,7 +185,7 @@ module PahoMqtt
|
|
220
185
|
end
|
221
186
|
end
|
222
187
|
unless connected?
|
223
|
-
|
188
|
+
PahoMqtt.logger.error("Reconnection atempt counter is over.(#{RECONNECT_RETRY_TIME} times)") if PahoMqtt.logger?
|
224
189
|
disconnect(false)
|
225
190
|
exit
|
226
191
|
end
|
@@ -228,38 +193,8 @@ module PahoMqtt
|
|
228
193
|
end
|
229
194
|
|
230
195
|
def disconnect(explicit=true)
|
231
|
-
@
|
232
|
-
|
233
|
-
if explicit
|
234
|
-
send_disconnect
|
235
|
-
@mqtt_thread.kill if @mqtt_thread && @mqtt_thread.alive?
|
236
|
-
@mqtt_thread.kill if @mqtt_thread.alive?
|
237
|
-
@last_packet_id = 0
|
238
|
-
|
239
|
-
@writing_mutex.synchronize {
|
240
|
-
@writing_queue = []
|
241
|
-
}
|
242
|
-
|
243
|
-
@puback_mutex.synchronize {
|
244
|
-
@waiting_puback = []
|
245
|
-
}
|
246
|
-
|
247
|
-
@pubrec_mutex.synchronize {
|
248
|
-
@waiting_pubrec = []
|
249
|
-
}
|
250
|
-
|
251
|
-
@pubrel_mutex.synchronize {
|
252
|
-
@waiting_pubrel = []
|
253
|
-
}
|
254
|
-
|
255
|
-
@pubcomp_mutex.synchronize {
|
256
|
-
@waiting_pubcomp = []
|
257
|
-
}
|
258
|
-
end
|
259
|
-
|
260
|
-
@socket.close unless @socket.nil? || @socket.closed?
|
261
|
-
@socket = nil
|
262
|
-
|
196
|
+
@last_packet_id = 0 if explicit
|
197
|
+
@connection_helper.do_disconnect(@publisher, explicit, @mqtt_thread)
|
263
198
|
@connection_state_mutex.synchronize {
|
264
199
|
@connection_state = MQTT_CS_DISCONNECT
|
265
200
|
}
|
@@ -268,656 +203,195 @@ module PahoMqtt
|
|
268
203
|
|
269
204
|
def publish(topic, payload="", retain=false, qos=0)
|
270
205
|
if topic == "" || !topic.is_a?(String)
|
271
|
-
|
272
|
-
raise
|
206
|
+
PahoMqtt.logger.error("Publish topics is invalid, not a string or empty.") if PahoMqtt.logger?
|
207
|
+
raise ArgumentError
|
273
208
|
end
|
274
|
-
|
209
|
+
id = next_packet_id
|
210
|
+
@publisher.send_publish(topic, payload, retain, qos, id)
|
211
|
+
MQTT_ERR_SUCCESS
|
275
212
|
end
|
276
213
|
|
277
214
|
def subscribe(*topics)
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
215
|
+
begin
|
216
|
+
id = next_packet_id
|
217
|
+
unless @subscriber.send_subscribe(topics, id) == PahoMqtt::MQTT_ERR_SUCCESS
|
218
|
+
reconnect if check_persistence
|
219
|
+
end
|
220
|
+
MQTT_ERR_SUCCESS
|
221
|
+
rescue ProtocolViolation
|
222
|
+
PahoMqtt.logger.error("Subscribe topics need one topic or a list of topics.") if PahoMqtt.logger?
|
282
223
|
disconnect(false)
|
283
224
|
raise ProtocolViolation
|
284
225
|
end
|
285
226
|
end
|
286
227
|
|
287
228
|
def unsubscribe(*topics)
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
229
|
+
begin
|
230
|
+
id = next_packet_id
|
231
|
+
unless @subscriber.send_unsubscribe(topics, id) == MQTT_ERR_SUCCESS
|
232
|
+
reconnect if check_persistence
|
233
|
+
end
|
234
|
+
MQTT_ERR_SUCCESS
|
235
|
+
rescue ProtocolViolation
|
236
|
+
PahoMqtt.logger.error("Unsubscribe need at least one topics.") if PahoMqtt.logger?
|
292
237
|
disconnect(false)
|
293
238
|
raise ProtocolViolation
|
294
239
|
end
|
295
240
|
end
|
296
241
|
|
297
242
|
def ping_host
|
298
|
-
send_pingreq
|
243
|
+
@sender.send_pingreq
|
299
244
|
end
|
300
245
|
|
301
246
|
def add_topic_callback(topic, callback=nil, &block)
|
302
|
-
|
303
|
-
@logger.error("The topics where the callback is trying to be registered have been found nil.") if @logger.is_a?(Logger)
|
304
|
-
raise ParameterException
|
305
|
-
end
|
306
|
-
remove_topic_callback(topic)
|
307
|
-
|
308
|
-
if block_given?
|
309
|
-
@registered_callback.push([topic, block])
|
310
|
-
elsif !(callback.nil?) && callback.class == Proc
|
311
|
-
@registered_callback.push([topic, callback])
|
312
|
-
end
|
313
|
-
MQTT_ERR_SUCCESS
|
247
|
+
@handler.register_topic_callback(topic, callback, &block)
|
314
248
|
end
|
315
249
|
|
316
250
|
def remove_topic_callback(topic)
|
317
|
-
|
318
|
-
@logger.error("The topics where the callback is trying to be unregistered have been found nil.") if @logger.is_a?(Logger)
|
319
|
-
raise ParameterException
|
320
|
-
end
|
321
|
-
@registered_callback.delete_if {|pair| pair.first == topic}
|
322
|
-
MQTT_ERR_SUCCESS
|
251
|
+
@handler.clear_topic_callback(topic)
|
323
252
|
end
|
324
253
|
|
325
254
|
def on_connack(&block)
|
326
|
-
@on_connack = block if block_given?
|
327
|
-
@on_connack
|
255
|
+
@handler.on_connack = block if block_given?
|
256
|
+
@handler.on_connack
|
328
257
|
end
|
329
258
|
|
330
259
|
def on_suback(&block)
|
331
|
-
@on_suback = block if block_given?
|
332
|
-
@on_suback
|
260
|
+
@handler.on_suback = block if block_given?
|
261
|
+
@handler.on_suback
|
333
262
|
end
|
334
263
|
|
335
264
|
def on_unsuback(&block)
|
336
|
-
@on_unsuback = block if block_given?
|
337
|
-
@on_unsuback
|
265
|
+
@handler.on_unsuback = block if block_given?
|
266
|
+
@handler.on_unsuback
|
338
267
|
end
|
339
268
|
|
340
269
|
def on_puback(&block)
|
341
|
-
@on_puback = block if block_given?
|
342
|
-
@on_puback
|
270
|
+
@handler.on_puback = block if block_given?
|
271
|
+
@handler.on_puback
|
343
272
|
end
|
344
273
|
|
345
274
|
def on_pubrec(&block)
|
346
|
-
@on_pubrec = block if block_given?
|
347
|
-
@on_pubrec
|
275
|
+
@handler.on_pubrec = block if block_given?
|
276
|
+
@handler.on_pubrec
|
348
277
|
end
|
349
278
|
|
350
279
|
def on_pubrel(&block)
|
351
|
-
@on_pubrel = block if block_given?
|
352
|
-
@on_pubrel
|
280
|
+
@handler.on_pubrel = block if block_given?
|
281
|
+
@handler.on_pubrel
|
353
282
|
end
|
354
283
|
|
355
284
|
def on_pubcomp(&block)
|
356
|
-
@on_pubcomp = block if block_given?
|
357
|
-
@on_pubcomp
|
285
|
+
@handler.on_pubcomp = block if block_given?
|
286
|
+
@handler.on_pubcomp
|
358
287
|
end
|
359
288
|
|
360
289
|
def on_message(&block)
|
361
|
-
@on_message = block if block_given?
|
362
|
-
@on_message
|
363
|
-
end
|
364
|
-
|
365
|
-
private
|
366
|
-
|
367
|
-
def next_packet_id
|
368
|
-
@last_packet_id = ( @last_packet_id || 0 ).next
|
369
|
-
end
|
370
|
-
|
371
|
-
def config_subscription
|
372
|
-
unless @subscribed_topics == []
|
373
|
-
new_id = next_packet_id
|
374
|
-
packet = PahoMqtt::Packet::Subscribe.new(
|
375
|
-
:id => new_id,
|
376
|
-
:topics => @subscribed_topics
|
377
|
-
)
|
378
|
-
@subscribed_mutex.synchronize {
|
379
|
-
@subscribed_topics = []
|
380
|
-
}
|
381
|
-
@suback_mutex.synchronize {
|
382
|
-
@waiting_suback.push({ :id => new_id, :packet => packet, :timestamp => Time.now })
|
383
|
-
}
|
384
|
-
send_packet(packet)
|
385
|
-
end
|
386
|
-
MQTT_ERR_SUCCESS
|
387
|
-
end
|
388
|
-
|
389
|
-
def config_all_message_queue
|
390
|
-
config_message_queue(@waiting_puback, @puback_mutex, MAX_PUBACK)
|
391
|
-
config_message_queue(@waiting_pubrec, @pubrec_mutex, MAX_PUBREC)
|
392
|
-
config_message_queue(@waiting_pubrel, @pubrel_mutex, MAX_PUBREL)
|
393
|
-
config_message_queue(@waiting_pubcomp, @pubcomp_mutex, MAX_PUBCOMP)
|
394
|
-
end
|
395
|
-
|
396
|
-
def config_message_queue(queue, mutex, max_packet)
|
397
|
-
mutex.synchronize {
|
398
|
-
cnt = 0
|
399
|
-
queue.each do |pck|
|
400
|
-
pck[:packet].dup ||= true
|
401
|
-
if cnt <= max_packet
|
402
|
-
append_to_writing(pck[:packet])
|
403
|
-
cnt += 1
|
404
|
-
end
|
405
|
-
end
|
406
|
-
}
|
407
|
-
end
|
408
|
-
|
409
|
-
def config_socket
|
410
|
-
unless @socket.nil?
|
411
|
-
@socket.close unless @socket.closed?
|
412
|
-
@socket = nil
|
413
|
-
end
|
414
|
-
|
415
|
-
unless @host.nil? || @port < 0
|
416
|
-
begin
|
417
|
-
tcp_socket = TCPSocket.new(@host, @port)
|
418
|
-
rescue ::Exception => exp
|
419
|
-
@logger.warn("Could not open a socket with #{@host} on port #{@port}") if @logger.is_a?(Logger)
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
if @ssl
|
424
|
-
unless @ssl_context.nil?
|
425
|
-
@socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, @ssl_context)
|
426
|
-
@socket.sync_close = true
|
427
|
-
@socket.connect
|
428
|
-
else
|
429
|
-
@logger.error("The ssl context was found as nil while the socket's opening.") if @logger.is_a?(Logger)
|
430
|
-
raise Exception
|
431
|
-
end
|
432
|
-
else
|
433
|
-
@socket = tcp_socket
|
434
|
-
end
|
290
|
+
@handler.on_message = block if block_given?
|
291
|
+
@handler.on_message
|
435
292
|
end
|
436
293
|
|
437
|
-
def
|
438
|
-
|
294
|
+
def on_connack=(callback)
|
295
|
+
@handler.on_connack = callback if callback.is_a?(Proc)
|
439
296
|
end
|
440
297
|
|
441
|
-
def
|
442
|
-
|
298
|
+
def on_suback=(callback)
|
299
|
+
@handler.on_suback = callback if callback.is_a?(Proc)
|
443
300
|
end
|
444
301
|
|
445
|
-
def
|
446
|
-
|
447
|
-
unless @ca_path.nil?
|
448
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
449
|
-
end
|
302
|
+
def on_unsuback=(callback)
|
303
|
+
@handler.on_unsuback = callback if callback.is_a?(Proc)
|
450
304
|
end
|
451
305
|
|
452
|
-
def
|
453
|
-
@
|
454
|
-
if @host.nil? || @host == ""
|
455
|
-
@logger.error("The host was found as nil while the connection setup.") if @logger.is_a?(Logger)
|
456
|
-
raise ParameterException
|
457
|
-
end
|
458
|
-
|
459
|
-
if @port.to_i <= 0
|
460
|
-
@logger.error("The port value is invalid (<= 0). Could not setup the connection.") if @logger.is_a?(Logger)
|
461
|
-
raise ParameterException
|
462
|
-
end
|
463
|
-
|
464
|
-
@socket.close unless @socket.nil? || @socket.closed?
|
465
|
-
@socket = nil
|
466
|
-
|
467
|
-
@last_ping_req = Time.now
|
468
|
-
@last_ping_resp = Time.now
|
469
|
-
|
470
|
-
@logger.debug("Atempt to connect to host: #{@host}") if @logger.is_a?(Logger)
|
471
|
-
config_socket
|
472
|
-
|
473
|
-
unless @socket.nil?
|
474
|
-
send_connect
|
475
|
-
|
476
|
-
# Waiting a Connack packet for "ack_timeout" second from the remote
|
477
|
-
connect_timeout = Time.now + @ack_timeout
|
478
|
-
while (Time.now <= connect_timeout) && (!connected?) do
|
479
|
-
receive_packet
|
480
|
-
sleep 0.0001
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
unless connected?
|
485
|
-
@logger.warn("Connection failed. Couldn't recieve a Connack packet from: #{@host}, socket is \"#{@socket}\".") if @logger.is_a?(Logger)
|
486
|
-
unless Thread.current == @reconnect_thread
|
487
|
-
raise Exception.new("Connection failed. Check log for more details.")
|
488
|
-
end
|
489
|
-
else
|
490
|
-
config_subscription if Thread.current == @reconnect_thread
|
491
|
-
end
|
306
|
+
def on_puback=(callback)
|
307
|
+
@handler.on_puback = callback if callback.is_a?(Proc)
|
492
308
|
end
|
493
309
|
|
494
|
-
def
|
495
|
-
|
496
|
-
now = Time.now
|
497
|
-
timeout_req = (@last_ping_req + (@keep_alive * 0.7).ceil)
|
498
|
-
|
499
|
-
if timeout_req <= now && @persistent
|
500
|
-
send_pingreq
|
501
|
-
@last_ping_req = now
|
502
|
-
end
|
503
|
-
|
504
|
-
timeout_resp = @last_ping_resp + (@keep_alive * 1.1).ceil
|
505
|
-
if timeout_resp <= now
|
506
|
-
@logger.debug("No activity period over timeout, disconnecting from #{@host}") if @logger.is_a?(Logger)
|
507
|
-
disconnect(false)
|
508
|
-
reconnect if @persistent
|
509
|
-
end
|
510
|
-
end
|
310
|
+
def on_pubrec=(callback)
|
311
|
+
@handler.on_pubrec = callback if callback.is_a?(Proc)
|
511
312
|
end
|
512
313
|
|
513
|
-
def
|
514
|
-
|
515
|
-
now = Time.now
|
516
|
-
cnt = 0
|
517
|
-
queue.each do |pck|
|
518
|
-
if now >= pck[:timestamp] + @ack_timeout
|
519
|
-
pck[:packet].dup ||= true unless pck[:packet].class == PahoMqtt::Packet::Subscribe || pck[:packet].class == PahoMqtt::Packet::Unsubscribe
|
520
|
-
unless cnt > max_packet
|
521
|
-
append_to_writing(pck[:packet])
|
522
|
-
pck[:timestamp] = now
|
523
|
-
cnt += 1
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
527
|
-
}
|
314
|
+
def on_pubrel=(callback)
|
315
|
+
@handler.on_pubrel = callback if callback.is_a?(Proc)
|
528
316
|
end
|
529
317
|
|
530
|
-
def
|
531
|
-
|
532
|
-
result = IO.select([@socket], [], [], SELECT_TIMEOUT) unless @socket.nil? || @socket.closed?
|
533
|
-
unless result.nil?
|
534
|
-
packet = PahoMqtt::Packet::Base.read(@socket)
|
535
|
-
unless packet.nil?
|
536
|
-
handle_packet packet
|
537
|
-
@last_ping_resp = Time.now
|
538
|
-
end
|
539
|
-
end
|
540
|
-
rescue ::Exception => exp
|
541
|
-
disconnect(false)
|
542
|
-
if @persistent
|
543
|
-
reconnect
|
544
|
-
else
|
545
|
-
@logger.error("The packet reading have failed.") if @logger.is_a?(Logger)
|
546
|
-
raise(exp)
|
547
|
-
end
|
548
|
-
end
|
318
|
+
def on_pubcomp=(callback)
|
319
|
+
@handler.on_pubcomp = callback if callback.is_a?(Proc)
|
549
320
|
end
|
550
321
|
|
551
|
-
def
|
552
|
-
@
|
553
|
-
if packet.class == PahoMqtt::Packet::Connack
|
554
|
-
handle_connack(packet)
|
555
|
-
elsif packet.class == PahoMqtt::Packet::Suback
|
556
|
-
handle_suback(packet)
|
557
|
-
elsif packet.class == PahoMqtt::Packet::Unsuback
|
558
|
-
handle_unsuback(packet)
|
559
|
-
elsif packet.class == PahoMqtt::Packet::Publish
|
560
|
-
handle_publish(packet)
|
561
|
-
elsif packet.class == PahoMqtt::Packet::Puback
|
562
|
-
handle_puback(packet)
|
563
|
-
elsif packet.class == PahoMqtt::Packet::Pubrec
|
564
|
-
handle_pubrec(packet)
|
565
|
-
elsif packet.class == PahoMqtt::Packet::Pubrel
|
566
|
-
handle_pubrel(packet)
|
567
|
-
elsif packet.class == PahoMqtt::Packet::Pubcomp
|
568
|
-
handle_pubcomp(packet)
|
569
|
-
elsif packet.class == PahoMqtt::Packet::Pingresp
|
570
|
-
handle_pingresp
|
571
|
-
else
|
572
|
-
@logger.error("The packets header is invalid for packet: #{packet}") if @logger.is_a?(Logger)
|
573
|
-
raise PacketException
|
574
|
-
end
|
322
|
+
def on_message=(callback)
|
323
|
+
@handler.on_message = callback if callback.is_a?(Proc)
|
575
324
|
end
|
576
325
|
|
577
|
-
def
|
578
|
-
|
579
|
-
@logger.debug("Connack receive and connection accepted.") if @logger.is_a?(Logger)
|
580
|
-
if @clean_session && !packet.session_present
|
581
|
-
@logger.debug("New session created for the client") if @logger.is_a?(Logger)
|
582
|
-
elsif !@clean_session && !packet.session_present
|
583
|
-
@logger.debug("No previous session found by server, starting a new one.") if @logger.is_a?(Logger)
|
584
|
-
elsif !@clean_session && packet.session_present
|
585
|
-
@logger.debug("Previous session restored by the server.") if @logger.is_a?(Logger)
|
586
|
-
end
|
587
|
-
@connection_state_mutex.synchronize{
|
588
|
-
@connection_state = MQTT_CS_CONNECTED
|
589
|
-
}
|
590
|
-
else
|
591
|
-
disconnect(false)
|
592
|
-
handle_connack_error(packet.return_code)
|
593
|
-
end
|
594
|
-
config_all_message_queue
|
595
|
-
@writing_mutex.synchronize {
|
596
|
-
@writing_queue.each do |m|
|
597
|
-
send_packet(m)
|
598
|
-
end
|
599
|
-
}
|
600
|
-
@on_connack.call(packet) unless @on_connack.nil?
|
326
|
+
def registered_callback
|
327
|
+
@handler.registered_callback
|
601
328
|
end
|
602
329
|
|
603
|
-
def
|
604
|
-
@
|
330
|
+
def subscribed_topics
|
331
|
+
@subscriber.subscribed_topics
|
605
332
|
end
|
606
333
|
|
607
|
-
def handle_suback(packet)
|
608
|
-
adjust_qos = []
|
609
|
-
max_qos = packet.return_codes
|
610
|
-
@suback_mutex.synchronize {
|
611
|
-
adjust_qos, @waiting_suback = @waiting_suback.partition { |pck| pck[:id] == packet.id }
|
612
|
-
}
|
613
|
-
if adjust_qos.length == 1
|
614
|
-
adjust_qos = adjust_qos.first[:packet].topics
|
615
|
-
adjust_qos.each do |t|
|
616
|
-
if [0, 1, 2].include?(max_qos[0])
|
617
|
-
t[1] = max_qos.shift
|
618
|
-
elsif max_qos[0] == 128
|
619
|
-
adjust_qos.delete(t)
|
620
|
-
else
|
621
|
-
@logger.error("The qos value is invalid in subscribe.") if @logger.is_a?(Logger)
|
622
|
-
raise PacketException
|
623
|
-
end
|
624
|
-
end
|
625
|
-
else
|
626
|
-
@logger.error("The packet id is invalid, already used.") if @logger.is_a?(Logger)
|
627
|
-
raise PacketException
|
628
|
-
end
|
629
|
-
@subscribed_mutex.synchronize {
|
630
|
-
@subscribed_topics.concat(adjust_qos)
|
631
|
-
}
|
632
|
-
@on_suback.call(adjust_qos) unless @on_suback.nil?
|
633
|
-
end
|
634
334
|
|
635
|
-
|
636
|
-
to_unsub = nil
|
637
|
-
@unsuback_mutex.synchronize {
|
638
|
-
to_unsub, @waiting_unsuback = @waiting_unsuback.partition { |pck| pck[:id] == packet.id }
|
639
|
-
}
|
640
|
-
|
641
|
-
if to_unsub.length == 1
|
642
|
-
to_unsub = to_unsub.first[:packet].topics
|
643
|
-
else
|
644
|
-
@logger.error("The packet id is invalid, already used.") if @logger.is_a?(Logger)
|
645
|
-
raise PacketException
|
646
|
-
end
|
335
|
+
private
|
647
336
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
end
|
337
|
+
def next_packet_id
|
338
|
+
@id_mutex.synchronize {
|
339
|
+
@last_packet_id = ( @last_packet_id || 0 ).next
|
652
340
|
}
|
653
|
-
@on_unsuback.call(to_unsub) unless @on_unsuback.nil?
|
654
341
|
end
|
655
342
|
|
656
|
-
def
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
when 2
|
662
|
-
send_pubrec(packet.id)
|
343
|
+
def downgrade_version
|
344
|
+
PahoMqtt.logger.debug("Unable to connect to the server with the version #{@mqtt_version}, trying 3.1") if PahoMqtt.logger?
|
345
|
+
if @mqtt_version != "3.1"
|
346
|
+
@mqtt_version = "3.1"
|
347
|
+
connect(@host, @port, @keep_alive)
|
663
348
|
else
|
664
|
-
|
665
|
-
raise PacketException
|
349
|
+
raise "Unsupported MQTT version"
|
666
350
|
end
|
667
|
-
|
668
|
-
@on_message.call(packet) unless @on_message.nil?
|
669
|
-
@registered_callback.assoc(packet.topic).last.call(packet) if @registered_callback.any? { |pair| pair.first == packet.topic}
|
670
|
-
end
|
671
|
-
|
672
|
-
def handle_puback(packet)
|
673
|
-
@puback_mutex.synchronize{
|
674
|
-
@waiting_puback.delete_if { |pck| pck[:id] == packet.id }
|
675
|
-
}
|
676
|
-
@on_puback.call(packet) unless @on_puback.nil?
|
677
|
-
end
|
678
|
-
|
679
|
-
def handle_pubrec(packet)
|
680
|
-
@pubrec_mutex.synchronize {
|
681
|
-
@waiting_pubrec.delete_if { |pck| pck[:id] == packet.id }
|
682
|
-
}
|
683
|
-
send_pubrel(packet.id)
|
684
|
-
@on_pubrec.call(packet) unless @on_pubrec.nil?
|
685
351
|
end
|
686
352
|
|
687
|
-
def
|
688
|
-
@
|
689
|
-
@
|
690
|
-
}
|
691
|
-
send_pubcomp(packet.id)
|
692
|
-
@on_pubrel.call(packet) unless @on_pubrel.nil?
|
693
|
-
end
|
694
|
-
|
695
|
-
def handle_pubcomp(packet)
|
696
|
-
@pubcomp_mutex.synchronize {
|
697
|
-
@waiting_pubcomp.delete_if { |pck| pck[:id] == packet.id }
|
698
|
-
}
|
699
|
-
@on_pubcomp.call(packet) unless @on_pubcomp.nil?
|
700
|
-
end
|
701
|
-
|
702
|
-
def handle_connack_error(return_code)
|
703
|
-
case return_code
|
704
|
-
when 0x01
|
705
|
-
@logger.debug("Unable to connect to the server with the version #{@mqtt_version}, trying 3.1") if @logger.is_a?(Logger)
|
706
|
-
if @mqtt_version != "3.1"
|
707
|
-
@mqtt_version = "3.1"
|
708
|
-
connect(@host, @port, @keep_alive)
|
709
|
-
end
|
710
|
-
when 0x02
|
711
|
-
@logger.warn("Client Identifier is correct but not allowed by remote server.") if @logger.is_a?(Logger)
|
712
|
-
MQTT_ERR_FAIL
|
713
|
-
when 0x03
|
714
|
-
@logger.warn("Connection established but MQTT service unvailable on remote server.") if @logger.is_a?(Logger)
|
715
|
-
MQTT_ERR_FAIL
|
716
|
-
when 0x04
|
717
|
-
@logger.warn("User name or user password is malformed.") if @logger.is_a?(Logger)
|
718
|
-
MQTT_ERR_FAIL
|
719
|
-
when 0x05
|
720
|
-
@logger.warn("Client is not authorized to connect to the server.") if @logger.is_a?(Logger)
|
721
|
-
MQTT_ERR_FAIL
|
722
|
-
end
|
723
|
-
end
|
724
|
-
|
725
|
-
def send_packet(packet)
|
726
|
-
begin
|
727
|
-
@socket.write(packet.to_s) unless @socket.nil? || @socket.closed?
|
728
|
-
@logger.info("A packet #{packet.class} have been sent.") if @logger.is_a?(Logger)
|
729
|
-
@last_ping_req = Time.now
|
730
|
-
MQTT_ERR_SUCCESS
|
731
|
-
rescue ::Exception => exp
|
732
|
-
disconnect(false)
|
733
|
-
if @persistent
|
734
|
-
reconnect
|
735
|
-
else
|
736
|
-
@logger.error("Trying to right a packet on a nil socket.") if @logger.is_a?(Logger)
|
737
|
-
raise(exp)
|
738
|
-
end
|
739
|
-
end
|
740
|
-
end
|
741
|
-
|
742
|
-
def append_to_writing(packet)
|
743
|
-
@writing_mutex.synchronize {
|
744
|
-
@writing_queue.push(packet)
|
745
|
-
}
|
746
|
-
MQTT_ERR_SUCCESS
|
747
|
-
end
|
748
|
-
|
749
|
-
def send_connect
|
750
|
-
packet = PahoMqtt::Packet::Connect.new(
|
751
|
-
:version => @mqtt_version,
|
752
|
-
:clean_session => @clean_session,
|
753
|
-
:keep_alive => @keep_alive,
|
754
|
-
:client_id => @client_id,
|
755
|
-
:username => @username,
|
756
|
-
:password => @password,
|
757
|
-
:will_topic => @will_topic,
|
758
|
-
:will_payload => @will_payload,
|
759
|
-
:will_qos => @will_qos,
|
760
|
-
:will_retain => @will_retain
|
761
|
-
)
|
762
|
-
send_packet(packet)
|
763
|
-
MQTT_ERR_SUCCESS
|
764
|
-
end
|
765
|
-
|
766
|
-
def send_disconnect
|
767
|
-
packet = PahoMqtt::Packet::Disconnect.new
|
768
|
-
send_packet(packet)
|
769
|
-
MQTT_ERR_SUCCESS
|
770
|
-
end
|
771
|
-
|
772
|
-
def send_pingreq
|
773
|
-
packet = PahoMqtt::Packet::Pingreq.new
|
774
|
-
@logger.debug("Checking if server is still alive.") if @logger.is_a?(Logger)
|
775
|
-
send_packet(packet)
|
776
|
-
MQTT_ERR_SUCCESS
|
777
|
-
end
|
778
|
-
|
779
|
-
def send_subscribe(topics)
|
780
|
-
unless valid_topics?(topics) == MQTT_ERR_FAIL
|
781
|
-
new_id = next_packet_id
|
782
|
-
packet = PahoMqtt::Packet::Subscribe.new(
|
783
|
-
:id => new_id,
|
784
|
-
:topics => topics
|
785
|
-
)
|
786
|
-
append_to_writing(packet)
|
787
|
-
@suback_mutex.synchronize {
|
788
|
-
@waiting_suback.push({ :id => new_id, :packet => packet, :timestamp => Time.now })
|
789
|
-
}
|
790
|
-
MQTT_ERR_SUCCESS
|
353
|
+
def build_pubsub
|
354
|
+
if @subscriber.nil?
|
355
|
+
@subscriber = Subscriber.new(@sender)
|
791
356
|
else
|
792
|
-
|
793
|
-
|
357
|
+
@subscriber.sender = @sender
|
358
|
+
@subscriber.config_subscription(next_packet_id)
|
794
359
|
end
|
795
|
-
|
796
|
-
|
797
|
-
def send_unsubscribe(topics)
|
798
|
-
unless valid_topics?(topics) == MQTT_ERR_FAIL
|
799
|
-
new_id = next_packet_id
|
800
|
-
packet = PahoMqtt::Packet::Unsubscribe.new(
|
801
|
-
:id => new_id,
|
802
|
-
:topics => topics
|
803
|
-
)
|
804
|
-
|
805
|
-
append_to_writing(packet)
|
806
|
-
@unsuback_mutex.synchronize {
|
807
|
-
@waiting_unsuback.push({:id => new_id, :packet => packet, :timestamp => Time.now})
|
808
|
-
}
|
809
|
-
MQTT_ERR_SUCCESS
|
360
|
+
if @publisher.nil?
|
361
|
+
@publisher = Publisher.new(@sender)
|
810
362
|
else
|
811
|
-
|
812
|
-
|
363
|
+
@publisher.sender = @sender
|
364
|
+
@publisher.config_all_message_queue
|
813
365
|
end
|
366
|
+
@handler.config_pubsub(@publisher, @subscriber)
|
367
|
+
@sender.flush_waiting_packet(true)
|
814
368
|
end
|
815
369
|
|
816
|
-
def
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
:payload => payload,
|
822
|
-
:retain => retain,
|
823
|
-
:qos => qos
|
824
|
-
)
|
825
|
-
|
826
|
-
append_to_writing(packet)
|
827
|
-
|
828
|
-
case qos
|
829
|
-
when 1
|
830
|
-
@puback_mutex.synchronize{
|
831
|
-
@waiting_puback.push({:id => new_id, :packet => packet, :timestamp => Time.now})
|
832
|
-
}
|
833
|
-
when 2
|
834
|
-
@pubrec_mutex.synchronize{
|
835
|
-
@waiting_pubrec.push({:id => new_id, :packet => packet, :timestamp => Time.now})
|
836
|
-
}
|
370
|
+
def init_connection
|
371
|
+
unless reconnect?
|
372
|
+
@connection_helper = ConnectionHelper.new(@host, @port, @ssl, @ssl_context, @ack_timeout)
|
373
|
+
@connection_helper.handler = @handler
|
374
|
+
@sender = @connection_helper.sender
|
837
375
|
end
|
838
|
-
|
376
|
+
@connection_helper.setup_connection
|
839
377
|
end
|
840
378
|
|
841
|
-
def
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
:id => packet_id
|
853
|
-
)
|
854
|
-
|
855
|
-
append_to_writing(packet)
|
856
|
-
|
857
|
-
@pubrel_mutex.synchronize{
|
858
|
-
@waiting_pubrel.push({:id => packet_id , :packet => packet, :timestamp => Time.now})
|
859
|
-
}
|
860
|
-
MQTT_ERR_SUCCESS
|
379
|
+
def session_params
|
380
|
+
{:version => @mqtt_version,
|
381
|
+
:clean_session => @clean_session,
|
382
|
+
:keep_alive => @keep_alive,
|
383
|
+
:client_id => @client_id,
|
384
|
+
:username => @username,
|
385
|
+
:password => @password,
|
386
|
+
:will_topic => @will_topic,
|
387
|
+
:will_payload => @will_payload,
|
388
|
+
:will_qos => @will_qos,
|
389
|
+
:will_retain => @will_retain}
|
861
390
|
end
|
862
|
-
|
863
|
-
def send_pubrel(packet_id)
|
864
|
-
packet = PahoMqtt::Packet::Pubrel.new(
|
865
|
-
:id => packet_id
|
866
|
-
)
|
867
|
-
|
868
|
-
append_to_writing(packet)
|
869
|
-
|
870
|
-
@pubcomp_mutex.synchronize{
|
871
|
-
@waiting_pubcomp.push({:id => packet_id, :packet => packet, :timestamp => Time.now})
|
872
|
-
}
|
873
|
-
MQTT_ERR_SUCCESS
|
874
|
-
end
|
875
|
-
|
876
|
-
def send_pubcomp(packet_id)
|
877
|
-
packet = PahoMqtt::Packet::Pubcomp.new(
|
878
|
-
:id => packet_id
|
879
|
-
)
|
880
391
|
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
def valid_topics?(topics)
|
886
|
-
unless topics.length == 0
|
887
|
-
topics.map do |topic|
|
888
|
-
return MQTT_ERR_FAIL if topic.first == ""
|
889
|
-
end
|
890
|
-
else
|
891
|
-
MQTT_ERR_FAIL
|
892
|
-
end
|
893
|
-
MQTT_ERR_SUCCESS
|
894
|
-
end
|
895
|
-
|
896
|
-
def match_filter(topics, filters)
|
897
|
-
if topics.is_a?(String) && filters.is_a?(String)
|
898
|
-
topic = topics.split('/')
|
899
|
-
filter = filters.split('/')
|
900
|
-
else
|
901
|
-
@logger.error("Topics and filters are not found as String while matching topics to filter.") if @logger.is_a?(Logger)
|
902
|
-
raise ParameterException
|
903
|
-
end
|
904
|
-
|
905
|
-
rc = false
|
906
|
-
index = 0
|
907
|
-
|
908
|
-
while index < [topic.length, filter.length].max do
|
909
|
-
if topic[index].nil? || filter[index].nil?
|
910
|
-
break
|
911
|
-
elsif filter[index] == '#' && index == (filter.length - 1)
|
912
|
-
rc = true
|
913
|
-
break
|
914
|
-
elsif filter[index] == topic[index] || filter[index] == '+'
|
915
|
-
index = index + 1
|
916
|
-
else
|
917
|
-
break
|
918
|
-
end
|
919
|
-
end
|
920
|
-
rc ||= (index == [topic.length, filter.length].max)
|
392
|
+
def check_persistence
|
393
|
+
disconnect(false)
|
394
|
+
@persistent
|
921
395
|
end
|
922
396
|
end
|
923
397
|
end
|