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,163 @@
|
|
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 Subscriber
|
17
|
+
|
18
|
+
attr_reader :subscribed_topics
|
19
|
+
|
20
|
+
def initialize(sender)
|
21
|
+
@waiting_suback = []
|
22
|
+
@waiting_unsuback = []
|
23
|
+
@subscribed_mutex = Mutex.new
|
24
|
+
@subscribed_topics = []
|
25
|
+
@suback_mutex = Mutex.new
|
26
|
+
@unsuback_mutex = Mutex.new
|
27
|
+
@sender = sender
|
28
|
+
end
|
29
|
+
|
30
|
+
def sender=(sender)
|
31
|
+
@sender = sender
|
32
|
+
end
|
33
|
+
|
34
|
+
def config_subscription(new_id)
|
35
|
+
unless @subscribed_topics == [] || @subscribed_topics.nil?
|
36
|
+
packet = PahoMqtt::Packet::Subscribe.new(
|
37
|
+
:id => new_id,
|
38
|
+
:topics => @subscribed_topics
|
39
|
+
)
|
40
|
+
@subscribed_mutex.synchronize do
|
41
|
+
@subscribed_topics = []
|
42
|
+
end
|
43
|
+
@suback_mutex.synchronize do
|
44
|
+
if @waiting_suback.length >= MAX_SUBACK
|
45
|
+
PahoMqtt.logger.error('SUBACK queue is full, could not send subscribe') if PahoMqtt.logger?
|
46
|
+
return MQTT_ERR_FAILURE
|
47
|
+
end
|
48
|
+
@waiting_suback.push(:id => new_id, :packet => packet, :timestamp => Time.now)
|
49
|
+
end
|
50
|
+
@sender.send_packet(packet)
|
51
|
+
end
|
52
|
+
MQTT_ERR_SUCCESS
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_subscription(max_qos, packet_id, adjust_qos)
|
56
|
+
@suback_mutex.synchronize do
|
57
|
+
adjust_qos, @waiting_suback = @waiting_suback.partition { |pck| pck[:id] == packet_id }
|
58
|
+
end
|
59
|
+
if adjust_qos.length == 1
|
60
|
+
adjust_qos = adjust_qos.first[:packet].topics
|
61
|
+
adjust_qos.each do |t|
|
62
|
+
if [0, 1, 2].include?(max_qos[0])
|
63
|
+
t[1] = max_qos.shift
|
64
|
+
elsif max_qos[0] == 128
|
65
|
+
adjust_qos.delete(t)
|
66
|
+
else
|
67
|
+
PahoMqtt.logger.error("The QoS value is invalid in subscribe.") if PahoMqtt.logger?
|
68
|
+
raise PacketException.new('Invalid suback QoS value')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
PahoMqtt.logger.error("The packet id is invalid, already used.") if PahoMqtt.logger?
|
73
|
+
raise PacketException.new("Invalid suback packet id: #{packet_id}")
|
74
|
+
end
|
75
|
+
@subscribed_mutex.synchronize do
|
76
|
+
@subscribed_topics.concat(adjust_qos)
|
77
|
+
end
|
78
|
+
return adjust_qos
|
79
|
+
end
|
80
|
+
|
81
|
+
def remove_subscription(packet_id, to_unsub)
|
82
|
+
@unsuback_mutex.synchronize do
|
83
|
+
to_unsub, @waiting_unsuback = @waiting_unsuback.partition { |pck| pck[:id] == packet_id }
|
84
|
+
end
|
85
|
+
|
86
|
+
if to_unsub.length == 1
|
87
|
+
to_unsub = to_unsub.first[:packet].topics
|
88
|
+
else
|
89
|
+
PahoMqtt.logger.error("The packet id is invalid, already used.") if PahoMqtt.logger?
|
90
|
+
raise PacketException.new("Invalid unsuback packet id: #{packet_id}")
|
91
|
+
end
|
92
|
+
|
93
|
+
@subscribed_mutex.synchronize do
|
94
|
+
to_unsub.each do |filter|
|
95
|
+
@subscribed_topics.delete_if { |topic| PahoMqtt.match_filter(topic.first, filter) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return to_unsub
|
99
|
+
end
|
100
|
+
|
101
|
+
def send_subscribe(topics, new_id)
|
102
|
+
unless valid_topics?(topics) == MQTT_ERR_FAIL
|
103
|
+
packet = PahoMqtt::Packet::Subscribe.new(
|
104
|
+
:id => new_id,
|
105
|
+
:topics => topics
|
106
|
+
)
|
107
|
+
@sender.append_to_writing(packet)
|
108
|
+
@suback_mutex.synchronize do
|
109
|
+
if @waiting_suback.length >= MAX_SUBACK
|
110
|
+
PahoMqtt.logger.error('SUBACK queue is full, could not send subscribe') if PahoMqtt.logger?
|
111
|
+
return MQTT_ERR_FAILURE
|
112
|
+
end
|
113
|
+
@waiting_suback.push(:id => new_id, :packet => packet, :timestamp => Time.now)
|
114
|
+
end
|
115
|
+
MQTT_ERR_SUCCESS
|
116
|
+
else
|
117
|
+
raise ProtocolViolation
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def send_unsubscribe(topics, new_id)
|
122
|
+
unless valid_topics?(topics) == MQTT_ERR_FAIL
|
123
|
+
packet = PahoMqtt::Packet::Unsubscribe.new(
|
124
|
+
:id => new_id,
|
125
|
+
:topics => topics
|
126
|
+
)
|
127
|
+
|
128
|
+
@sender.append_to_writing(packet)
|
129
|
+
@unsuback_mutex.synchronize do
|
130
|
+
if @waiting_suback.length >= MAX_UNSUBACK
|
131
|
+
PahoMqtt.logger.error('UNSUBACK queue is full, could not send unbsubscribe') if PahoMqtt.logger?
|
132
|
+
return MQTT_ERR_FAIL
|
133
|
+
end
|
134
|
+
@waiting_unsuback.push(:id => new_id, :packet => packet, :timestamp => Time.now)
|
135
|
+
end
|
136
|
+
MQTT_ERR_SUCCESS
|
137
|
+
else
|
138
|
+
raise ProtocolViolation
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def check_waiting_subscriber
|
143
|
+
@sender.check_ack_alive(@waiting_suback, @suback_mutex)
|
144
|
+
@sender.check_ack_alive(@waiting_unsuback, @unsuback_mutex)
|
145
|
+
end
|
146
|
+
|
147
|
+
def valid_topics?(topics)
|
148
|
+
unless topics.length == 0
|
149
|
+
topics.map do |topic|
|
150
|
+
case topic
|
151
|
+
when Array
|
152
|
+
return MQTT_ERR_FAIL if topic.first == ""
|
153
|
+
when String
|
154
|
+
return MQTT_ERR_FAIL if topic == ""
|
155
|
+
end
|
156
|
+
end
|
157
|
+
else
|
158
|
+
MQTT_ERR_FAIL
|
159
|
+
end
|
160
|
+
MQTT_ERR_SUCCESS
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'paho-mqtt'
|
2
|
+
|
3
|
+
client = PahoMqtt::Client.new()
|
4
|
+
PahoMqtt.logger = 'paho.log'
|
5
|
+
|
6
|
+
client.on_message do |pck|
|
7
|
+
puts "New Message: #{pck.topic}\n>>> #{pck.payload}"
|
8
|
+
end
|
9
|
+
|
10
|
+
wait_suback = true
|
11
|
+
client.on_suback do |pck|
|
12
|
+
wait_suback = false
|
13
|
+
end
|
14
|
+
|
15
|
+
client.connect('localhost', 1883, client.keep_alive, true, true)
|
16
|
+
|
17
|
+
Thread.new do
|
18
|
+
while wait_suback do
|
19
|
+
client.loop_read
|
20
|
+
sleep 0.001
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
client.subscribe(["topic_test", 2])
|
25
|
+
client.loop_write
|
26
|
+
|
27
|
+
loop do
|
28
|
+
client.loop_read
|
29
|
+
sleep 0.01
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'paho-mqtt'
|
2
|
+
|
3
|
+
PahoMqtt.logger = ('paho_mqtt.log')
|
4
|
+
|
5
|
+
client = PahoMqtt::Client.new()
|
6
|
+
|
7
|
+
client.on_message = lambda { |p| puts ">>>>> This is the callback for a message event <<<<<\nTopic: #{p.topic}\nPayload: #{p.payload}\nQoS: #{p.qos}" }
|
8
|
+
|
9
|
+
|
10
|
+
client.connect('localhost', 1883, client.keep_alive, true, true)
|
11
|
+
client.subscribe(["topic_test", 2])
|
12
|
+
|
13
|
+
loop do
|
14
|
+
client.publish("topic_test", "Hello, Are you there?", false, 1)
|
15
|
+
client.loop_write
|
16
|
+
client.loop_read
|
17
|
+
sleep 1
|
18
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'paho-mqtt'
|
2
|
+
|
3
|
+
### Create a simple client with default attributes
|
4
|
+
client = PahoMqtt::Client.new
|
5
|
+
PahoMqtt.logger = 'paho_mqtt'
|
6
|
+
### Register a callback on message event to display messages
|
7
|
+
message_counter = 0
|
8
|
+
client.on_message do |message|
|
9
|
+
puts "Message recieved on topic: #{message.topic}\n>>> #{message.payload}"
|
10
|
+
message_counter += 1
|
11
|
+
end
|
12
|
+
|
13
|
+
### Register a callback on suback to assert the subcription
|
14
|
+
waiting_suback = true
|
15
|
+
client.on_suback do
|
16
|
+
waiting_suback = false
|
17
|
+
puts "Subscribed"
|
18
|
+
end
|
19
|
+
|
20
|
+
### Register a callback for puback event when receiving a puback
|
21
|
+
waiting_puback = true
|
22
|
+
client.on_puback do
|
23
|
+
waiting_puback = false
|
24
|
+
puts "Message Acknowledged"
|
25
|
+
end
|
26
|
+
|
27
|
+
### Connect to the eclipse test server on port 1883 (Unencrypted mode)
|
28
|
+
client.connect('iot.eclipse.org', 1883)
|
29
|
+
|
30
|
+
### Subscribe to a topic
|
31
|
+
client.subscribe(['/paho/ruby/test', 2])
|
32
|
+
|
33
|
+
### Waiting for the suback answer and excute the previously set on_suback callback
|
34
|
+
while waiting_suback do
|
35
|
+
sleep 0.001
|
36
|
+
end
|
37
|
+
|
38
|
+
### Publlish a message on the topic "/paho/ruby/test" with "retain == false" and "qos == 1"
|
39
|
+
client.publish("/paho/ruby/test", "Hello there!", false, 1)
|
40
|
+
|
41
|
+
while waiting_puback do
|
42
|
+
sleep 0.001
|
43
|
+
end
|
44
|
+
|
45
|
+
### Waiting to assert that the message is displayed by on_message callback
|
46
|
+
sleep 1
|
47
|
+
|
48
|
+
### Calling an explicit disconnect
|
49
|
+
client.disconnect
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "paho-mqtt"
|
2
|
+
require "logger"
|
3
|
+
|
4
|
+
cli = PahoMqtt::Client.new({persistent: true, keep_alive: 7})
|
5
|
+
PahoMqtt.logger = 'paho_log'
|
6
|
+
|
7
|
+
cli.connect('localhost', 1883)
|
8
|
+
|
9
|
+
#########################################################
|
10
|
+
### Callback settings
|
11
|
+
waiting = true
|
12
|
+
cli.on_suback { waiting = false}
|
13
|
+
|
14
|
+
cli.on_message = lambda { |p| puts ">>>>> This is a LAMBDA callback for message event <<<<<\nTopic: #{p.topic}\nPayload: #{p.payload}\nQoS: #{p.qos}" }
|
15
|
+
|
16
|
+
foo_foo = lambda { |p| puts ">>>>> I am LAMBDA callback for the /foo/foo topic <<<<<" }
|
17
|
+
foo_bar = proc { puts ">>>>> I am PROC callback for the /foo/bar topic <<<<<" }
|
18
|
+
|
19
|
+
|
20
|
+
cli.add_topic_callback('/foo/tutu') do
|
21
|
+
puts ">>>>> I am BLOCK callback for the /foo/tutu topic <<<<<"
|
22
|
+
end
|
23
|
+
cli.add_topic_callback('/foo/bar', foo_bar)
|
24
|
+
cli.add_topic_callback('/foo/foo', foo_foo)
|
25
|
+
|
26
|
+
#########################################################
|
27
|
+
|
28
|
+
cli.subscribe(['/foo/foo', 0], ['/foo/bar', 1], ['/foo/tutu', 2], ["/foo", 0])
|
29
|
+
|
30
|
+
while waiting do
|
31
|
+
sleep 0.0001
|
32
|
+
end
|
33
|
+
|
34
|
+
cli.publish("/foo/tutu", "It's me!", false, 2)
|
35
|
+
cli.publish("/foo/tutu", "It's you!", false, 1)
|
36
|
+
cli.publish("/foo/tutu", "It's them!", false, 0)
|
37
|
+
|
38
|
+
cli.publish("/foo/bar", "It's me!", false, 2)
|
39
|
+
cli.publish("/foo/bar", "It's you!", false, 1)
|
40
|
+
cli.publish("/foo/bar", "It's them!", false, 0)
|
41
|
+
|
42
|
+
cli.publish("/foo/foo", "It's me!", false, 2)
|
43
|
+
cli.publish("/foo/foo", "It's you!", false, 1)
|
44
|
+
cli.publish("/foo/foo", "It's them!", false, 0)
|
45
|
+
|
46
|
+
sleep cli.ack_timeout
|
47
|
+
|
48
|
+
cli.on_message = nil
|
49
|
+
foo_tutu = lambda { |p| puts ">>>>> Changing callback type to LAMBDA for the /foo/tutu topic <<<<<" }
|
50
|
+
cli.add_topic_callback('/foo/tutu', foo_tutu)
|
51
|
+
cli.add_topic_callback('/foo/bar') do
|
52
|
+
puts ">>>>> Changing callback type to BLOCK for the /foo/bar topic <<<<<"
|
53
|
+
end
|
54
|
+
|
55
|
+
cli.publish("/foo/tutu", "It's me!", false, 2)
|
56
|
+
cli.publish("/foo/tutu", "It's you!", false, 1)
|
57
|
+
cli.publish("/foo/tutu", "It's them!", false, 0)
|
58
|
+
|
59
|
+
cli.publish("/foo/bar", "It's me!", false, 2)
|
60
|
+
cli.publish("/foo/bar", "It's you!", false, 1)
|
61
|
+
cli.publish("/foo/bar", "It's them!", false, 0)
|
62
|
+
|
63
|
+
sleep cli.ack_timeout
|
64
|
+
|
65
|
+
cli.unsubscribe("+/tutu", "+/+")
|
66
|
+
|
67
|
+
puts "Waiting 10 sec for keeping alive..."
|
68
|
+
sleep 10
|
69
|
+
|
70
|
+
cli.disconnect
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: apiotics-paho-mqtt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mac Dougherty
|
8
|
+
- Pierre Goudet
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-05-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.11'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.11'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.0'
|
56
|
+
description: A simple mqtt client gem
|
57
|
+
email:
|
58
|
+
- mac@apiotics.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
66
|
+
- CODE_OF_CONDUCT.md
|
67
|
+
- Gemfile
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- apiotics-paho-mqtt.gemspec
|
71
|
+
- bin/console
|
72
|
+
- bin/setup
|
73
|
+
- lib/paho-mqtt.rb
|
74
|
+
- lib/paho_mqtt/client.rb
|
75
|
+
- lib/paho_mqtt/connection_helper.rb
|
76
|
+
- lib/paho_mqtt/exception.rb
|
77
|
+
- lib/paho_mqtt/handler.rb
|
78
|
+
- lib/paho_mqtt/packet.rb
|
79
|
+
- lib/paho_mqtt/packet/base.rb
|
80
|
+
- lib/paho_mqtt/packet/connack.rb
|
81
|
+
- lib/paho_mqtt/packet/connect.rb
|
82
|
+
- lib/paho_mqtt/packet/disconnect.rb
|
83
|
+
- lib/paho_mqtt/packet/pingreq.rb
|
84
|
+
- lib/paho_mqtt/packet/pingresp.rb
|
85
|
+
- lib/paho_mqtt/packet/puback.rb
|
86
|
+
- lib/paho_mqtt/packet/pubcomp.rb
|
87
|
+
- lib/paho_mqtt/packet/publish.rb
|
88
|
+
- lib/paho_mqtt/packet/pubrec.rb
|
89
|
+
- lib/paho_mqtt/packet/pubrel.rb
|
90
|
+
- lib/paho_mqtt/packet/suback.rb
|
91
|
+
- lib/paho_mqtt/packet/subscribe.rb
|
92
|
+
- lib/paho_mqtt/packet/unsuback.rb
|
93
|
+
- lib/paho_mqtt/packet/unsubscribe.rb
|
94
|
+
- lib/paho_mqtt/publisher.rb
|
95
|
+
- lib/paho_mqtt/sender.rb
|
96
|
+
- lib/paho_mqtt/ssl_helper.rb
|
97
|
+
- lib/paho_mqtt/subscriber.rb
|
98
|
+
- lib/paho_mqtt/version.rb
|
99
|
+
- samples/client_blocking(reading).rb
|
100
|
+
- samples/client_blocking(writing).rb
|
101
|
+
- samples/getting_started.rb
|
102
|
+
- samples/test_client.rb
|
103
|
+
homepage: https://portal.apiotics.com
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.2.2
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: A simple mqtt client gem
|
127
|
+
test_files: []
|