mqtt_pipe 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +72 -2
- data/lib/mqtt_pipe/packer.rb +23 -0
- data/lib/mqtt_pipe/version.rb +2 -2
- data/spec/packer_spec.rb +35 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f579008e0f69a4f8dd375038f2b611d39e82ec07
|
4
|
+
data.tar.gz: 4b54e9845ad534d37b6f954028f5c6d9e3bcd83b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ded3c38efb21c73ecb8ac1cb2455cb1dc206e7e6273101fd26672e1c914143748e37862f39e311a79aed4a2fe3b7a2879f48586029d9ac2c96b271f8bd31e68
|
7
|
+
data.tar.gz: 249ded44ccac0db4e6f66372f242b99ea9d4c205fc245fe62c4b0233328ceebcfa9536450542dbf72a8af750754fdbf6a38bb648431b792ca24c4c18cf9df50b
|
data/README.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# MQTTPipe
|
2
2
|
|
3
|
-
This gem wraps the [MQTT gem](https://github.com/njh/ruby-mqtt) and adds a serializer for simple data structures.
|
3
|
+
This gem wraps the [MQTT gem](https://github.com/njh/ruby-mqtt) and adds a serializer for simple data structures. The serializer is heavily inspired by [MessagePack](http://msgpack.org) and borrows some of their byte values when packing the data. It is however much more restricted in what data types it supports. Right now hashes are for example not supported, but this may change in the future.
|
4
|
+
|
5
|
+
The reason for the limitations is that the gem is later meant to talk to devices with much more limited hardware (think Arduino, but really the ESP8266).
|
6
|
+
|
7
|
+
## TODO
|
8
|
+
|
9
|
+
1. Handle disconnects gracefully
|
10
|
+
2. Possibly add a few data types. See below for more details on that.
|
4
11
|
|
5
12
|
## Installation
|
6
13
|
|
@@ -21,10 +28,26 @@ Or install it yourself as:
|
|
21
28
|
## Usage
|
22
29
|
|
23
30
|
```ruby
|
24
|
-
|
31
|
+
MQTTPipe.create do
|
25
32
|
on 'hello/world/#' do |message, id|
|
26
33
|
p message, id
|
27
34
|
end
|
35
|
+
|
36
|
+
open 'test.mosquitto.org', port: 1883 do
|
37
|
+
100.times do |i|
|
38
|
+
send "hello/world/#{i}", Time.now
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Everything does not need to be contained in a block:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
pipe = MQTTPipe.create
|
48
|
+
|
49
|
+
pipe.on 'hello/#' do
|
50
|
+
# do something
|
28
51
|
end
|
29
52
|
|
30
53
|
pipe.open 'test.mosquitto.org', port: 1883 do
|
@@ -34,6 +57,53 @@ pipe.open 'test.mosquitto.org', port: 1883 do
|
|
34
57
|
end
|
35
58
|
```
|
36
59
|
|
60
|
+
## Protocol
|
61
|
+
|
62
|
+
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:
|
63
|
+
|
64
|
+
Data type | Byte value (in hex)
|
65
|
+
------------------------- | -------------------
|
66
|
+
`0..127` | 0x00 - 0x7F
|
67
|
+
`Array` | 0x80 - 0x9F
|
68
|
+
`String` | 0xA0 - 0xBF
|
69
|
+
`Class` | 0xC0
|
70
|
+
`NilClass` | 0xC1
|
71
|
+
`FalseClass` | 0xC2
|
72
|
+
`TrueClass` | 0xC3
|
73
|
+
`8 bit unsigned` | 0xC4
|
74
|
+
`6 bit signed` | 0xC5
|
75
|
+
`32 bit signed` | 0xC6
|
76
|
+
`Float` | 0xC7
|
77
|
+
`Time` | 0xC8
|
78
|
+
`MQTTPipe::Types::Color` | 0xC9
|
79
|
+
- | 0xCA
|
80
|
+
- | 0xCB
|
81
|
+
- | 0xCC
|
82
|
+
- | 0xCD
|
83
|
+
- | 0xCE
|
84
|
+
- | 0xCF
|
85
|
+
`-48..-1` | 0xD0 - 0xFF
|
86
|
+
|
87
|
+
Note that the integers are split over several codes to accommodate for the various sizes that can occur. Because it is common to send small numerical values these can in most cases be represented by a single byte, instead of two.
|
88
|
+
|
89
|
+
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
|
+
#### Strings with length 1..31:
|
92
|
+
|
93
|
+
'test' -> [0xA0 + 4, 0x74, 0x65, 0x73, 0x74]
|
94
|
+
|
95
|
+
#### Strings with length 32..288
|
96
|
+
|
97
|
+
'testing how really long strings are encoded'
|
98
|
+
-> [0xA0, 43 - 32, 0x74, 0x65, 0x73, ...]
|
99
|
+
|
100
|
+
Some data types that may be supported in the future are:
|
101
|
+
|
102
|
+
- IP Addresses
|
103
|
+
- Hashes
|
104
|
+
- Strings longer than 288 characters
|
105
|
+
- UTF-8 encoded strings (could be a breaking change)
|
106
|
+
|
37
107
|
## Contributing
|
38
108
|
|
39
109
|
1. Fork it ( https://github.com/[my-github-username]/mqtt_pipe/fork )
|
data/lib/mqtt_pipe/packer.rb
CHANGED
@@ -22,6 +22,27 @@ module MQTTPipe
|
|
22
22
|
# Use the refinements made to the supported classes
|
23
23
|
|
24
24
|
using Types
|
25
|
+
|
26
|
+
|
27
|
+
##
|
28
|
+
# Checks whether a class or object is supported by the
|
29
|
+
# packer. For arrays each item is checked recursivly
|
30
|
+
|
31
|
+
def supports_type? type
|
32
|
+
if type.is_a? Class
|
33
|
+
type.to_packed
|
34
|
+
elsif type.is_a? Array
|
35
|
+
return type.detect{|obj| not supports_type? obj }.nil?
|
36
|
+
else
|
37
|
+
type.class.to_packed
|
38
|
+
end
|
39
|
+
return true
|
40
|
+
rescue NoMethodError
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
alias_method :supports?, :supports_type?
|
45
|
+
|
25
46
|
|
26
47
|
##
|
27
48
|
# Packs the arguments acording to their type.
|
@@ -58,6 +79,7 @@ module MQTTPipe
|
|
58
79
|
return result
|
59
80
|
end
|
60
81
|
|
82
|
+
|
61
83
|
##
|
62
84
|
# A simple helper method to read a given number of bytes
|
63
85
|
# +from+ IO object and format them +as+ anything
|
@@ -70,6 +92,7 @@ module MQTTPipe
|
|
70
92
|
raw.unpack(as).first
|
71
93
|
end
|
72
94
|
|
95
|
+
|
73
96
|
private
|
74
97
|
|
75
98
|
def unpack_single raw
|
data/lib/mqtt_pipe/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module MQTTPipe
|
2
|
-
VERSION = "0.0.
|
3
|
-
end
|
2
|
+
VERSION = "0.0.3"
|
3
|
+
end
|
data/spec/packer_spec.rb
CHANGED
@@ -3,6 +3,41 @@ require 'mqtt_pipe'
|
|
3
3
|
describe MQTTPipe::Packer do
|
4
4
|
let(:klass) { MQTTPipe::Packer }
|
5
5
|
|
6
|
+
describe '#supports_type?' do
|
7
|
+
it 'expects one argument' do
|
8
|
+
expect{klass.supports_type?}.to raise_error ArgumentError
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'When the type is supported' do
|
12
|
+
it 'returns true for integers' do
|
13
|
+
expect(klass.supports_type? Integer).to be true
|
14
|
+
expect(klass.supports_type? Fixnum).to be true
|
15
|
+
expect(klass.supports_type? 42).to be true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns true for strings' do
|
19
|
+
expect(klass.supports_type? String).to be true
|
20
|
+
expect(klass.supports_type? 'string').to be true
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns true for arrays containing supported types' do
|
24
|
+
expect(klass.supports_type? Array).to be true
|
25
|
+
expect(klass.supports_type? [42, 'string']).to be true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'When the type is not supported' do
|
30
|
+
it 'returns false for arbitrary classes/objects' do
|
31
|
+
expect(klass.supports_type? Regexp).to be false
|
32
|
+
expect(klass.supports_type? /regexp/).to be false
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns false for arrays containing unsupported objects' do
|
36
|
+
expect(klass.supports_type? [42, /regexp/]).to be false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
6
41
|
describe '#pack/#[]' do
|
7
42
|
describe 'Array' do
|
8
43
|
it 'serializes empty arrays to nil' do
|