ardtweeno 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d157740b9956acd9a32efa343e0f781d4aca11d
4
- data.tar.gz: 6d23a441b410510a3212412e0ec9424a4d981911
3
+ metadata.gz: 53873386c274f4259d283b97c153f7edeb1649a7
4
+ data.tar.gz: 9bec1a6d15af011369aa6b7e59c1e64ce3df77d1
5
5
  SHA512:
6
- metadata.gz: 4114dd22733d63b18891faaafc33f0668f45a01f6be67bc678306602283202dff74ac63bd5ee7a5bf19e4e4416c78ef0669627d1f655496822c5e33bd614888f
7
- data.tar.gz: fcd8e50001b844d2b98a127253c730e5255dfaaa74a762a29d643443750d55687b03ece7904cdaff5a78045f0098b8c9506108d0a43652d2c02b8ca2fe51a588
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
- atomic (1.1.14)
14
- bson (1.9.2)
15
- bson_ext (1.9.2)
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.4)
19
- dotenv (0.9.0)
20
- ethon (0.6.1)
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.1)
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
- mime-types (1.25)
30
- mini_portile (0.5.2)
31
- mongo (1.9.2)
32
- bson (~> 1.9.2)
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.1)
31
+ rack-protection (1.5.2)
37
32
  rack
38
33
  rack-test (0.6.2)
39
34
  rack (>= 1.0)
40
- rake (10.1.0)
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.6)
46
- rspec-expectations (2.14.3)
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.4)
49
- rufus-scheduler (3.0.2)
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.0)
50
+ thin (1.6.2)
58
51
  daemons (>= 1.0.9)
59
52
  eventmachine (>= 1.0.0)
60
- rack (>= 1.5.0)
61
- thor (0.18.1)
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.5)
66
- ethon (~> 0.6.1)
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 node required
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
- theArray = theArray.sort_by {|x| x.seqNo}
524
- return theArray.reverse()
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
@@ -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
- return true
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
- @log.debug "Associated watch found, checking for method " + i[:method]
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
@@ -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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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 |zoneid|
179
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 500, "500 Internal Server Error" ]
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
- settings.log.debug params.inspect
239
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- settings.log.debug params.inspect
252
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- settings.log.debug params.inspect
265
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- "The Ardtweeno system is launching, this will take a moment..."
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
- throw :halt, [ 404, "404 Page Not Found" ] unless @@theDispatcher.authenticate?(params[:key])
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
- "The Ardtweeno system is shutting down, this will take a moment..."
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.3.1" unless defined? Ardtweeno::VERSION
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
@@ -3,10 +3,6 @@ var tabsId = '#tabs';
3
3
  var keepUpdating = false;
4
4
 
5
5
 
6
- function hashchanged(){
7
- keepUpdating = false;
8
- }
9
-
10
6
  $(document).ready(function(){
11
7
  // Preload tab on page load
12
8
  if($(tabsId + ' LI.current A').length > 0){
data/test/debug/run_mock CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'serialport'
3
3
  require 'json'
4
- require "../serialport_mock.rb"
4
+ require "./serialport_mock.rb"
5
5
 
6
6
  mock = SerialDeviceMock.new('/dev/pts/3', 9600, 100)
7
7
 
@@ -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..9))
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.9))
13
+ sleep(rand(0.90))
14
14
  end
@@ -5,8 +5,8 @@ require 'json'
5
5
 
6
6
  body = {:key=> "1230aea77d7bd38898fec74a75a87738dea9f657",
7
7
  # :node=>"node1",
8
- :notifyURL=>"http://localhost:5000/push/node1",
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://localhost:4567/api/v1/watch/node1", :body=>body)
12
+ puts Typhoeus::Request.post("http://192.168.1.14:4567/api/v1/watch/node1", :body=>body)
Binary file
@@ -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={:zonename=>"testzone0", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
107
+ get "/api/v1/zones", params={:key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
108
108
  json = JSON.parse(last_response.body)
109
109
 
110
- assert_equal(1, json["found"])
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(0, json["found"])
115
+ assert_equal(2, json["found"])
116
116
  assert_equal(2, json["total"])
117
117
 
118
- get "/api/v1/zones", params={:key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
118
+ get "/api/v1/zones", params={:key=>"455a807bb34b1976bac820b07c263ee81bd267cc"}
119
119
  json = JSON.parse(last_response.body)
120
- assert_equal(2, json["found"])
120
+ assert_equal(1, json["found"])
121
121
  assert_equal(2, json["total"])
122
122
 
123
- get "/api/v1/zones/testzone0", params={:zonename=>"testzone0", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
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={:zonename=>"testzonez", :key=>"1230aea77d7bd38898fec74a75a87738dea9f657"}
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("The Ardtweeno system is launching, this will take a moment...", last_response.body)
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=>"898fec74a75a87738dea9f657"}
240
- assert not(last_response.ok?)
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("The Ardtweeno system is shutting down, this will take a moment...", last_response.body)
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=>"898fec74a75a87738dea9f657"}
252
- assert not(last_response.ok?)
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
- setTimeout(fetchData, 10000);
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.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: 2013-10-27 00:00:00.000000000 Z
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.0.3
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: