apiotics-paho-mqtt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +49 -0
  6. data/Gemfile +4 -0
  7. data/README.md +322 -0
  8. data/Rakefile +6 -0
  9. data/apiotics-paho-mqtt.gemspec +33 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/paho-mqtt.rb +165 -0
  13. data/lib/paho_mqtt/client.rb +417 -0
  14. data/lib/paho_mqtt/connection_helper.rb +169 -0
  15. data/lib/paho_mqtt/exception.rb +43 -0
  16. data/lib/paho_mqtt/handler.rb +273 -0
  17. data/lib/paho_mqtt/packet/base.rb +315 -0
  18. data/lib/paho_mqtt/packet/connack.rb +102 -0
  19. data/lib/paho_mqtt/packet/connect.rb +183 -0
  20. data/lib/paho_mqtt/packet/disconnect.rb +38 -0
  21. data/lib/paho_mqtt/packet/pingreq.rb +29 -0
  22. data/lib/paho_mqtt/packet/pingresp.rb +38 -0
  23. data/lib/paho_mqtt/packet/puback.rb +44 -0
  24. data/lib/paho_mqtt/packet/pubcomp.rb +44 -0
  25. data/lib/paho_mqtt/packet/publish.rb +148 -0
  26. data/lib/paho_mqtt/packet/pubrec.rb +44 -0
  27. data/lib/paho_mqtt/packet/pubrel.rb +62 -0
  28. data/lib/paho_mqtt/packet/suback.rb +75 -0
  29. data/lib/paho_mqtt/packet/subscribe.rb +124 -0
  30. data/lib/paho_mqtt/packet/unsuback.rb +49 -0
  31. data/lib/paho_mqtt/packet/unsubscribe.rb +84 -0
  32. data/lib/paho_mqtt/packet.rb +33 -0
  33. data/lib/paho_mqtt/publisher.rb +191 -0
  34. data/lib/paho_mqtt/sender.rb +86 -0
  35. data/lib/paho_mqtt/ssl_helper.rb +42 -0
  36. data/lib/paho_mqtt/subscriber.rb +163 -0
  37. data/lib/paho_mqtt/version.rb +3 -0
  38. data/samples/client_blocking(reading).rb +30 -0
  39. data/samples/client_blocking(writing).rb +18 -0
  40. data/samples/getting_started.rb +49 -0
  41. data/samples/test_client.rb +70 -0
  42. 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,3 @@
1
+ module PahoMqtt
2
+ VERSION = "1.0.0"
3
+ 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: []