mqtt_pipe 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -3
- data/examples/receiver.rb +1 -1
- data/examples/sender.rb +1 -1
- data/lib/mqtt_pipe/listener.rb +2 -2
- data/lib/mqtt_pipe/packer.rb +1 -1
- data/lib/mqtt_pipe/pipe.rb +50 -41
- data/lib/mqtt_pipe/types/color.rb +9 -0
- data/lib/mqtt_pipe/version.rb +1 -1
- data/spec/listener_spec.rb +2 -1
- data/spec/pipe_spec.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eb995dda9d228f1276dd94091d8e4e243eeae66
|
4
|
+
data.tar.gz: 54dbf42a2f536c7865cd3c529489ea34fccf7f1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f23a64abaf8a1db9a9288b8a93367b8b5552e46c0b30645eb0bb4fdb5d9aa5a27f4f10dde32ce2ff5a2a7ee4483a69387e6b0293ff38a0548e82048283752e6
|
7
|
+
data.tar.gz: 31e0b5d28c07cc7d3b44b701dec0160559b88a7ea7a80ef6cc79127838ab5fcf26b609494f62f026e4e16b4beeed0d5c4031f2b09d266b2e818d795500181b6e
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ MQTTPipe.create do
|
|
41
41
|
end
|
42
42
|
```
|
43
43
|
|
44
|
-
|
44
|
+
Or without the block:
|
45
45
|
|
46
46
|
```ruby
|
47
47
|
pipe = MQTTPipe.create
|
@@ -57,6 +57,7 @@ pipe.open 'test.mosquitto.org', port: 1883 do
|
|
57
57
|
end
|
58
58
|
```
|
59
59
|
|
60
|
+
|
60
61
|
## Protocol
|
61
62
|
|
62
63
|
Taking inspiration from the excellent [MessagePack](http://msgpack.org) project each data type is represented by a byte value, or in same cases a range of values. The currently supported data types along with their byte values are:
|
@@ -88,15 +89,17 @@ Note that the integers are split over several codes to accommodate for the vario
|
|
88
89
|
|
89
90
|
Array and string are also special cases in that their sizes are not known. They require a length value to be passed along with them, but instead of always including an extra byte for that purpose, length smaller than 32 can be encoded directly in the type byte value. An example is shown below:
|
90
91
|
|
91
|
-
|
92
|
+
Strings with length 1..31:
|
92
93
|
|
93
94
|
'test' -> [0xA0 + 4, 0x74, 0x65, 0x73, 0x74]
|
94
95
|
|
95
|
-
|
96
|
+
Strings with length 32..288
|
96
97
|
|
97
98
|
'testing how really long strings are encoded'
|
98
99
|
-> [0xA0, 43 - 32, 0x74, 0x65, 0x73, ...]
|
99
100
|
|
101
|
+
**Note that both strings and arrays with length 0 are converted to and sent as `nil`.**
|
102
|
+
|
100
103
|
Some data types that may be supported in the future are:
|
101
104
|
|
102
105
|
- IP Addresses
|
data/examples/receiver.rb
CHANGED
data/examples/sender.rb
CHANGED
data/lib/mqtt_pipe/listener.rb
CHANGED
@@ -6,7 +6,7 @@ module MQTTPipe
|
|
6
6
|
# given string as well as calling the action.
|
7
7
|
|
8
8
|
class Listener
|
9
|
-
attr_reader :topic, :pattern
|
9
|
+
attr_reader :topic, :pattern, :action
|
10
10
|
|
11
11
|
##
|
12
12
|
# The listener requires a topic string and a callable
|
@@ -20,7 +20,7 @@ module MQTTPipe
|
|
20
20
|
@topic = topic
|
21
21
|
@action = action
|
22
22
|
|
23
|
-
pattern = topic.gsub('*', '([^/]+)').gsub('/#', '/?(.*)')
|
23
|
+
pattern = topic.gsub('*', '([^/]+)').gsub('/#', '/?(.*)').gsub('#', '(.*)')
|
24
24
|
@pattern = %r{^#{pattern}$}
|
25
25
|
end
|
26
26
|
|
data/lib/mqtt_pipe/packer.rb
CHANGED
data/lib/mqtt_pipe/pipe.rb
CHANGED
@@ -6,7 +6,7 @@ module MQTTPipe
|
|
6
6
|
class Pipe
|
7
7
|
|
8
8
|
##
|
9
|
-
# Raised when the connection
|
9
|
+
# Raised when the connection is broken
|
10
10
|
|
11
11
|
class ConnectionError < StandardError; end
|
12
12
|
|
@@ -14,7 +14,9 @@ module MQTTPipe
|
|
14
14
|
# Create a new pipe and optionally yield to a block
|
15
15
|
|
16
16
|
def initialize &block
|
17
|
-
@listeners = []
|
17
|
+
@listeners = []
|
18
|
+
@error_handler = nil
|
19
|
+
|
18
20
|
instance_eval &block unless block.nil?
|
19
21
|
end
|
20
22
|
|
@@ -35,6 +37,10 @@ module MQTTPipe
|
|
35
37
|
on '#', &action
|
36
38
|
end
|
37
39
|
|
40
|
+
def on_error &action
|
41
|
+
@error_handler = action
|
42
|
+
end
|
43
|
+
|
38
44
|
alias_method :on_everything, :on_anything
|
39
45
|
|
40
46
|
def topics
|
@@ -45,54 +51,57 @@ module MQTTPipe
|
|
45
51
|
# Open the pipe
|
46
52
|
|
47
53
|
def open host, port: 1883, &block
|
48
|
-
|
54
|
+
listener_thread = nil
|
55
|
+
client = MQTT::Client.connect host: host, port: port
|
56
|
+
context = Context.new client
|
49
57
|
|
50
|
-
|
51
|
-
listener_thread =
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
if m = listener.match(topic)
|
61
|
-
listener.call unpacked_data, *m
|
62
|
-
end
|
58
|
+
unless @listeners.empty?
|
59
|
+
listener_thread = Thread.new(Thread.current) do |parent|
|
60
|
+
client.get do |topic, data|
|
61
|
+
begin
|
62
|
+
unpacked_data = Packer.unpack data
|
63
|
+
|
64
|
+
@listeners.each do |listener|
|
65
|
+
if m = listener.match(topic)
|
66
|
+
#listener.call unpacked_data, *m
|
67
|
+
context.instance_exec unpacked_data, *m, &listener.action
|
63
68
|
end
|
64
|
-
|
65
|
-
rescue Packer::FormatError
|
66
|
-
# TODO: Handle more gracefully
|
67
|
-
puts 'Could not parse data!'
|
68
|
-
next
|
69
69
|
end
|
70
|
+
|
71
|
+
rescue Packer::FormatError
|
72
|
+
@error_handler.call topic, data unless @error_handler.nil?
|
73
|
+
next
|
74
|
+
|
75
|
+
# Raise the exception in the parent thread
|
76
|
+
rescue Exception => e
|
77
|
+
parent.raise e
|
70
78
|
end
|
71
79
|
end
|
72
|
-
|
73
|
-
client.subscribe *topics
|
74
80
|
end
|
75
|
-
|
76
|
-
unless block.nil?
|
77
|
-
context = Context.new client
|
78
|
-
|
79
|
-
begin
|
80
|
-
context.instance_eval &block
|
81
|
-
rescue ConnectionError
|
82
|
-
|
83
|
-
puts 'Need to reconnect'
|
84
|
-
rescue Interrupt
|
85
|
-
ensure
|
86
|
-
listener_thread.exit unless topics.empty?
|
87
|
-
end
|
88
81
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
82
|
+
client.subscribe *topics
|
83
|
+
end
|
84
|
+
|
85
|
+
# Call user block
|
86
|
+
unless block.nil?
|
87
|
+
begin
|
88
|
+
context.instance_eval &block
|
89
|
+
rescue ConnectionError
|
90
|
+
puts 'TODO: Handle reconnect'
|
91
|
+
rescue Interrupt
|
92
|
+
exit
|
94
93
|
end
|
95
94
|
end
|
95
|
+
|
96
|
+
# Join with listener thread
|
97
|
+
begin
|
98
|
+
listener_thread.join unless listener_thread.nil?
|
99
|
+
rescue Interrupt
|
100
|
+
end
|
101
|
+
|
102
|
+
ensure
|
103
|
+
client.disconnect
|
104
|
+
listener_thread.exit unless listener_thread.nil?
|
96
105
|
end
|
97
106
|
|
98
107
|
private
|
data/lib/mqtt_pipe/version.rb
CHANGED
data/spec/listener_spec.rb
CHANGED
@@ -3,6 +3,7 @@ require 'mqtt_pipe'
|
|
3
3
|
describe MQTTPipe::Listener do
|
4
4
|
let(:klass) { MQTTPipe::Listener }
|
5
5
|
let(:topic) { 'test/*/topic/#' }
|
6
|
+
let(:topic_pattern) { %r{^test/([^/]+)/topic/?(.*)$} }
|
6
7
|
let(:matching_topic_1) { 'test/some/topic' }
|
7
8
|
let(:matching_topic_2) { 'test/some/topic/with/more/5' }
|
8
9
|
let(:non_matching_topic) { 'test/topic/with/8' }
|
@@ -31,6 +32,7 @@ describe MQTTPipe::Listener do
|
|
31
32
|
pattern = @listener.pattern
|
32
33
|
|
33
34
|
expect(pattern).to be_a(Regexp)
|
35
|
+
expect(pattern).to eq topic_pattern
|
34
36
|
expect(pattern === topic).to be true
|
35
37
|
end
|
36
38
|
|
@@ -82,6 +84,5 @@ describe MQTTPipe::Listener do
|
|
82
84
|
expect(@listener.run 42).to eq 84
|
83
85
|
end
|
84
86
|
end
|
85
|
-
|
86
87
|
end
|
87
88
|
end
|
data/spec/pipe_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mqtt_pipe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Lindberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mqtt
|