mqtt-sub_handler 0.1.0.dev → 0.1.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 +4 -4
- data/README.md +0 -5
- data/lib/mqtt/sub_handler.rb +18 -6
- data/lib/mqtt/sub_testing.rb +52 -16
- data/lib/mqtt/subscription_classes.rb +2 -2
- metadata +60 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77c5c7ff31447b119bde650cc2bab092e930fb1e
|
4
|
+
data.tar.gz: 73f5d04c7d2acb4da546ab3b9a16995e643a96ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecb77d9ee3bdf6d121edf8c19808c973a3a1c9ca1736119793d7b2a6afa0abb2720b7ab4e4613a6165ac473db1ee36ca0d746af6c3add4ac3e5fa58d9ad89e55
|
7
|
+
data.tar.gz: 1cb20f6c9c7a6e40a09b36d868e65698aaa953a5cd48e5a6f55ca18cb73d965d6f5c99ffdbda0f356f0407e175f3f432204bd3e9edbee966a49ae4579f5f2c86
|
data/README.md
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
|
2
|
-
### Where're the tests?
|
3
|
-
They're not here yet! But if you know how to set them up, I'd absolutely love to have you contribute.
|
4
|
-
Open an issue about that and we can figure things out!
|
5
|
-
|
6
1
|
# A topic-based, asynchronous MQTT handler
|
7
2
|
That's right, finally there's a *mostly* stable, connection-loss resistant MQTT handler out there that runs fully asynchronously.
|
8
3
|
What's even nicer is that you can attach (and detach!) callbacks to *any* topic you want - including wildcards!
|
data/lib/mqtt/sub_handler.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
require 'timeout'
|
3
3
|
require 'mqtt'
|
4
|
+
require 'json'
|
4
5
|
|
5
|
-
|
6
|
+
require_relative 'subscription_classes.rb'
|
6
7
|
|
7
8
|
# @author Xasin
|
8
9
|
module MQTT
|
@@ -15,11 +16,14 @@ end
|
|
15
16
|
|
16
17
|
|
17
18
|
class SubHandler
|
19
|
+
# Whether or not hashes and arrays should be converted to JSON when sending
|
20
|
+
attr_accessor :jsonifyHashes
|
21
|
+
|
18
22
|
# Split a Topic into a Topic-Array
|
19
23
|
# @param topicName [String] The string topic which to split
|
20
24
|
# @return [Array<String>] A list of individual topic-branches
|
21
25
|
# @note This function is mainly used for background processing.
|
22
|
-
def self.
|
26
|
+
def self.get_topic_split(topicName)
|
23
27
|
return topicName.scan(/[^\/]+/);
|
24
28
|
end
|
25
29
|
|
@@ -27,13 +31,13 @@ class SubHandler
|
|
27
31
|
# @param receivedTopicString [String] The string (as
|
28
32
|
# returned by MQTT.get) to compare
|
29
33
|
# @param topicPattern [Array<String>] The Topic-Array (as
|
30
|
-
# returned by .
|
34
|
+
# returned by .get_topic_split) to compare against
|
31
35
|
# @return [nil, Array<String>] Nil if no match was found.
|
32
36
|
# An Array of matched wildcard topic branches (can be empty) when
|
33
37
|
# successfully matched
|
34
|
-
# @note (see .
|
38
|
+
# @note (see .get_topic_split)
|
35
39
|
def self.getTopicMatch(receivedTopicString, topicPattern)
|
36
|
-
receivedTopicList =
|
40
|
+
receivedTopicList = get_topic_split receivedTopicString;
|
37
41
|
|
38
42
|
outputTopicList = Array.new();
|
39
43
|
|
@@ -206,6 +210,10 @@ class SubHandler
|
|
206
210
|
def publish_to(topic, data, qos: 1, retain: false)
|
207
211
|
raise ArgumentError, "Wrong symbol in topic: #{topic}" if topic =~ /[#\+]/
|
208
212
|
|
213
|
+
if(@jsonifyHashes and (data.is_a? Array or data.is_a? Hash))
|
214
|
+
data = data.to_json
|
215
|
+
end
|
216
|
+
|
209
217
|
begin
|
210
218
|
@conChangeMutex.lock
|
211
219
|
if not @connected
|
@@ -335,10 +343,12 @@ class SubHandler
|
|
335
343
|
# @param mqttClient [String, MQTT::Client] Either a URI to connect to, or a MQTT::Client
|
336
344
|
# The URI can be of the form "mqtts://Password@User:URL:port".
|
337
345
|
# The MQTT client instance can be fully configured, as specified by the MQTT Gem. It must *not* already be connected!
|
346
|
+
# @param jsonify [Boolean] Should Hashes and Arrays input into publish_to be converted to JSON?
|
347
|
+
# This can be useful to have one less .to_json call. Default is true.
|
338
348
|
# @example Starting the handler
|
339
349
|
# mqtt = MQTT::SubHandler.new('iot.eclipse.org');
|
340
350
|
# mqtt = MQTT::SubHandler.new(MQTT::Client.new("Your.Client.Opts"))
|
341
|
-
def initialize(mqttClient)
|
351
|
+
def initialize(mqttClient, jsonify: true)
|
342
352
|
@callbackList = Array.new();
|
343
353
|
if mqttClient.is_a? String
|
344
354
|
@mqtt = MQTT::Client.new(mqttClient);
|
@@ -346,6 +356,8 @@ class SubHandler
|
|
346
356
|
@mqtt = mqttClient;
|
347
357
|
end
|
348
358
|
|
359
|
+
@jsonifyHashes = jsonify;
|
360
|
+
|
349
361
|
@conChangeMutex = Mutex.new();
|
350
362
|
@connected = false;
|
351
363
|
|
data/lib/mqtt/sub_testing.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require_relative "sub_handler.rb"
|
3
|
+
require 'securerandom'
|
3
4
|
|
4
5
|
module MQTT
|
5
6
|
module Testing
|
@@ -12,20 +13,13 @@ module MQTT
|
|
12
13
|
attr_reader :publish_queue
|
13
14
|
attr_accessor :retained_topics
|
14
15
|
|
16
|
+
attr_accessor :test_handler
|
17
|
+
|
15
18
|
def call_interested(topic, data)
|
16
19
|
@callbackList.each do |h|
|
17
20
|
tMatch = SubHandler.getTopicMatch(topic, h.topic_split);
|
18
21
|
if tMatch then
|
19
|
-
|
20
|
-
h.offer(tMatch, data)
|
21
|
-
rescue StandardError => e
|
22
|
-
if(@error_handler)
|
23
|
-
@error_handler.call(e);
|
24
|
-
else
|
25
|
-
raise
|
26
|
-
end
|
27
|
-
return
|
28
|
-
end
|
22
|
+
h.offer(tMatch, data)
|
29
23
|
end
|
30
24
|
end
|
31
25
|
end
|
@@ -44,6 +38,12 @@ module MQTT
|
|
44
38
|
# @note The published data is not immediately processed.
|
45
39
|
# Use process_message or process_all
|
46
40
|
def publish_to(topic, data, qos: nil, retain: false)
|
41
|
+
if(@jsonifyHashes and (data.is_a? Array or data.is_a? Hash))
|
42
|
+
data = data.to_json
|
43
|
+
else
|
44
|
+
data = data.to_s;
|
45
|
+
end
|
46
|
+
|
47
47
|
@publish_queue << [topic, data];
|
48
48
|
@message_log[topic] << data;
|
49
49
|
@retained_topics[topic] = data if retain;
|
@@ -64,13 +64,33 @@ module MQTT
|
|
64
64
|
until @publish_queue.empty?
|
65
65
|
process_message
|
66
66
|
max_loops -= 1;
|
67
|
+
|
67
68
|
if(max_loops == 0)
|
68
69
|
if(error_on_loop)
|
69
|
-
|
70
|
+
if(@test_handler)
|
71
|
+
@test_handler.flunk("MQTT Loop recursion detected")
|
72
|
+
else
|
73
|
+
raise RuntimeError, "MQTT Loop recursion detected"
|
74
|
+
end
|
70
75
|
end
|
71
76
|
return
|
72
77
|
end
|
73
78
|
end
|
79
|
+
|
80
|
+
if(error_on_loop and @test_handler)
|
81
|
+
@test_handler.pass("No MQTT Loop recursion.");
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def assert_garbage_resilient()
|
86
|
+
@callbackList.each do |c|
|
87
|
+
t = Array.new() {|a,k| a[k] = SecureRandom.random_bytes(100)}
|
88
|
+
c.offer(t, SecureRandom.random_bytes(100));
|
89
|
+
end
|
90
|
+
|
91
|
+
if(@test_handler)
|
92
|
+
@test_handler.pass("No garbage message problem detected.");
|
93
|
+
end
|
74
94
|
end
|
75
95
|
|
76
96
|
# Prepare the code for the next test by cleaning out all queues.
|
@@ -90,15 +110,31 @@ module MQTT
|
|
90
110
|
@message_log.clear()
|
91
111
|
end
|
92
112
|
|
93
|
-
|
113
|
+
# Perform a complete reset of the testing unit, clearing out all
|
114
|
+
# queues and removing all callbacks. This should mainly be used
|
115
|
+
# inside the teardown or setup routines, before creating a new
|
116
|
+
# testing instance, to prevent uncleaned garbage.
|
117
|
+
def full_reset()
|
118
|
+
@callbackList.clear();
|
119
|
+
prepare();
|
120
|
+
end
|
121
|
+
|
122
|
+
# Initialize the test class
|
123
|
+
# @param jsonify [Boolean] Whether or not Hashes and Arrays should be
|
124
|
+
# converted to JSON before sending.
|
125
|
+
# @param test_handler [nil, MiniTest::Test] The test handler to use to report
|
126
|
+
# errors or pass sanity checks. Must support flunk and pass!
|
127
|
+
def initialize(jsonify: true, test_handler: nil)
|
94
128
|
@callbackList = Array.new();
|
95
129
|
@retained_topics = Hash.new();
|
96
130
|
@publish_queue = Queue.new();
|
97
131
|
@message_log = Hash.new() do |h, key| h = Array.new() end;
|
98
|
-
end
|
99
132
|
|
100
|
-
|
101
|
-
|
133
|
+
@trackerHash = Hash.new();
|
134
|
+
|
135
|
+
@jsonifyHashes = jsonify;
|
136
|
+
|
137
|
+
@test_handler = test_handler;
|
102
138
|
end
|
103
139
|
end
|
104
140
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require_relative 'Waitpoint.rb'
|
3
3
|
|
4
4
|
module MQTT
|
5
5
|
module Subscriptions
|
@@ -11,7 +11,7 @@ module MQTT
|
|
11
11
|
|
12
12
|
def initialize(topic, _qos)
|
13
13
|
@topic = topic;
|
14
|
-
@topic_split = SubHandler.
|
14
|
+
@topic_split = SubHandler.get_topic_split(topic);
|
15
15
|
|
16
16
|
@qos = 0;
|
17
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mqtt-sub_handler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xasin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mqtt
|
@@ -24,6 +24,62 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.5.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
27
83
|
description: Asynchronous handling of callbacks that can be attached to individual
|
28
84
|
topics, based on the mqtt gem.
|
29
85
|
email:
|
@@ -51,9 +107,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
107
|
version: '0'
|
52
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
109
|
requirements:
|
54
|
-
- - "
|
110
|
+
- - ">="
|
55
111
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
112
|
+
version: '0'
|
57
113
|
requirements: []
|
58
114
|
rubyforge_project:
|
59
115
|
rubygems_version: 2.6.14.1
|