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,75 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
### original file from the ruby-mqtt gem
|
3
|
+
### located at https://github.com/njh/ruby-mqtt/blob/master/lib/mqtt/packet.rb
|
4
|
+
### Copyright (c) 2009-2013 Nicholas J Humfrey
|
5
|
+
|
6
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
7
|
+
#
|
8
|
+
# All rights reserved. This program and the accompanying materials
|
9
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
10
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
11
|
+
#
|
12
|
+
# The Eclipse Public License is available at
|
13
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
14
|
+
# and the Eclipse Distribution License is available at
|
15
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
16
|
+
#
|
17
|
+
# Contributors:
|
18
|
+
# Pierre Goudet - initial committer
|
19
|
+
|
20
|
+
module PahoMqtt
|
21
|
+
module Packet
|
22
|
+
class Suback < PahoMqtt::Packet::Base
|
23
|
+
# An array of return codes, ordered by the topics that were subscribed to
|
24
|
+
attr_accessor :return_codes
|
25
|
+
|
26
|
+
# Default attribute values
|
27
|
+
ATTR_DEFAULTS = {
|
28
|
+
:return_codes => [],
|
29
|
+
}
|
30
|
+
|
31
|
+
# Create a new Subscribe Acknowledgment packet
|
32
|
+
def initialize(args={})
|
33
|
+
super(ATTR_DEFAULTS.merge(args))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set the granted QoS value for each of the topics that were subscribed to
|
37
|
+
# Can either be an integer or an array or integers.
|
38
|
+
def return_codes=(value)
|
39
|
+
if value.is_a?(Array)
|
40
|
+
@return_codes = value
|
41
|
+
elsif value.is_a?(Integer)
|
42
|
+
@return_codes = [value]
|
43
|
+
else
|
44
|
+
raise PahoMqtt::PacketFormatException.new(
|
45
|
+
"return_codes should be an integer or an array of return codes")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get serialisation of packet's body
|
50
|
+
def encode_body
|
51
|
+
if @return_codes.empty?
|
52
|
+
raise PahoMqtt::PacketFormatException.new(
|
53
|
+
"No granted QoS given when serialising packet")
|
54
|
+
end
|
55
|
+
body = encode_short(@id)
|
56
|
+
return_codes.each { |qos| body += encode_bytes(qos) }
|
57
|
+
return body
|
58
|
+
end
|
59
|
+
|
60
|
+
# Parse the body (variable header and payload) of a packet
|
61
|
+
def parse_body(buffer)
|
62
|
+
super(buffer)
|
63
|
+
@id = shift_short(buffer)
|
64
|
+
while buffer.bytesize > 0
|
65
|
+
@return_codes << shift_byte(buffer)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns a human readable string, summarising the properties of the packet
|
70
|
+
def inspect
|
71
|
+
"\#<#{self.class}: 0x%2.2X, rc=%s>" % [id, return_codes.map { |rc| "0x%2.2X" % rc }.join(',')]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
### original file from the ruby-mqtt gem
|
3
|
+
### located at https://github.com/njh/ruby-mqtt/blob/master/lib/mqtt/packet.rb
|
4
|
+
### Copyright (c) 2009-2013 Nicholas J Humfrey
|
5
|
+
|
6
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
7
|
+
#
|
8
|
+
# All rights reserved. This program and the accompanying materials
|
9
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
10
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
11
|
+
#
|
12
|
+
# The Eclipse Public License is available at
|
13
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
14
|
+
# and the Eclipse Distribution License is available at
|
15
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
16
|
+
#
|
17
|
+
# Contributors:
|
18
|
+
# Pierre Goudet - initial committer
|
19
|
+
|
20
|
+
module PahoMqtt
|
21
|
+
module Packet
|
22
|
+
class Subscribe < PahoMqtt::Packet::Base
|
23
|
+
# One or more topic filters to subscribe to
|
24
|
+
attr_accessor :topics
|
25
|
+
|
26
|
+
# Default attribute values
|
27
|
+
ATTR_DEFAULTS = {
|
28
|
+
:topics => [],
|
29
|
+
:flags => [false, true, false, false],
|
30
|
+
}
|
31
|
+
|
32
|
+
# Create a new Subscribe packet
|
33
|
+
def initialize(args={})
|
34
|
+
super(ATTR_DEFAULTS.merge(args))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Set one or more topic filters for the Subscribe packet
|
38
|
+
# The topics parameter should be one of the following:
|
39
|
+
# * String: subscribe to one topic with QoS 0
|
40
|
+
# * Array: subscribe to multiple topics with QoS 0
|
41
|
+
# * Hash: subscribe to multiple topics where the key is the topic and the value is the QoS level
|
42
|
+
#
|
43
|
+
# For example:
|
44
|
+
# packet.topics = 'a/b'
|
45
|
+
# packet.topics = ['a/b', 'c/d']
|
46
|
+
# packet.topics = [['a/b',0], ['c/d',1]]
|
47
|
+
# packet.topics = {'a/b' => 0, 'c/d' => 1}
|
48
|
+
#
|
49
|
+
def topics=(value)
|
50
|
+
# Get input into a consistent state
|
51
|
+
if value.is_a?(Array)
|
52
|
+
input = value.flatten
|
53
|
+
else
|
54
|
+
input = [value]
|
55
|
+
end
|
56
|
+
|
57
|
+
@topics = []
|
58
|
+
while(input.length>0)
|
59
|
+
item = input.shift
|
60
|
+
if item.is_a?(Hash)
|
61
|
+
# Convert hash into an ordered array of arrays
|
62
|
+
@topics += item.sort
|
63
|
+
elsif item.is_a?(String)
|
64
|
+
# Peek at the next item in the array, and remove it if it is an integer
|
65
|
+
if input.first.is_a?(Integer)
|
66
|
+
qos = input.shift
|
67
|
+
@topics << [item, qos]
|
68
|
+
else
|
69
|
+
@topics << [item, 0]
|
70
|
+
end
|
71
|
+
else
|
72
|
+
# Meh?
|
73
|
+
raise PahoMqtt::PacketFormatException.new(
|
74
|
+
"Invalid topics input: #{value.inspect}")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
@topics
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get serialisation of packet's body
|
81
|
+
def encode_body
|
82
|
+
if @topics.empty?
|
83
|
+
raise PahoMqtt::PacketFormatException.new(
|
84
|
+
"No topics given when serialising packet")
|
85
|
+
end
|
86
|
+
body = encode_short(@id)
|
87
|
+
topics.each do |item|
|
88
|
+
body += encode_string(item[0])
|
89
|
+
body += encode_bytes(item[1])
|
90
|
+
end
|
91
|
+
return body
|
92
|
+
end
|
93
|
+
|
94
|
+
# Parse the body (variable header and payload) of a packet
|
95
|
+
def parse_body(buffer)
|
96
|
+
super(buffer)
|
97
|
+
@id = shift_short(buffer)
|
98
|
+
@topics = []
|
99
|
+
while(buffer.bytesize>0)
|
100
|
+
topic_name = shift_string(buffer)
|
101
|
+
topic_qos = shift_byte(buffer)
|
102
|
+
@topics << [topic_name, topic_qos]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Check that fixed header flags are valid for this packet type
|
107
|
+
# @private
|
108
|
+
def validate_flags
|
109
|
+
if @flags != [false, true, false, false]
|
110
|
+
raise PahoMqtt::PacketFormatException.new(
|
111
|
+
"Invalid flags in SUBSCRIBE packet header")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns a human readable string, summarising the properties of the packet
|
116
|
+
def inspect
|
117
|
+
_str = "\#<#{self.class}: 0x%2.2X, %s>" % [
|
118
|
+
id,
|
119
|
+
topics.map { |t| "'#{t[0]}':#{t[1]}" }.join(', ')
|
120
|
+
]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
### original file from the ruby-mqtt gem
|
3
|
+
### located at https://github.com/njh/ruby-mqtt/blob/master/lib/mqtt/packet.rb
|
4
|
+
### Copyright (c) 2009-2013 Nicholas J Humfrey
|
5
|
+
|
6
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
7
|
+
#
|
8
|
+
# All rights reserved. This program and the accompanying materials
|
9
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
10
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
11
|
+
#
|
12
|
+
# The Eclipse Public License is available at
|
13
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
14
|
+
# and the Eclipse Distribution License is available at
|
15
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
16
|
+
#
|
17
|
+
# Contributors:
|
18
|
+
# Pierre Goudet - initial committer
|
19
|
+
|
20
|
+
module PahoMqtt
|
21
|
+
module Packet
|
22
|
+
class Unsuback < PahoMqtt::Packet::Base
|
23
|
+
# Create a new Unsubscribe Acknowledgment packet
|
24
|
+
def initialize(args={})
|
25
|
+
super(args)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get serialisation of packet's body
|
29
|
+
def encode_body
|
30
|
+
encode_short(@id)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Parse the body (variable header and payload) of a packet
|
34
|
+
def parse_body(buffer)
|
35
|
+
super(buffer)
|
36
|
+
@id = shift_short(buffer)
|
37
|
+
unless buffer.empty?
|
38
|
+
raise PahoMqtt::PacketFormatException.new(
|
39
|
+
"Extra bytes at end of Unsubscribe Acknowledgment packet")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a human readable string, summarising the properties of the packet
|
44
|
+
def inspect
|
45
|
+
"\#<#{self.class}: 0x%2.2X>" % id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
### original file from the ruby-mqtt gem
|
3
|
+
### located at https://github.com/njh/ruby-mqtt/blob/master/lib/mqtt/packet.rb
|
4
|
+
### Copyright (c) 2009-2013 Nicholas J Humfrey
|
5
|
+
|
6
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
7
|
+
#
|
8
|
+
# All rights reserved. This program and the accompanying materials
|
9
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
10
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
11
|
+
#
|
12
|
+
# The Eclipse Public License is available at
|
13
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
14
|
+
# and the Eclipse Distribution License is available at
|
15
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
16
|
+
#
|
17
|
+
# Contributors:
|
18
|
+
# Pierre Goudet - initial committer
|
19
|
+
|
20
|
+
module PahoMqtt
|
21
|
+
module Packet
|
22
|
+
class Unsubscribe < PahoMqtt::Packet::Base
|
23
|
+
# One or more topic paths to unsubscribe from
|
24
|
+
attr_accessor :topics
|
25
|
+
|
26
|
+
# Default attribute values
|
27
|
+
ATTR_DEFAULTS = {
|
28
|
+
:topics => [],
|
29
|
+
:flags => [false, true, false, false],
|
30
|
+
}
|
31
|
+
|
32
|
+
# Create a new Unsubscribe packet
|
33
|
+
def initialize(args={})
|
34
|
+
super(ATTR_DEFAULTS.merge(args))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Set one or more topic paths to unsubscribe from
|
38
|
+
def topics=(value)
|
39
|
+
if value.is_a?(Array)
|
40
|
+
@topics = value
|
41
|
+
else
|
42
|
+
@topics = [value]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get serialisation of packet's body
|
47
|
+
def encode_body
|
48
|
+
if @topics.empty?
|
49
|
+
raise PahoMqtt::PacketFormatException.new(
|
50
|
+
"No topics given when serialising packet")
|
51
|
+
end
|
52
|
+
body = encode_short(@id)
|
53
|
+
topics.each { |topic| body += encode_string(topic) }
|
54
|
+
return body
|
55
|
+
end
|
56
|
+
|
57
|
+
# Parse the body (variable header and payload) of a packet
|
58
|
+
def parse_body(buffer)
|
59
|
+
super(buffer)
|
60
|
+
@id = shift_short(buffer)
|
61
|
+
while buffer.bytesize > 0
|
62
|
+
@topics << shift_string(buffer)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Check that fixed header flags are valid for this packet type
|
67
|
+
# @private
|
68
|
+
def validate_flags
|
69
|
+
if @flags != [false, true, false, false]
|
70
|
+
raise PahoMqtt::PacketFormatException.new(
|
71
|
+
"Invalid flags in UNSUBSCRIBE packet header")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns a human readable string, summarising the properties of the packet
|
76
|
+
def inspect
|
77
|
+
"\#<#{self.class}: 0x%2.2X, %s>" % [
|
78
|
+
id,
|
79
|
+
topics.map { |t| "'#{t}'" }.join(', ')
|
80
|
+
]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
# Copyright (c) 2016-2017 Pierre Goudet <p-goudet@ruby-dev.jp>
|
3
|
+
#
|
4
|
+
# All rights reserved. This program and the accompanying materials
|
5
|
+
# are made available under the terms of the Eclipse Public License v1.0
|
6
|
+
# and Eclipse Distribution License v1.0 which accompany this distribution.
|
7
|
+
#
|
8
|
+
# The Eclipse Public License is available at
|
9
|
+
# https://eclipse.org/org/documents/epl-v10.php.
|
10
|
+
# and the Eclipse Distribution License is available at
|
11
|
+
# https://eclipse.org/org/documents/edl-v10.php.
|
12
|
+
#
|
13
|
+
# Contributors:
|
14
|
+
# Pierre Goudet - initial committer
|
15
|
+
|
16
|
+
require "paho_mqtt/packet/base"
|
17
|
+
require "paho_mqtt/packet/connect"
|
18
|
+
require "paho_mqtt/packet/connack"
|
19
|
+
require "paho_mqtt/packet/publish"
|
20
|
+
require "paho_mqtt/packet/puback"
|
21
|
+
require "paho_mqtt/packet/pubrec"
|
22
|
+
require "paho_mqtt/packet/pubrel"
|
23
|
+
require "paho_mqtt/packet/pubcomp"
|
24
|
+
require "paho_mqtt/packet/subscribe"
|
25
|
+
require "paho_mqtt/packet/suback"
|
26
|
+
require "paho_mqtt/packet/unsubscribe"
|
27
|
+
require "paho_mqtt/packet/unsuback"
|
28
|
+
require "paho_mqtt/packet/pingreq"
|
29
|
+
require "paho_mqtt/packet/pingresp"
|
30
|
+
require "paho_mqtt/packet/disconnect"
|
31
|
+
|
32
|
+
module PahoMqtt
|
33
|
+
end
|
@@ -0,0 +1,191 @@
|
|
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
|
+
module PahoMqtt
|
16
|
+
class Publisher
|
17
|
+
|
18
|
+
def initialize(sender)
|
19
|
+
@waiting_puback = []
|
20
|
+
@waiting_pubrec = []
|
21
|
+
@waiting_pubrel = []
|
22
|
+
@waiting_pubcomp = []
|
23
|
+
@puback_mutex = Mutex.new
|
24
|
+
@pubrec_mutex = Mutex.new
|
25
|
+
@pubrel_mutex = Mutex.new
|
26
|
+
@pubcomp_mutex = Mutex.new
|
27
|
+
@sender = sender
|
28
|
+
end
|
29
|
+
|
30
|
+
def sender=(sender)
|
31
|
+
@sender = sender
|
32
|
+
end
|
33
|
+
|
34
|
+
def send_publish(topic, payload, retain, qos, new_id)
|
35
|
+
packet = PahoMqtt::Packet::Publish.new(
|
36
|
+
:id => new_id,
|
37
|
+
:topic => topic,
|
38
|
+
:payload => payload,
|
39
|
+
:retain => retain,
|
40
|
+
:qos => qos
|
41
|
+
)
|
42
|
+
case qos
|
43
|
+
when 1
|
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
|
51
|
+
when 2
|
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
|
59
|
+
end
|
60
|
+
@sender.append_to_writing(packet)
|
61
|
+
MQTT_ERR_SUCCESS
|
62
|
+
end
|
63
|
+
|
64
|
+
def do_publish(qos, packet_id)
|
65
|
+
case qos
|
66
|
+
when 0
|
67
|
+
when 1
|
68
|
+
send_puback(packet_id)
|
69
|
+
when 2
|
70
|
+
send_pubrec(packet_id)
|
71
|
+
else
|
72
|
+
PahoMqtt.logger.error("The packet QoS value is invalid in publish.") if PahoMqtt.logger?
|
73
|
+
raise PacketException.new('Invalid publish QoS value')
|
74
|
+
end
|
75
|
+
MQTT_ERR_SUCCESS
|
76
|
+
end
|
77
|
+
|
78
|
+
def send_puback(packet_id)
|
79
|
+
packet = PahoMqtt::Packet::Puback.new(
|
80
|
+
:id => packet_id
|
81
|
+
)
|
82
|
+
@sender.append_to_writing(packet)
|
83
|
+
MQTT_ERR_SUCCESS
|
84
|
+
end
|
85
|
+
|
86
|
+
def do_puback(packet_id)
|
87
|
+
@puback_mutex.synchronize do
|
88
|
+
@waiting_puback.delete_if { |pck| pck[:id] == packet_id }
|
89
|
+
end
|
90
|
+
MQTT_ERR_SUCCESS
|
91
|
+
end
|
92
|
+
|
93
|
+
def send_pubrec(packet_id)
|
94
|
+
packet = PahoMqtt::Packet::Pubrec.new(
|
95
|
+
:id => packet_id
|
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
|
104
|
+
@sender.append_to_writing(packet)
|
105
|
+
MQTT_ERR_SUCCESS
|
106
|
+
end
|
107
|
+
|
108
|
+
def do_pubrec(packet_id)
|
109
|
+
@pubrec_mutex.synchronize do
|
110
|
+
@waiting_pubrec.delete_if { |pck| pck[:id] == packet_id }
|
111
|
+
end
|
112
|
+
send_pubrel(packet_id)
|
113
|
+
MQTT_ERR_SUCCESS
|
114
|
+
end
|
115
|
+
|
116
|
+
def send_pubrel(packet_id)
|
117
|
+
packet = PahoMqtt::Packet::Pubrel.new(
|
118
|
+
:id => packet_id
|
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
|
127
|
+
@sender.append_to_writing(packet)
|
128
|
+
MQTT_ERR_SUCCESS
|
129
|
+
end
|
130
|
+
|
131
|
+
def do_pubrel(packet_id)
|
132
|
+
@pubrel_mutex.synchronize do
|
133
|
+
@waiting_pubrel.delete_if { |pck| pck[:id] == packet_id }
|
134
|
+
end
|
135
|
+
send_pubcomp(packet_id)
|
136
|
+
MQTT_ERR_SUCCESS
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_pubcomp(packet_id)
|
140
|
+
packet = PahoMqtt::Packet::Pubcomp.new(
|
141
|
+
:id => packet_id
|
142
|
+
)
|
143
|
+
@sender.append_to_writing(packet)
|
144
|
+
MQTT_ERR_SUCCESS
|
145
|
+
end
|
146
|
+
|
147
|
+
def do_pubcomp(packet_id)
|
148
|
+
@pubcomp_mutex.synchronize do
|
149
|
+
@waiting_pubcomp.delete_if { |pck| pck[:id] == packet_id }
|
150
|
+
end
|
151
|
+
MQTT_ERR_SUCCESS
|
152
|
+
end
|
153
|
+
|
154
|
+
def config_all_message_queue
|
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)
|
159
|
+
end
|
160
|
+
|
161
|
+
def config_message_queue(queue, mutex)
|
162
|
+
mutex.synchronize do
|
163
|
+
queue.each do |pck|
|
164
|
+
pck[:timestamp] = Time.now
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def check_waiting_publisher
|
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)
|
174
|
+
end
|
175
|
+
|
176
|
+
def flush_publisher
|
177
|
+
@puback_mutex.synchronize do
|
178
|
+
@waiting_puback = []
|
179
|
+
end
|
180
|
+
@pubrec_mutex.synchronize do
|
181
|
+
@waiting_pubrec = []
|
182
|
+
end
|
183
|
+
@pubrel_mutex.synchronize do
|
184
|
+
@waiting_pubrel = []
|
185
|
+
end
|
186
|
+
@pubcomp_mutex.synchronize do
|
187
|
+
@waiting_pubcomp = []
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,86 @@
|
|
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
|
+
module PahoMqtt
|
16
|
+
class Sender
|
17
|
+
|
18
|
+
attr_accessor :last_ping_req
|
19
|
+
|
20
|
+
def initialize(ack_timeout)
|
21
|
+
@socket = nil
|
22
|
+
@writing_queue = []
|
23
|
+
@writing_mutex = Mutex.new
|
24
|
+
@last_ping_req = -1
|
25
|
+
@ack_timeout = ack_timeout
|
26
|
+
end
|
27
|
+
|
28
|
+
def socket=(socket)
|
29
|
+
@socket = socket
|
30
|
+
end
|
31
|
+
|
32
|
+
def send_packet(packet)
|
33
|
+
begin
|
34
|
+
@socket.write(packet.to_s) unless @socket.nil? || @socket.closed?
|
35
|
+
@last_ping_req = Time.now
|
36
|
+
MQTT_ERR_SUCCESS
|
37
|
+
rescue StandardError
|
38
|
+
raise WritingException
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def append_to_writing(packet)
|
43
|
+
@writing_mutex.synchronize do
|
44
|
+
@writing_queue.push(packet) unless @writing_queue.length >= MAX_WRITING
|
45
|
+
end
|
46
|
+
MQTT_ERR_SUCCESS
|
47
|
+
end
|
48
|
+
|
49
|
+
def writing_loop(max_packet)
|
50
|
+
@writing_mutex.synchronize do
|
51
|
+
cnt = 0
|
52
|
+
while !@writing_queue.empty? && cnt < max_packet do
|
53
|
+
packet = @writing_queue.shift
|
54
|
+
send_packet(packet)
|
55
|
+
cnt += 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
MQTT_ERR_SUCCESS
|
59
|
+
end
|
60
|
+
|
61
|
+
def flush_waiting_packet(sending=true)
|
62
|
+
if sending
|
63
|
+
@writing_mutex.synchronize do
|
64
|
+
@writing_queue.each do |m|
|
65
|
+
send_packet(m)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
else
|
69
|
+
@writing_queue = []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_ack_alive(queue, mutex)
|
74
|
+
mutex.synchronize do
|
75
|
+
now = Time.now
|
76
|
+
queue.each do |pck|
|
77
|
+
if now >= pck[:timestamp] + @ack_timeout
|
78
|
+
pck[:packet].dup ||= true unless pck[:packet].class == PahoMqtt::Packet::Subscribe || pck[:packet].class == PahoMqtt::Packet::Unsubscribe
|
79
|
+
append_to_writing(pck[:packet])
|
80
|
+
pck[:timestamp] = now
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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 'openssl'
|
16
|
+
|
17
|
+
module PahoMqtt
|
18
|
+
module SSLHelper
|
19
|
+
extend self
|
20
|
+
|
21
|
+
def config_ssl_context(cert_path, key_path, ca_path=nil)
|
22
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
23
|
+
set_cert(cert_path, ssl_context)
|
24
|
+
set_key(key_path, ssl_context)
|
25
|
+
set_root_ca(ca_path, ssl_context)
|
26
|
+
#ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER unless ca_path.nil?
|
27
|
+
ssl_context
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_cert(cert_path, ssl_context)
|
31
|
+
ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_key(key_path, ssl_context)
|
35
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(File.read(key_path))
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_root_ca(ca_path, ssl_context)
|
39
|
+
ssl_context.ca_file = ca_path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|