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 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: