ardtweeno 0.4.0 → 0.5.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/CHANGELOG +24 -0
- data/Gemfile.lock +22 -33
- data/lib/ardtweeno/api.rb +9 -4
- data/lib/ardtweeno/dispatcher.rb +5 -4
- data/lib/ardtweeno/nodemanager.rb +13 -1
- data/lib/ardtweeno/restapi.rb +46 -34
- data/lib/ardtweeno.rb +1 -1
- data/public/main.css +10 -0
- data/public/main.js +0 -4
- data/test/debug/run_mock +1 -1
- data/test/debug/run_packet_push +2 -2
- data/test/debug/run_post_watch +3 -3
- data/test/debug/tty0tty-1.1/pts/tty0tty +0 -0
- data/test/rest_api_test.rb +15 -13
- data/views/api.erb +252 -0
- data/views/index.erb +1 -0
- data/views/status.erb +4 -1
- metadata +32 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53873386c274f4259d283b97c153f7edeb1649a7
|
4
|
+
data.tar.gz: 9bec1a6d15af011369aa6b7e59c1e64ce3df77d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9036d28f3317a76cc2a1ef61f7106916536507babf822a1b458ca7da206b9863e3c385ef01e803c358f43b3a9e4623d0e2ce2f79e4401affc24cd6b2f656e91f
|
7
|
+
data.tar.gz: df69ac9c1589916f2b9450327a93d99d415b0d3b0bac67484d0e1e035be36792501621dae198d9882bf96f531dfd43926a3e11b72214abbd95e127ea6829ae63
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
## Version 0.5.0
|
2
|
+
- Push notification cooloff periods are now respected. fixes #38
|
3
|
+
- /api/v1/system/start stop and config endpoints only respond to the Admin apikey
|
4
|
+
- Updated each REST API endpoint with the latest Ardtweeno::Dispatcher#authenticate? calls
|
5
|
+
- Resolved bug with /api/v1/zones and /api/v1/zones/:zonename endpoints responding with admin responses when using zoneapi keys - Refs #35
|
6
|
+
- Refactored /api/v1/zones and /api/v1/zones/:zonename to only return zone info as authorised by the API key
|
7
|
+
- Updated test fixtures to reflect this change - References #35
|
8
|
+
- Fixed failing tests related to changes made towards fixing #35
|
9
|
+
- Slightly refactored response generated by Ardtweeno::Dispatcher#authenticate? Refs #35
|
10
|
+
- Updated authentication around the /api/v1/zone endpoints to only return data related to that particular zone. Refs #35
|
11
|
+
- Switching between tabs no longer initiates a new setTimeout() to refresh the statuslist graph. Fixes #39
|
12
|
+
- /api/v1/system/start and /api/v1/system/stop endpoints now return JSON responses
|
13
|
+
- Updated tests to take account for the endpoint changes - Fixes #37
|
14
|
+
- Updated public/main.css to style the API table specification in /api view
|
15
|
+
- Implemented HTTP REST API specification in the /api view. Fixes
|
16
|
+
- Removed the /api/v1/system/reboot endpoint. - Fixes #10 - Fixes #34
|
17
|
+
- Resolved issue with the sort parameter edgecases previously not spotted. Fixes #36
|
18
|
+
- Updated restapi.rb to include the /api endpoint which will display the Ardtweeno API specification once fully implemented
|
19
|
+
- Updated index.erb to include a new API tab which points at the /api endpoint - Added an api.erb view which will hold the HTTP REST API specification for the gateway - Refs #34
|
20
|
+
- Removed rufus scheduler from the dependencies, and the codebase.
|
21
|
+
- Updated gemspec to 0.4.0
|
22
|
+
- Added flot library JS files
|
23
|
+
- Release 0.4.0 Changelog
|
24
|
+
|
1
25
|
## Version 0.4.0
|
2
26
|
- Implemented status graph using the flot.js library. Fixes #28
|
3
27
|
- Implemented disk utility df parser - Table in /status endpoint now populated with disk usage data. Fixes #23
|
data/Gemfile.lock
CHANGED
@@ -4,68 +4,57 @@ GEM
|
|
4
4
|
ardtweeno (0.4.0)
|
5
5
|
bson_ext (>= 1.6.2)
|
6
6
|
bundler (>= 1.2.3)
|
7
|
-
foreman (>= 0.63.0)
|
8
7
|
mongo (>= 1.6.2)
|
9
|
-
rufus-scheduler (>= 2.0.0)
|
10
8
|
sinatra (>= 1.3.3)
|
11
9
|
thin (>= 1.5.0)
|
12
10
|
typhoeus (>= 0.6.3)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
bson (~> 1.9.2)
|
11
|
+
bson (1.10.0)
|
12
|
+
bson_ext (1.10.0)
|
13
|
+
bson (~> 1.10.0)
|
17
14
|
daemons (1.1.9)
|
18
|
-
diff-lcs (1.2.
|
19
|
-
dotenv (0.
|
20
|
-
ethon (0.
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
dotenv (0.10.0)
|
17
|
+
ethon (0.7.0)
|
21
18
|
ffi (>= 1.3.0)
|
22
|
-
mime-types (~> 1.18)
|
23
19
|
eventmachine (1.0.3)
|
24
|
-
ffi (1.9.
|
20
|
+
ffi (1.9.3)
|
25
21
|
foreman (0.63.0)
|
26
22
|
dotenv (>= 0.7)
|
27
23
|
thor (>= 0.13.6)
|
28
24
|
json (1.8.1)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
nokogiri (1.6.0)
|
25
|
+
mini_portile (0.5.3)
|
26
|
+
mongo (1.10.0)
|
27
|
+
bson (~> 1.10.0)
|
28
|
+
nokogiri (1.6.1)
|
34
29
|
mini_portile (~> 0.5.0)
|
35
30
|
rack (1.5.2)
|
36
|
-
rack-protection (1.5.
|
31
|
+
rack-protection (1.5.2)
|
37
32
|
rack
|
38
33
|
rack-test (0.6.2)
|
39
34
|
rack (>= 1.0)
|
40
|
-
rake (10.
|
35
|
+
rake (10.2.2)
|
41
36
|
rspec (2.14.1)
|
42
37
|
rspec-core (~> 2.14.0)
|
43
38
|
rspec-expectations (~> 2.14.0)
|
44
39
|
rspec-mocks (~> 2.14.0)
|
45
|
-
rspec-core (2.14.
|
46
|
-
rspec-expectations (2.14.
|
40
|
+
rspec-core (2.14.8)
|
41
|
+
rspec-expectations (2.14.5)
|
47
42
|
diff-lcs (>= 1.1.3, < 2.0)
|
48
|
-
rspec-mocks (2.14.
|
49
|
-
|
50
|
-
tzinfo
|
51
|
-
serialport (1.2.1)
|
43
|
+
rspec-mocks (2.14.6)
|
44
|
+
serialport (1.3.0)
|
52
45
|
sinatra (1.4.4)
|
53
46
|
rack (~> 1.4)
|
54
47
|
rack-protection (~> 1.4)
|
55
48
|
tilt (~> 1.3, >= 1.3.4)
|
56
49
|
test-unit (2.5.5)
|
57
|
-
thin (1.6.
|
50
|
+
thin (1.6.2)
|
58
51
|
daemons (>= 1.0.9)
|
59
52
|
eventmachine (>= 1.0.0)
|
60
|
-
rack (>= 1.
|
61
|
-
thor (0.
|
62
|
-
thread_safe (0.1.3)
|
63
|
-
atomic
|
53
|
+
rack (>= 1.0.0)
|
54
|
+
thor (0.19.1)
|
64
55
|
tilt (1.4.1)
|
65
|
-
typhoeus (0.6.
|
66
|
-
ethon (
|
67
|
-
tzinfo (1.1.0)
|
68
|
-
thread_safe (~> 0.1)
|
56
|
+
typhoeus (0.6.8)
|
57
|
+
ethon (>= 0.7.0)
|
69
58
|
|
70
59
|
PLATFORMS
|
71
60
|
ruby
|
data/lib/ardtweeno/api.rb
CHANGED
@@ -191,8 +191,8 @@ module Ardtweeno
|
|
191
191
|
containerArray = Array.new
|
192
192
|
|
193
193
|
theArray.each do |i|
|
194
|
-
# Found the
|
195
|
-
if i[:zonename] == theParams[:zonename]
|
194
|
+
# Found the zone required
|
195
|
+
if i[:zonename] == theParams[:zonename] or theParams[:role] == "admin"
|
196
196
|
containerArray << i
|
197
197
|
end
|
198
198
|
end
|
@@ -520,8 +520,13 @@ module Ardtweeno
|
|
520
520
|
@log.debug "handleSort function executing"
|
521
521
|
|
522
522
|
if theParams.has_key?(:sort) and theParams[:sort] == "desc"
|
523
|
-
|
524
|
-
|
523
|
+
begin
|
524
|
+
|
525
|
+
theArray = theArray.sort_by {|x| x.seqNo}
|
526
|
+
return theArray.reverse()
|
527
|
+
rescue Exception => e
|
528
|
+
return theArray.reverse()
|
529
|
+
end
|
525
530
|
|
526
531
|
else
|
527
532
|
return theArray # Order is already ascending, return original array
|
data/lib/ardtweeno/dispatcher.rb
CHANGED
@@ -630,18 +630,19 @@ module Ardtweeno
|
|
630
630
|
# - true/false
|
631
631
|
# * *Raises* :
|
632
632
|
#
|
633
|
-
def authenticate?(key)
|
633
|
+
def authenticate?(key)
|
634
634
|
if key == @confdata["adminkey"]
|
635
|
-
return true
|
635
|
+
return true, {:role=>"admin"}
|
636
636
|
else
|
637
637
|
|
638
638
|
@confdata["zones"].each do |i|
|
639
639
|
if i["zonekey"] == key
|
640
|
-
|
640
|
+
i[:role] = "zone"
|
641
|
+
return true, i
|
641
642
|
end
|
642
643
|
end
|
643
644
|
|
644
|
-
return false
|
645
|
+
return false, {}
|
645
646
|
end
|
646
647
|
end
|
647
648
|
|
@@ -297,9 +297,19 @@ module Ardtweeno
|
|
297
297
|
@log.debug "Comparing " + i[:node] + " to " + node
|
298
298
|
|
299
299
|
if i[:node] == node
|
300
|
+
@log.debug "Ensuring the timeout cooloff period is respected"
|
301
|
+
now = Time.now.to_i
|
300
302
|
|
301
|
-
|
303
|
+
if i.has_key?(:last_push)
|
304
|
+
timeout = i[:last_push] + i[:timeout].to_i
|
305
|
+
|
306
|
+
if timeout > now
|
307
|
+
@log.debug "We are within the cooloff period, ignoring the push notification"
|
308
|
+
return
|
309
|
+
end
|
310
|
+
end
|
302
311
|
|
312
|
+
@log.debug "Associated watch found, checking for method " + i[:method]
|
303
313
|
if i[:method] == "POST"
|
304
314
|
@log.debug "HTTP POST method executing"
|
305
315
|
Typhoeus::Request.post(i[:notifyURL],
|
@@ -313,6 +323,8 @@ module Ardtweeno
|
|
313
323
|
:content=>"#{i[:node]}",
|
314
324
|
:code=>""})
|
315
325
|
end
|
326
|
+
|
327
|
+
i[:last_push] = now
|
316
328
|
|
317
329
|
end
|
318
330
|
end
|
data/lib/ardtweeno/restapi.rb
CHANGED
@@ -116,6 +116,11 @@ class RESTAPI < Sinatra::Base
|
|
116
116
|
end
|
117
117
|
|
118
118
|
|
119
|
+
get '/api' do
|
120
|
+
erb :api
|
121
|
+
end
|
122
|
+
|
123
|
+
|
119
124
|
get '/graph/v1/punchcard/:node' do |node|
|
120
125
|
begin
|
121
126
|
theData, theDays, theRange= @@theDispatcher.constructPunchcard(params)
|
@@ -164,8 +169,14 @@ class RESTAPI < Sinatra::Base
|
|
164
169
|
|
165
170
|
|
166
171
|
get '/api/v1/zones' do
|
167
|
-
|
172
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
173
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
168
174
|
settings.log.debug "The retrieve zones hook has been called"
|
175
|
+
|
176
|
+
unless zonedata.nil?
|
177
|
+
params["role"] = zonedata[:role]
|
178
|
+
unless params.has_key?("zonename") then params["zonename"] = zonedata["zonename"]; end
|
179
|
+
end
|
169
180
|
|
170
181
|
begin
|
171
182
|
@@theDispatcher.retrieve_zones(params).to_json # Returns String in JSON form
|
@@ -175,9 +186,14 @@ class RESTAPI < Sinatra::Base
|
|
175
186
|
end
|
176
187
|
|
177
188
|
|
178
|
-
get '/api/v1/zones/:zonename' do |
|
179
|
-
|
189
|
+
get '/api/v1/zones/:zonename' do |zonename|
|
190
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
191
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
180
192
|
settings.log.debug "The retrieve zones hook has been called"
|
193
|
+
|
194
|
+
unless zonedata.nil?
|
195
|
+
params["role"] = zonedata[:role]
|
196
|
+
end
|
181
197
|
|
182
198
|
begin
|
183
199
|
@@theDispatcher.retrieve_zones(params).to_json # Returns String in JSON form
|
@@ -191,7 +207,8 @@ class RESTAPI < Sinatra::Base
|
|
191
207
|
|
192
208
|
|
193
209
|
get '/api/v1/packets' do
|
194
|
-
|
210
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
211
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
195
212
|
settings.log.debug "The retrieve packets hook has been called"
|
196
213
|
|
197
214
|
begin
|
@@ -203,7 +220,8 @@ class RESTAPI < Sinatra::Base
|
|
203
220
|
|
204
221
|
|
205
222
|
post '/api/v1/packets' do
|
206
|
-
|
223
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
224
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
207
225
|
settings.log.debug "The add packets hook has been called"
|
208
226
|
|
209
227
|
settings.log.debug "Add packet API request: " + params[:payload]
|
@@ -221,13 +239,15 @@ class RESTAPI < Sinatra::Base
|
|
221
239
|
#########################################################################################################
|
222
240
|
|
223
241
|
get '/api/v1/nodes' do
|
224
|
-
|
242
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
243
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
225
244
|
settings.log.debug "The retrieve nodes hook has been called"
|
226
245
|
|
227
246
|
begin
|
228
247
|
@@theDispatcher.retrieve_nodes(params).to_json # Returns String in JSON form
|
229
248
|
rescue Exception => e
|
230
|
-
|
249
|
+
raise e
|
250
|
+
#throw :halt, [ 500, "500 Internal Server Error" ]
|
231
251
|
end
|
232
252
|
end
|
233
253
|
|
@@ -235,8 +255,8 @@ class RESTAPI < Sinatra::Base
|
|
235
255
|
#########################################################################################################
|
236
256
|
|
237
257
|
post '/api/v1/watch/:node' do |node|
|
238
|
-
|
239
|
-
throw :halt, [ 404, "404 Page Not Found" ] unless
|
258
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
259
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
240
260
|
settings.log.debug "The add watch to node hook has been called"
|
241
261
|
|
242
262
|
begin
|
@@ -248,8 +268,8 @@ class RESTAPI < Sinatra::Base
|
|
248
268
|
|
249
269
|
|
250
270
|
get '/api/v1/watch/:node' do |node|
|
251
|
-
|
252
|
-
throw :halt, [ 404, "404 Page Not Found" ] unless
|
271
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
272
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
253
273
|
settings.log.debug "Check if a node is being watched"
|
254
274
|
|
255
275
|
begin
|
@@ -261,8 +281,8 @@ class RESTAPI < Sinatra::Base
|
|
261
281
|
|
262
282
|
|
263
283
|
get '/api/v1/watch' do
|
264
|
-
|
265
|
-
throw :halt, [ 404, "404 Page Not Found" ] unless
|
284
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
285
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
266
286
|
settings.log.debug "Check if a node is being watched"
|
267
287
|
|
268
288
|
begin
|
@@ -276,7 +296,9 @@ class RESTAPI < Sinatra::Base
|
|
276
296
|
#########################################################################################################
|
277
297
|
|
278
298
|
get '/api/v1/system/config' do
|
279
|
-
|
299
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
300
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
301
|
+
throw :halt, [ 401, "401 Not Authorised" ] unless zonedata[:role] == "admin"
|
280
302
|
settings.log.debug "The system config hook has been called, querying the Ardtweeno gateway to retrieve config"
|
281
303
|
|
282
304
|
begin
|
@@ -289,46 +311,36 @@ class RESTAPI < Sinatra::Base
|
|
289
311
|
|
290
312
|
|
291
313
|
get '/api/v1/system/start' do
|
292
|
-
|
314
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
315
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
316
|
+
throw :halt, [ 401, "401 Not Authorised" ] unless zonedata[:role] == "admin"
|
293
317
|
settings.log.debug "The system start hook has been called, launching the Ardtweeno system"
|
294
318
|
|
295
319
|
begin
|
296
|
-
@@theDispatcher.start
|
320
|
+
theResponse = @@theDispatcher.start
|
297
321
|
rescue Exception => e
|
298
322
|
throw :halt, [ 500, "500 Internal Server Error" ]
|
299
323
|
end
|
300
324
|
|
301
|
-
|
325
|
+
return {:response=>theResponse, :running=>@@theDispatcher.running?}.to_json
|
302
326
|
end
|
303
327
|
|
304
328
|
|
305
329
|
get '/api/v1/system/stop' do
|
306
|
-
|
330
|
+
auth, zonedata = @@theDispatcher.authenticate?(params[:key])
|
331
|
+
throw :halt, [ 404, "404 Page Not Found" ] unless auth
|
332
|
+
throw :halt, [ 401, "401 Not Authorised" ] unless zonedata[:role] == "admin"
|
307
333
|
settings.log.debug "The system stop hook has been called, shutting the Ardtweeno system down..."
|
308
334
|
|
309
335
|
begin
|
310
|
-
@@theDispatcher.stop
|
336
|
+
theResponse = @@theDispatcher.stop
|
311
337
|
rescue Exception => e
|
312
338
|
throw :halt, [ 500, "500 Internal Server Error" ]
|
313
339
|
end
|
314
340
|
|
315
|
-
|
341
|
+
return {:response=>theResponse, :running=>@@theDispatcher.running?}.to_json
|
316
342
|
end
|
317
343
|
|
318
|
-
|
319
|
-
# This is currently not implemented correctly
|
320
|
-
get '/api/v1/system/reboot' do
|
321
|
-
throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
|
322
|
-
settings.log.debug "The system reboot hook has been called, rebooting the host"
|
323
|
-
|
324
|
-
begin
|
325
|
-
@@theDispatcher.reboot
|
326
|
-
rescue Exception => e
|
327
|
-
throw :halt, [ 500, "500 Internal Server Error" ]
|
328
|
-
end
|
329
|
-
|
330
|
-
"The host is rebooting, this will take a moment..."
|
331
|
-
end
|
332
344
|
|
333
345
|
|
334
346
|
get '/api/v1/system/status' do
|
data/lib/ardtweeno.rb
CHANGED
@@ -31,7 +31,7 @@ module Ardtweeno
|
|
31
31
|
|
32
32
|
|
33
33
|
# Constants
|
34
|
-
Ardtweeno::VERSION = "0.
|
34
|
+
Ardtweeno::VERSION = "0.5.0" unless defined? Ardtweeno::VERSION
|
35
35
|
Ardtweeno::CONFIGPATH = ENV['HOME'] + "/.ardtweeno" unless defined? Ardtweeno::CONFIGPATH
|
36
36
|
Ardtweeno::DBPATH = Ardtweeno::CONFIGPATH + "/conf.yaml" unless defined? Ardtweeno::DBPATH
|
37
37
|
Ardtweeno::NODEPATH = Ardtweeno::CONFIGPATH + "/nodelist.yaml" unless defined? Ardtweeno::NODEPATH
|
data/public/main.css
CHANGED
@@ -528,3 +528,13 @@ table th[class*="span"],
|
|
528
528
|
.legend table {
|
529
529
|
border-spacing: 5px;
|
530
530
|
}
|
531
|
+
|
532
|
+
|
533
|
+
#apitable td, th { font: 12px Verdana,sans-serif; color: #444; }
|
534
|
+
#apitable td.path { font-family: monospace; }
|
535
|
+
#apitable th { font-size 1em; font-weight: bold; }
|
536
|
+
#apitable table { background: #F0F0F0; border-collapse: collapse; }
|
537
|
+
#apitable table th, table td { vertical-align: top; border: 1px solid #bbb; padding: 5px; }
|
538
|
+
#apitable code { background: #ffa; }
|
539
|
+
#apitable pre { background: black; color: #0f0; padding: 10px; word-wrap: break-word;}
|
540
|
+
#apitable table pre { background: #ffa; color: black; }
|
data/public/main.js
CHANGED
data/test/debug/run_mock
CHANGED
data/test/debug/run_packet_push
CHANGED
@@ -8,7 +8,7 @@ while true
|
|
8
8
|
testData2 = {"data" => [rand(0..100), rand(0..1000)], "key" => "a46fe0c4dab0453f5d86bed6206040880f59393e"}.to_json
|
9
9
|
|
10
10
|
puts Typhoeus::Request.post("http://localhost:4567/api/v1/packets", :body=> {:key => key, :payload=>testData})
|
11
|
-
sleep(rand(0..
|
11
|
+
sleep(rand(0..90))
|
12
12
|
puts Typhoeus::Request.post("http://localhost:4567/api/v1/packets", :body=> {:key => key, :payload=>testData2})
|
13
|
-
sleep(rand(0.
|
13
|
+
sleep(rand(0.90))
|
14
14
|
end
|
data/test/debug/run_post_watch
CHANGED
@@ -5,8 +5,8 @@ require 'json'
|
|
5
5
|
|
6
6
|
body = {:key=> "1230aea77d7bd38898fec74a75a87738dea9f657",
|
7
7
|
# :node=>"node1",
|
8
|
-
:notifyURL=>"http://
|
8
|
+
:notifyURL=>"http://192.168.1.2:5000/push/node1",
|
9
9
|
:method=>"GET",
|
10
|
-
:timeout=>60}
|
10
|
+
:timeout=>"60"}
|
11
11
|
|
12
|
-
puts Typhoeus::Request.post("http://
|
12
|
+
puts Typhoeus::Request.post("http://192.168.1.14:4567/api/v1/watch/node1", :body=>body)
|
Binary file
|
data/test/rest_api_test.rb
CHANGED
@@ -104,28 +104,28 @@ class RESTAPITest < Test::Unit::TestCase
|
|
104
104
|
|
105
105
|
# Test retrieval of zones
|
106
106
|
def test_retrieve_zones
|
107
|
-
get "/api/v1/zones", params={:
|
107
|
+
get "/api/v1/zones", params={:key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
108
108
|
json = JSON.parse(last_response.body)
|
109
109
|
|
110
|
-
assert_equal(
|
110
|
+
assert_equal(2, json["found"])
|
111
111
|
assert_equal(2, json["total"])
|
112
112
|
|
113
113
|
get "/api/v1/zones", params={:zonename=>"testzonez", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
114
114
|
json = JSON.parse(last_response.body)
|
115
|
-
assert_equal(
|
115
|
+
assert_equal(2, json["found"])
|
116
116
|
assert_equal(2, json["total"])
|
117
117
|
|
118
|
-
get "/api/v1/zones", params={:key=>"
|
118
|
+
get "/api/v1/zones", params={:key=>"455a807bb34b1976bac820b07c263ee81bd267cc"}
|
119
119
|
json = JSON.parse(last_response.body)
|
120
|
-
assert_equal(
|
120
|
+
assert_equal(1, json["found"])
|
121
121
|
assert_equal(2, json["total"])
|
122
122
|
|
123
|
-
get "/api/v1/zones/testzone0", params={:
|
123
|
+
get "/api/v1/zones/testzone0", params={:key=>"455a807bb34b1976bac820b07c263ee81bd267cc"}
|
124
124
|
json = JSON.parse(last_response.body)
|
125
125
|
assert_equal(1, json["found"])
|
126
126
|
assert_equal(2, json["total"])
|
127
127
|
|
128
|
-
get "/api/v1/zones/testzonez", params={:
|
128
|
+
get "/api/v1/zones/testzonez", params={:key=>"79a7c75758879243418fe2c87ec7d5d4e1451129"}
|
129
129
|
json = JSON.parse(last_response.body)
|
130
130
|
assert_equal(0, json["found"])
|
131
131
|
assert_equal(2, json["total"])
|
@@ -232,24 +232,26 @@ class RESTAPITest < Test::Unit::TestCase
|
|
232
232
|
# Test the system start parser command
|
233
233
|
def test_system_start
|
234
234
|
get "/api/v1/system/start", params={:node=>"node1", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
235
|
-
assert_equal("
|
235
|
+
assert_equal('{"response":true,"running":true}', last_response.body)
|
236
236
|
assert last_response.ok?
|
237
237
|
|
238
238
|
# Test call with invalid key fails
|
239
|
-
get "/api/v1/system/start", params={:node=>"node1", :key=>"
|
240
|
-
|
239
|
+
get "/api/v1/system/start", params={:node=>"node1", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
240
|
+
assert_equal('{"response":false,"running":true}', last_response.body)
|
241
|
+
assert last_response.ok?
|
241
242
|
end
|
242
243
|
|
243
244
|
|
244
245
|
# Test the system stop parser command
|
245
246
|
def test_system_stop
|
246
247
|
get "/api/v1/system/stop", params={:node=>"node1", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
247
|
-
assert_equal("
|
248
|
+
assert_equal('{"response":true,"running":false}', last_response.body)
|
248
249
|
assert last_response.ok?
|
249
250
|
|
250
251
|
# Test call with invalid key fails
|
251
|
-
get "/api/v1/system/stop", params={:node=>"node1", :key=>"
|
252
|
-
|
252
|
+
get "/api/v1/system/stop", params={:node=>"node1", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
|
253
|
+
assert_equal('{"response":false,"running":false}', last_response.body)
|
254
|
+
assert last_response.ok?
|
253
255
|
end
|
254
256
|
|
255
257
|
|
data/views/api.erb
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
<p id="blurb">
|
2
|
+
Ardtweeno Gateway HTTP REST API specification. For more information see <a href="https://github.com/davidkirwan/ardtweeno/wiki/API">here</a>
|
3
|
+
</p>
|
4
|
+
|
5
|
+
<div id="apitable">
|
6
|
+
<table>
|
7
|
+
<tbody>
|
8
|
+
<tr>
|
9
|
+
<th>GET</th>
|
10
|
+
<th>PUT</th>
|
11
|
+
<th>DELETE</th>
|
12
|
+
<th>POST</th>
|
13
|
+
<th>Path</th>
|
14
|
+
<th>Description</th>
|
15
|
+
</tr>
|
16
|
+
<tr>
|
17
|
+
<td>X</td>
|
18
|
+
<td>X</td>
|
19
|
+
<td>X</td>
|
20
|
+
<td>X</td>
|
21
|
+
<td class="path">Common to all endpoints:</td>
|
22
|
+
<td>
|
23
|
+
Parameters:
|
24
|
+
<ul>
|
25
|
+
<li>sort the result set, defaults to asc<code>/api/v1/packets?sort=(desc or asc)</code></li>
|
26
|
+
<li>offset the result set, by the passed integer number<code>/api/v1/packets?offset=(positive and negative work)</code></li>
|
27
|
+
<li>length the result set, is limited to only return the first integer number of results. Max of 200<code>/api/v1/packets?length=(positive integer)</code></li>
|
28
|
+
</ul>
|
29
|
+
</td>
|
30
|
+
</tr>
|
31
|
+
<tr>
|
32
|
+
<td>X</td>
|
33
|
+
<td></td>
|
34
|
+
<td></td>
|
35
|
+
<td></td>
|
36
|
+
<td class="path">/api/v1/nodes</td>
|
37
|
+
<td>
|
38
|
+
Retrieve a list of Nodes and authenticate with API Key:
|
39
|
+
<pre>/api/v1/nodes?key=0dfdFFeeDx</pre>
|
40
|
+
The following Parameters are respected:
|
41
|
+
<ul>
|
42
|
+
<li>name</li>
|
43
|
+
<li>nodekey</li>
|
44
|
+
<li>nodename</li>
|
45
|
+
</ul>
|
46
|
+
Typical response from the gateway:
|
47
|
+
<code>
|
48
|
+
<pre>
|
49
|
+
{
|
50
|
+
"nodes": [
|
51
|
+
{
|
52
|
+
"name": "node0",
|
53
|
+
"key": "500d81aafe637717a52f8650e54206e64da33d27",
|
54
|
+
"description": "This node has a temperature sensor",
|
55
|
+
"version": "0.2.1",
|
56
|
+
"sensors": [
|
57
|
+
"Temperature"
|
58
|
+
],
|
59
|
+
"packets": 0
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"name": "node1",
|
63
|
+
"key": "f937c37e949d9efa20d2958af309235c73ec039a",
|
64
|
+
"description": "This node has a movement sensor",
|
65
|
+
"version": "0.2.1",
|
66
|
+
"sensors": [
|
67
|
+
"Movement"
|
68
|
+
],
|
69
|
+
"packets": 0
|
70
|
+
}
|
71
|
+
],
|
72
|
+
"total": 2,
|
73
|
+
"found": 2
|
74
|
+
}
|
75
|
+
</pre>
|
76
|
+
</code>
|
77
|
+
</td>
|
78
|
+
</tr>
|
79
|
+
<tr>
|
80
|
+
<td>X</td>
|
81
|
+
<td></td>
|
82
|
+
<td></td>
|
83
|
+
<td>X</td>
|
84
|
+
<td class="path">/api/v1/packets</td>
|
85
|
+
<td>
|
86
|
+
Retrieve a list of packets and authenticate with API Key:
|
87
|
+
<pre>/api/v1/packets?key=0dfdFFeeDx</pre>
|
88
|
+
The following parameters are respected:
|
89
|
+
<ul>
|
90
|
+
<li>node</li>
|
91
|
+
<li>seqno</li>
|
92
|
+
<li>hour</li>
|
93
|
+
<li>minute</li>
|
94
|
+
<li>date</li>
|
95
|
+
</ul>
|
96
|
+
Typical response from the gateway:
|
97
|
+
<code>
|
98
|
+
<pre>
|
99
|
+
{
|
100
|
+
"packets": [
|
101
|
+
{
|
102
|
+
"date": "2013-11-11",
|
103
|
+
"hour": "22",
|
104
|
+
"minute": "04",
|
105
|
+
"node": "node0",
|
106
|
+
"key": "500d81aafe637717a52f8650e54206e64da33d27",
|
107
|
+
"seqNo": 0,
|
108
|
+
"data": [
|
109
|
+
13
|
110
|
+
]
|
111
|
+
}
|
112
|
+
],
|
113
|
+
"total": 1,
|
114
|
+
"found": 1
|
115
|
+
}
|
116
|
+
</pre>
|
117
|
+
</code>
|
118
|
+
</td>
|
119
|
+
</tr>
|
120
|
+
<tr>
|
121
|
+
<td>X</td>
|
122
|
+
<td></td>
|
123
|
+
<td></td>
|
124
|
+
<td></td>
|
125
|
+
<td class="path">/api/v1/zones</td>
|
126
|
+
<td>
|
127
|
+
Retrieve a list of zones and authenticate with API Key:
|
128
|
+
<pre>/api/v1/zones?key=0dfdFFeeDx</pre>
|
129
|
+
The following parameters are respected:
|
130
|
+
<ul>
|
131
|
+
<li>zonename</li>
|
132
|
+
</ul>
|
133
|
+
Typical response from the gateway:
|
134
|
+
<code>
|
135
|
+
<pre>
|
136
|
+
{
|
137
|
+
"zones": [
|
138
|
+
{
|
139
|
+
"zonename": "testzone1",
|
140
|
+
"key": "79a7c75758879243418fe2c87ec7d5d4e1451129",
|
141
|
+
"nodes": [
|
142
|
+
"node1"
|
143
|
+
]
|
144
|
+
},
|
145
|
+
{
|
146
|
+
"zonename": "testzone0",
|
147
|
+
"key": "455a807bb34b1976bac820b07c263ee81bd267cc",
|
148
|
+
"nodes": [
|
149
|
+
"node0"
|
150
|
+
]
|
151
|
+
}
|
152
|
+
],
|
153
|
+
"total": 2,
|
154
|
+
"found": 2
|
155
|
+
}
|
156
|
+
</pre>
|
157
|
+
</code>
|
158
|
+
</td>
|
159
|
+
</tr>
|
160
|
+
<tr>
|
161
|
+
<td>X</td>
|
162
|
+
<td></td>
|
163
|
+
<td></td>
|
164
|
+
<td></td>
|
165
|
+
<td class="path">/api/v1/zones/:zonename</td>
|
166
|
+
<td>
|
167
|
+
Retrieve a list of zones and authenticate with API Key:
|
168
|
+
<pre>/api/v1/zones/testzone1?key=0dfdFFeeDx</pre>
|
169
|
+
Typical response from the gateway:
|
170
|
+
<code>
|
171
|
+
<pre>
|
172
|
+
{
|
173
|
+
"zones": [
|
174
|
+
{
|
175
|
+
"zonename": "testzone1",
|
176
|
+
"key": "79a7c75758879243418fe2c87ec7d5d4e1451129",
|
177
|
+
"nodes": [
|
178
|
+
"node1"
|
179
|
+
]
|
180
|
+
}
|
181
|
+
],
|
182
|
+
"total": 2,
|
183
|
+
"found": 1
|
184
|
+
}
|
185
|
+
</pre>
|
186
|
+
</code>
|
187
|
+
</td>
|
188
|
+
</tr>
|
189
|
+
<tr>
|
190
|
+
<td>X</td>
|
191
|
+
<td></td>
|
192
|
+
<td></td>
|
193
|
+
<td></td>
|
194
|
+
<td class="path">/api/v1/watch</td>
|
195
|
+
<td>
|
196
|
+
Retrieve a list of nodes currently on the watch list and authenticate with API Key:
|
197
|
+
<pre>/api/v1/watch?key=0dfdFFeeDx</pre>
|
198
|
+
Typical response from the gateway:
|
199
|
+
<code>
|
200
|
+
<pre>
|
201
|
+
{
|
202
|
+
"watched": [
|
203
|
+
|
204
|
+
]
|
205
|
+
}
|
206
|
+
</pre>
|
207
|
+
</tr>
|
208
|
+
<tr>
|
209
|
+
<td>X</td>
|
210
|
+
<td></td>
|
211
|
+
<td></td>
|
212
|
+
<td>X</td>
|
213
|
+
<td class="path">/api/v1/watch/:node</td>
|
214
|
+
<td>
|
215
|
+
Retrieve a list of nodes currently on the watch list and authenticate with API Key:
|
216
|
+
<pre>/api/v1/watch/node0?key=0dfdFFeeDx</pre>
|
217
|
+
Typical response from the gateway:
|
218
|
+
<code>
|
219
|
+
<pre>
|
220
|
+
{
|
221
|
+
"watched": false
|
222
|
+
}
|
223
|
+
</pre>
|
224
|
+
</code>
|
225
|
+
To add a node to the watchlist use the following parameters in a POST request:
|
226
|
+
<ul>
|
227
|
+
<li>node</li>
|
228
|
+
<li>notifyURL</li>
|
229
|
+
<li>method</li>
|
230
|
+
<li>timeout</li>
|
231
|
+
See the following full example for more information:
|
232
|
+
<code>
|
233
|
+
<pre>
|
234
|
+
require 'rubygems'
|
235
|
+
require 'typhoeus'
|
236
|
+
require 'json'
|
237
|
+
|
238
|
+
|
239
|
+
body = {:key=> "1230aea77d7bd38898fec74a75a87738dea9f657",
|
240
|
+
:notifyURL=>"http://some-server/push/notifications",
|
241
|
+
:method=>"POST",
|
242
|
+
:timeout=>"60"}
|
243
|
+
|
244
|
+
puts Typhoeus::Request.post("http://localhost:4567/api/v1/watch/node2", :body=>body)
|
245
|
+
</pre>
|
246
|
+
</code>
|
247
|
+
</ul>
|
248
|
+
</td>
|
249
|
+
</tr>
|
250
|
+
</tbody>
|
251
|
+
</table>
|
252
|
+
</div>
|
data/views/index.erb
CHANGED
@@ -29,6 +29,7 @@
|
|
29
29
|
<li class="current"><a href="/home">Home</a></li>
|
30
30
|
<li><a href="/status">Status</a></li>
|
31
31
|
<li><a href="/topology">Topology</a></li>
|
32
|
+
<li><a href="/api">API</a></li>
|
32
33
|
</ul>
|
33
34
|
<div class="mytabs-container" id="tabs-container">
|
34
35
|
<img src="/img/ajax_preloader.gif" width="64" height="64" class="preloader" />
|
data/views/status.erb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
<script type="text/javascript">
|
6
6
|
$(function() {
|
7
7
|
|
8
|
+
keepUpdating = true;
|
8
9
|
var options = {
|
9
10
|
xaxis: { mode: 'time' },
|
10
11
|
legend: { show: true,
|
@@ -31,7 +32,9 @@
|
|
31
32
|
success: onDataReceived
|
32
33
|
});
|
33
34
|
|
34
|
-
|
35
|
+
if(keepUpdating){
|
36
|
+
setTimeout(fetchData, 10000);
|
37
|
+
}
|
35
38
|
}
|
36
39
|
|
37
40
|
setTimeout(fetchData, 1000);
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ardtweeno
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Kirwan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.2.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: mongo
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.6.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.6.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bson_ext
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 1.6.2
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.6.2
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: sinatra
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 1.3.3
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.3.3
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: thin
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 1.5.0
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.5.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: typhoeus
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 0.6.3
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.6.3
|
97
97
|
description: "Ardtweeno - Application Gateway bridges device connected through a serial
|
@@ -104,6 +104,14 @@ executables: []
|
|
104
104
|
extensions: []
|
105
105
|
extra_rdoc_files: []
|
106
106
|
files:
|
107
|
+
- CHANGELOG
|
108
|
+
- COPYING
|
109
|
+
- Gemfile
|
110
|
+
- Gemfile.lock
|
111
|
+
- INSTALL
|
112
|
+
- Procfile
|
113
|
+
- README.md
|
114
|
+
- Rakefile
|
107
115
|
- lib/ardtweeno.rb
|
108
116
|
- lib/ardtweeno/api.rb
|
109
117
|
- lib/ardtweeno/configreader.rb
|
@@ -116,23 +124,9 @@ files:
|
|
116
124
|
- lib/ardtweeno/restapi.rb
|
117
125
|
- lib/ardtweeno/ringbuffer.rb
|
118
126
|
- lib/ardtweeno/serialparser.rb
|
119
|
-
- CHANGELOG
|
120
|
-
- COPYING
|
121
|
-
- Gemfile
|
122
|
-
- Gemfile.lock
|
123
|
-
- INSTALL
|
124
|
-
- Procfile
|
125
|
-
- README.md
|
126
|
-
- Rakefile
|
127
127
|
- public/favicon.ico
|
128
128
|
- public/main.css
|
129
129
|
- public/main.js
|
130
|
-
- views/createpost.erb
|
131
|
-
- views/home.erb
|
132
|
-
- views/index.erb
|
133
|
-
- views/punchcard.erb
|
134
|
-
- views/status.erb
|
135
|
-
- views/topology.erb
|
136
130
|
- resources/conf.yaml
|
137
131
|
- resources/nodelist.yaml
|
138
132
|
- resources/posts.yaml
|
@@ -167,6 +161,13 @@ files:
|
|
167
161
|
- test/ringbuffer_test.rb
|
168
162
|
- test/serialport_mock.rb
|
169
163
|
- test/test_helper.rb
|
164
|
+
- views/api.erb
|
165
|
+
- views/createpost.erb
|
166
|
+
- views/home.erb
|
167
|
+
- views/index.erb
|
168
|
+
- views/punchcard.erb
|
169
|
+
- views/status.erb
|
170
|
+
- views/topology.erb
|
170
171
|
homepage: http://rubygems.org/gems/ardtweeno
|
171
172
|
licenses:
|
172
173
|
- CC BY-NC 3.0
|
@@ -179,20 +180,19 @@ require_paths:
|
|
179
180
|
- lib
|
180
181
|
required_ruby_version: !ruby/object:Gem::Requirement
|
181
182
|
requirements:
|
182
|
-
- -
|
183
|
+
- - ">="
|
183
184
|
- !ruby/object:Gem::Version
|
184
185
|
version: 2.0.0
|
185
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
187
|
requirements:
|
187
|
-
- -
|
188
|
+
- - ">="
|
188
189
|
- !ruby/object:Gem::Version
|
189
190
|
version: '0'
|
190
191
|
requirements: []
|
191
192
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.
|
193
|
+
rubygems_version: 2.2.2
|
193
194
|
signing_key:
|
194
195
|
specification_version: 4
|
195
196
|
summary: Serial Device / IP Network Gateway designed as a PaaS to be run on the Raspberry
|
196
197
|
Pi, exposes Sinatra API
|
197
198
|
test_files: []
|
198
|
-
has_rdoc:
|