apiotics-paho-mqtt 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|