fancybox2 0.0.1 → 0.0.6
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 +4 -180
- data/lib/fancybox2.rb +2 -0
- data/lib/fancybox2/core_ext/array.rb +2 -0
- data/lib/fancybox2/core_ext/hash.rb +2 -0
- data/lib/fancybox2/logger/json_formatter.rb +2 -0
- data/lib/fancybox2/logger/mqtt_log_device.rb +6 -1
- data/lib/fancybox2/logger/multi.rb +2 -0
- data/lib/fancybox2/module/base.rb +43 -37
- data/lib/fancybox2/module/config.rb +2 -0
- data/lib/fancybox2/module/exceptions.rb +2 -0
- data/lib/fancybox2/utils/os.rb +26 -26
- data/lib/fancybox2/version.rb +3 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88d9c51fb40eb09f50db57b7dd601e78f36dc27df736d3b801c331cf9b6ba62c
|
4
|
+
data.tar.gz: 7cb67a8d2d7894591dca8815f9aee65a809498405ad65fd2fc05e05d3af192f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 253c8254774761d441e39ef541038a86e6f4860db9fe5d7584565e7aa1641110247231a59cad0ae2304e5f9fe462a5f09fa2c62f8fb9ebe6aa0cc2a38834cf9f
|
7
|
+
data.tar.gz: ce444bf2a0f6eb8ce1148a17013a0419a50029c193b0a7f89423f768120fcddcd0f25acf2356154d4f75b9c277e265a1499a99fec3588124c1f3f086f3f34d60
|
data/README.md
CHANGED
@@ -2,188 +2,12 @@
|
|
2
2
|
<img width="480" src="assets/logo.png"/>
|
3
3
|
</p>
|
4
4
|
|
5
|
-
[](https://travis-ci.org/FancyPixel/fancybox2-ruby-sdk)
|
6
|
+
[](https://badge.fury.io/rb/fancybox2)
|
7
7
|
|
8
|
-
|
9
|
-
exchange messages with a server or even with each other. You can store the data, receive timely event notifications,
|
10
|
-
monitor live streams and remotely control your devices. Easy to use, and ready to scale at any time.
|
8
|
+
FancyPixel's FancyBox2 Ruby SDK for developing modules
|
11
9
|
|
12
|
-
|
13
|
-
Please feel free to contribute!
|
14
|
-
|
15
|
-
## Installation
|
16
|
-
|
17
|
-
Add this line to your application's Gemfile:
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
gem 'spacebunny'
|
21
|
-
```
|
22
|
-
|
23
|
-
And then execute:
|
24
|
-
|
25
|
-
$ bundle
|
26
|
-
|
27
|
-
Or install it yourself as:
|
28
|
-
|
29
|
-
$ gem install spacebunny
|
30
|
-
|
31
|
-
After you have signed up for a [SpaceBunny](http://spacebunny.io)'s account, follow the
|
32
|
-
[Getting Started](http://getting_started_link) guide for a one minute introduction to the platform concepts
|
33
|
-
and a super rapid setup.
|
34
|
-
|
35
|
-
This SDK provides Device and LiveStream clients and currently supports the AMQP protocol.
|
36
|
-
|
37
|
-
## Device - Basic usage
|
38
|
-
|
39
|
-
Pick a device, view its configurations and copy the Device Key. Instantiate a new `Spacebunny::Device` client,
|
40
|
-
providing the Device Key:
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
dev = Spacebunny::Device.new 'device_key'
|
44
|
-
```
|
45
|
-
|
46
|
-
the SDK will auto-configure, contacting [SpaceBunny APIs](http://doc.spacebunny.io/api) endpoint, retrieving the
|
47
|
-
connection configurations and required parameters. Nothing remains but to connect:
|
48
|
-
|
49
|
-
```ruby
|
50
|
-
dev.connect
|
51
|
-
```
|
52
|
-
|
53
|
-
### Publish
|
54
|
-
|
55
|
-
Ok, all set up! Let's publish some message:
|
56
|
-
|
57
|
-
```ruby
|
58
|
-
# We're assuming you have created a 'data' channel and you have enabled it for your device
|
59
|
-
|
60
|
-
# Let's publish, for instance, some JSON. Payload can be everything you want,
|
61
|
-
# SpaceBunny does not impose any constraint on format or content.
|
62
|
-
|
63
|
-
require 'json' # to convert our payload to JSON
|
64
|
-
|
65
|
-
# Publish one message every second for a minute.
|
66
|
-
60.times do
|
67
|
-
# Generate some random data
|
68
|
-
payload = { greetings: 'Hello, World!', temp: rand(20.0..25.0), foo: rand(100..200) }.to_json
|
69
|
-
|
70
|
-
# Publish
|
71
|
-
dev.publish :data, payload
|
72
|
-
|
73
|
-
# Give feedback on what has been published
|
74
|
-
puts "Published: #{payload}"
|
75
|
-
|
76
|
-
# Take a nap...
|
77
|
-
sleep 1
|
78
|
-
end
|
79
|
-
```
|
80
|
-
|
81
|
-
Let's check out that our data is really being sent by going to our web dashboard: navigate to devices, select the
|
82
|
-
device and click on 'LIVE DATA'. Select the 'data' channel from the dropdown and click **Start**.
|
83
|
-
Having published data as JSON allows SpaceBunny's web UI to parse them and visualize a nice
|
84
|
-
realtime graph: On the **Chart** tab write `temp` in the input field and press enter.
|
85
|
-
You'll see the graph of the `temp` parameter being rendered. If you want to plot more parameters,
|
86
|
-
just use a comma as separator e.g: temp, pressure, voltage
|
87
|
-
On the **Messages** tab you'll see raw messages' payloads received on this channel.
|
88
|
-
|
89
|
-
### Inbox
|
90
|
-
|
91
|
-
Waiting for and reading messages from the device's Inbox is trivial:
|
92
|
-
|
93
|
-
```ruby
|
94
|
-
dev.inbox(wait: true, ack: :auto) do |message|
|
95
|
-
puts "Received: #{message.payload}"
|
96
|
-
end
|
97
|
-
```
|
98
|
-
|
99
|
-
`wait` option (default false) causes the script to wait forever on the receive block
|
100
|
-
|
101
|
-
`ack` option can have two values: `:manual` (default) or `:auto`. When `:manual` you are responsible to ack the messages,
|
102
|
-
for instance:
|
103
|
-
|
104
|
-
```ruby
|
105
|
-
dev.inbox(wait: true, ack: :manual) do |message|
|
106
|
-
puts "Received: #{message.payload}"
|
107
|
-
# Manually ack the message
|
108
|
-
message.ack
|
109
|
-
end
|
110
|
-
```
|
111
|
-
This permits to handle errors or other critical situations
|
112
|
-
|
113
|
-
## Live Stream - Basic usage
|
114
|
-
|
115
|
-
For accessing a Live Stream a Live Stream Key's is required. On SpaceBunny's Web UI, go to the Streams section,
|
116
|
-
click on "Live Stream Keys" and pick or create one.
|
117
|
-
|
118
|
-
```ruby
|
119
|
-
live = Spacebunny::LiveStream.new client: 'live_stream_key_client', secret: 'live_stream_key_secret'
|
120
|
-
```
|
121
|
-
|
122
|
-
Similarly to the Device client, the SDK will auto-configure itself, contacting [SpaceBunny APIs](http://doc.spacebunny.io/api)
|
123
|
-
endpoint, retrieving the connection configurations and required parameters. Nothing remains but to connect:
|
124
|
-
|
125
|
-
```ruby
|
126
|
-
live.connect
|
127
|
-
```
|
128
|
-
|
129
|
-
### Reading live messages
|
130
|
-
|
131
|
-
Each LiveStream has its own cache that will keep always last 100 messages (FIFO, when there are more than 100 messages,
|
132
|
-
the oldest ones get discarded). If you want to consume messages in a parallel way, you shoul use the cache and connect
|
133
|
-
as many LiveStream clients as you need: this way messages will be equally distributed to clients.
|
134
|
-
|
135
|
-
```ruby
|
136
|
-
live.message_from_cache :some_live_stream, wait: true, ack: :auto do |message|
|
137
|
-
puts "Received from cache: #{message.payload}"
|
138
|
-
end
|
139
|
-
|
140
|
-
# An equivalent method is:
|
141
|
-
# live.message_from :some_live_stream, from_cache: true, wait: true, ack: :auto do |message|
|
142
|
-
# puts "Received from cache: #{message.payload}"
|
143
|
-
# end
|
144
|
-
```
|
145
|
-
|
146
|
-
Conversely, if you want that each client will receive a copy of each message, don't use the cache:
|
147
|
-
|
148
|
-
```ruby
|
149
|
-
live.message_from :some_live_stream, wait: true, ack: :auto do |message|
|
150
|
-
puts "Received a copy of: #{message.payload}"
|
151
|
-
end
|
152
|
-
```
|
153
|
-
|
154
|
-
Every client subscribed to the LiveStream in this way will receive a copy of the message.
|
155
|
-
|
156
|
-
## TLS
|
157
|
-
|
158
|
-
Instantiating a TLS-secured connection is trivial:
|
159
|
-
|
160
|
-
```ruby
|
161
|
-
# For a Device
|
162
|
-
|
163
|
-
dev = Spacebunny::Device.new key, tls: true
|
164
|
-
|
165
|
-
# Similarly, for a Live Stream
|
166
|
-
|
167
|
-
live = Spacebunny::LiveStream.new client, secret, tls: true
|
168
|
-
```
|
169
|
-
|
170
|
-
## More examples and options
|
171
|
-
|
172
|
-
Take a look at the ```examples``` directory for more code samples and further details about available options.
|
173
|
-
|
174
|
-
|
175
|
-
### Contributing
|
176
|
-
|
177
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/FancyPixel/spacebunny_ruby.
|
178
|
-
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere
|
179
|
-
to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
180
|
-
|
181
|
-
### Development
|
182
|
-
|
183
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests.
|
184
|
-
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
185
|
-
|
186
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
10
|
+
[FancyBox](https://www.fancypixel.it/fancybox-standard/)
|
187
11
|
|
188
12
|
### License
|
189
13
|
|
data/lib/fancybox2.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fancybox2
|
2
4
|
module Logger
|
3
5
|
class MQTTLogDevice
|
@@ -11,10 +13,13 @@ module Fancybox2
|
|
11
13
|
unless @client.respond_to?(:publish)
|
12
14
|
raise ArgumentError, "provided client does not respond to 'publish'"
|
13
15
|
end
|
16
|
+
unless @client.respond_to?(:connected?)
|
17
|
+
raise ArgumentError, "provided client does not respond to 'connected?'"
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
def write(message)
|
17
|
-
if @client.connected?
|
22
|
+
if @client && @client.connected?
|
18
23
|
@client.publish @topic, message
|
19
24
|
end
|
20
25
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'yaml'
|
3
5
|
require 'logger'
|
@@ -28,6 +30,7 @@ module Fancybox2
|
|
28
30
|
@logger = options.fetch :logger, create_default_logger
|
29
31
|
@status = :stopped
|
30
32
|
@alive_task = nil
|
33
|
+
@configs = {}
|
31
34
|
end
|
32
35
|
|
33
36
|
def alive_message_data(&block)
|
@@ -84,20 +87,15 @@ module Fancybox2
|
|
84
87
|
@on_configs = block
|
85
88
|
return
|
86
89
|
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
logger.debug 'on_configs: failed parsing packet as YAML. Falling back to raw payload'
|
97
|
-
# Fallback to original content
|
98
|
-
packet.payload
|
99
|
-
end
|
100
|
-
end
|
90
|
+
begin
|
91
|
+
cfg = packet.payload
|
92
|
+
if cfg && cfg.is_a?(Hash) && cfg['configs']
|
93
|
+
self.configs.merge! cfg['configs']
|
94
|
+
end
|
95
|
+
rescue JSON::ParserError
|
96
|
+
logger.debug 'on_configs: failed parsing packet as JSON'
|
97
|
+
end
|
98
|
+
|
101
99
|
@on_configs.call(packet) if @on_configs
|
102
100
|
end
|
103
101
|
|
@@ -140,6 +138,8 @@ module Fancybox2
|
|
140
138
|
return
|
141
139
|
end
|
142
140
|
|
141
|
+
@status = :on_shutdown
|
142
|
+
|
143
143
|
shutdown_ok = true
|
144
144
|
logger.debug "Received 'shutdown' command"
|
145
145
|
# Stop sending alive messages
|
@@ -160,17 +160,20 @@ module Fancybox2
|
|
160
160
|
message_to :core, :shutdown, { status: shutdown_message }
|
161
161
|
sleep 0.05 # Wait some time in order to be sure that the message has been published (message is not mandatory)
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
163
|
+
Thread.new do
|
164
|
+
if mqtt_client && mqtt_client.connected?
|
165
|
+
# Gracefully disconnect from broker and exit
|
166
|
+
logger.debug 'Disconnecting from broker, bye'
|
167
|
+
mqtt_client.disconnect
|
168
|
+
@mqtt_client = nil
|
169
|
+
end
|
168
170
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
171
|
+
if do_exit
|
172
|
+
# Exit from process
|
173
|
+
status_code = shutdown_ok ? 0 : 1
|
174
|
+
logger.debug "Exiting with status code #{status_code}"
|
175
|
+
exit status_code
|
176
|
+
end
|
174
177
|
end
|
175
178
|
end
|
176
179
|
|
@@ -186,8 +189,8 @@ module Fancybox2
|
|
186
189
|
# Call user code
|
187
190
|
@on_start.call(packet) if @on_start
|
188
191
|
|
189
|
-
|
190
|
-
interval =
|
192
|
+
cfg = packet ? packet.payload : {}
|
193
|
+
interval = cfg['aliveTimeout'] || 1000
|
191
194
|
# Start code execution from scratch
|
192
195
|
logger.debug "Received 'start'"
|
193
196
|
@status = :running
|
@@ -228,14 +231,17 @@ module Fancybox2
|
|
228
231
|
def start_sending_alive(interval: 5000)
|
229
232
|
# TODO: replace the alive interval task with Eventmachine?
|
230
233
|
# Interval is expected to be msec, so convert it to secs
|
231
|
-
interval /= 1000
|
234
|
+
interval /= 1000.0
|
232
235
|
@alive_task.shutdown if @alive_task
|
233
236
|
@alive_task = Concurrent::TimerTask.new(execution_interval: interval, timeout_interval: 2, run_now: true) do
|
234
|
-
packet = { status: @status, lastSeen: Time.now.utc }
|
235
|
-
|
236
|
-
packet[:data] =
|
237
|
+
packet = { status: @status, lastSeen: Time.now.utc, data: nil }
|
238
|
+
begin
|
239
|
+
packet[:data] = alive_message_data
|
240
|
+
message_to :core, :alive, packet
|
241
|
+
rescue StandardError => e
|
242
|
+
logger.error "Error in alive_message_data callback: #{e.message}"
|
243
|
+
logger.error e.backtrace.join "\n"
|
237
244
|
end
|
238
|
-
message_to :core, :alive, packet
|
239
245
|
end
|
240
246
|
@alive_task.execute
|
241
247
|
end
|
@@ -353,12 +359,12 @@ module Fancybox2
|
|
353
359
|
|
354
360
|
def create_default_logger
|
355
361
|
stdout_logger = ::Logger.new STDOUT
|
356
|
-
broker_logger = ::Logger.new(Logger::MQTTLogDevice.new(topic_for(dest: :core, action: :logs),
|
357
|
-
|
358
|
-
|
359
|
-
logger = Logger::Multi.new stdout_logger
|
360
|
-
|
361
|
-
|
362
|
+
# broker_logger = ::Logger.new(Logger::MQTTLogDevice.new(topic_for(dest: :core, action: :logs),
|
363
|
+
# client: mqtt_client),
|
364
|
+
# formatter: Logger::JSONFormatter.new)
|
365
|
+
logger = Logger::Multi.new stdout_logger,# broker_logger,
|
366
|
+
level: @log_level,
|
367
|
+
progname: @log_progname
|
362
368
|
logger
|
363
369
|
end
|
364
370
|
|
data/lib/fancybox2/utils/os.rb
CHANGED
@@ -4,34 +4,34 @@ module Fancybox2
|
|
4
4
|
extend self
|
5
5
|
|
6
6
|
def identifier
|
7
|
-
return @
|
7
|
+
return @identifier if @identifier
|
8
8
|
|
9
9
|
host_os = RbConfig::CONFIG['host_os']
|
10
|
-
case host_os
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
10
|
+
@identifier = case host_os
|
11
|
+
when /aix(.+)$/
|
12
|
+
'aix'
|
13
|
+
when /darwin(.+)$/
|
14
|
+
'darwin'
|
15
|
+
when /linux/
|
16
|
+
'linux'
|
17
|
+
when /freebsd(.+)$/
|
18
|
+
'freebsd'
|
19
|
+
when /openbsd(.+)$/
|
20
|
+
'openbsd'
|
21
|
+
when /netbsd(.*)$/
|
22
|
+
'netbsd'
|
23
|
+
when /dragonfly(.*)$/
|
24
|
+
'dragonflybsd'
|
25
|
+
when /solaris2/
|
26
|
+
'solaris2'
|
27
|
+
when /mswin|mingw32|windows/
|
28
|
+
# No Windows platform exists that was not based on the Windows_NT kernel,
|
29
|
+
# so 'windows' refers to all platforms built upon the Windows_NT kernel and
|
30
|
+
# have access to win32 or win64 subsystems.
|
31
|
+
'windows'
|
32
|
+
else
|
33
|
+
host_os
|
34
|
+
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/fancybox2/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fancybox2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Verlato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: paho-mqtt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.12
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.12
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: concurrent-ruby
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|