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.
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: []