automate-em 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/jquery.automate.js +439 -0
- data/app/controllers/tokens_controller.rb +99 -0
- data/app/models/setting.rb +2 -2
- data/config/routes.rb +12 -0
- data/lib/automate-em/core/modules.rb +23 -16
- data/lib/automate-em/core/system.rb +1 -1
- data/lib/automate-em/engine.rb +1 -0
- data/lib/automate-em/version.rb +1 -1
- data/lib/generators/module/module_generator.rb +3 -3
- data/test/functional/tokens_controller_test.rb +7 -0
- data/test/unit/helpers/tokens_helper_test.rb +4 -0
- metadata +9 -2
@@ -0,0 +1,439 @@
|
|
1
|
+
/**
|
2
|
+
* ACA Control jQuery Interface Library
|
3
|
+
* Simplifies communication with an ACA Control server when using jQuery
|
4
|
+
*
|
5
|
+
* Copyright (c) 2011 Advanced Control and Acoustics.
|
6
|
+
*
|
7
|
+
* @author Stephen von Takach <steve@advancedcontrol.com.au>
|
8
|
+
* @copyright 2011 advancedcontrol.com.au
|
9
|
+
*
|
10
|
+
* --- Usage ---
|
11
|
+
* Connecting to an ACA Control Server:
|
12
|
+
var controller = new AutomateEm.EventsDispatcher({
|
13
|
+
url: 'http://my.control.server.org:8080/',
|
14
|
+
one_time_key: '/key/url'
|
15
|
+
});
|
16
|
+
|
17
|
+
* Binding to an event:
|
18
|
+
controller.bind('some_event', function(data){
|
19
|
+
alert(data.name + ' says: ' + data.message)
|
20
|
+
});
|
21
|
+
|
22
|
+
* Sending a command to the server:
|
23
|
+
controller.send('Module.function', "item1", ['item', 2], {item:3}, 4, 5.0, ...);
|
24
|
+
|
25
|
+
*
|
26
|
+
**/
|
27
|
+
|
28
|
+
|
29
|
+
var AutomateEm = {
|
30
|
+
Off: false,
|
31
|
+
On: true,
|
32
|
+
Controllers: [], // So we can inspect all instances
|
33
|
+
EventsDispatcher: function (options) {
|
34
|
+
//
|
35
|
+
// options contains: url, system calls, system
|
36
|
+
//
|
37
|
+
var config = {
|
38
|
+
servers: null, // List of ACA Control Servers in priority order
|
39
|
+
system: null, // The system we are connecting to and authentication details for re-connects
|
40
|
+
auto_auth: null, // Are we using the manifest authentication system
|
41
|
+
idle_update: null, // Do we want to auto-update the interface when it is idle
|
42
|
+
forced_update: null,// Update the interface as soon as possible
|
43
|
+
},
|
44
|
+
state ={
|
45
|
+
connection: null, // Base web socket
|
46
|
+
connected: true, // Are we currently connected (initialised to true so that any initial failure is triggered)
|
47
|
+
ready: false, // Is the server ready for bindings and commands
|
48
|
+
polling: false, // Are we polling to remain connected when there is little activity
|
49
|
+
resume: false, // The reference to the resume timer
|
50
|
+
updater: false, // The reference to the update timer
|
51
|
+
offline: false // The system has indicated that it is offline
|
52
|
+
},
|
53
|
+
bindings = {},
|
54
|
+
system_calls = {
|
55
|
+
open: true, // Connection to the server has been made
|
56
|
+
close: true, // Connection to the server was closed or lost
|
57
|
+
ls: true, // List of control systems available to the current user (paginated)
|
58
|
+
ready: true, // Remote System is ready for bindings
|
59
|
+
authenticate: true, // Authentication required
|
60
|
+
system: true, // Please select a system
|
61
|
+
pong: true, // System is idle
|
62
|
+
offline: true // System is offline (slow down re-connect periods)
|
63
|
+
},
|
64
|
+
$this = this;
|
65
|
+
$.extend(config, options);
|
66
|
+
this.config = config; // Allow external access
|
67
|
+
|
68
|
+
|
69
|
+
//
|
70
|
+
// Sends a command to the server in the appropriate format
|
71
|
+
//
|
72
|
+
var send = function (command_name) {
|
73
|
+
var payload = JSON.stringify({ command: command_name, data: Array.prototype.slice.call( arguments, 1 ) });
|
74
|
+
// Array.prototype.slice.call( arguments, 1 ) gets all the arguments - the first in an array
|
75
|
+
|
76
|
+
if (state.connection != null && state.connection.readyState == state.connection.OPEN) {
|
77
|
+
state.connection.send(payload); // <= send JSON data to socket server
|
78
|
+
set_poll(); // Reset polling
|
79
|
+
}
|
80
|
+
|
81
|
+
return $this; // chainable
|
82
|
+
};
|
83
|
+
this.send = send;
|
84
|
+
|
85
|
+
//
|
86
|
+
// Requests to recieve notifications of a value change from the server
|
87
|
+
// Triggers the functions passed in when the server informs us of an update
|
88
|
+
//
|
89
|
+
this.bind = function (events, func) {
|
90
|
+
if(!!func) {
|
91
|
+
var temp = {};
|
92
|
+
temp[events] = func;
|
93
|
+
events = temp;
|
94
|
+
}
|
95
|
+
|
96
|
+
jQuery.each( events, function(event_name, callback){
|
97
|
+
bindings[event_name] = bindings[event_name] || [];
|
98
|
+
bindings[event_name].push(callback);
|
99
|
+
|
100
|
+
if (!system_calls[event_name] && state.connection != null && state.connection.readyState == state.connection.OPEN){
|
101
|
+
var args = event_name.split('.');
|
102
|
+
args.splice(0,0, 'register');
|
103
|
+
send.apply( this, args );
|
104
|
+
}
|
105
|
+
});
|
106
|
+
|
107
|
+
return this; // chainable
|
108
|
+
};
|
109
|
+
|
110
|
+
this.is_connected = function(){
|
111
|
+
return state.connected;
|
112
|
+
};
|
113
|
+
|
114
|
+
//
|
115
|
+
// Removes all the callbacks for the event and lets the server know that we
|
116
|
+
// don't want to revieve it anymore.
|
117
|
+
//
|
118
|
+
this.unbind = function (event_name) {
|
119
|
+
delete bindings[event_name];
|
120
|
+
|
121
|
+
if (state.connection != null && state.connection.readyState == state.connection.OPEN){
|
122
|
+
var args = event_name.split('.');
|
123
|
+
args.splice(0,0, 'unregister');
|
124
|
+
send.apply( this, args );
|
125
|
+
}
|
126
|
+
|
127
|
+
return this; // chainable
|
128
|
+
};
|
129
|
+
|
130
|
+
//
|
131
|
+
// The event trigger, calls the registered handlers in order
|
132
|
+
//
|
133
|
+
var trigger = function (event_name, message) {
|
134
|
+
var chain = bindings[event_name];
|
135
|
+
if (chain === undefined) return; // no bindings for this event
|
136
|
+
|
137
|
+
var i, result;
|
138
|
+
for (i = 0; i < chain.length; i = i + 1) {
|
139
|
+
try {
|
140
|
+
result = chain[i](message);
|
141
|
+
if(result === false) // Return false to prevent later bindings
|
142
|
+
break;
|
143
|
+
} catch (err) { } // Catch any user code errors
|
144
|
+
}
|
145
|
+
|
146
|
+
return $this; // chainable
|
147
|
+
};
|
148
|
+
this.trigger = trigger;
|
149
|
+
|
150
|
+
|
151
|
+
//
|
152
|
+
// Polling functions
|
153
|
+
// Only called if no other traffic is being transmitted.
|
154
|
+
//
|
155
|
+
function set_poll(){
|
156
|
+
if(!!state.polling) {
|
157
|
+
clearInterval(state.polling);
|
158
|
+
}
|
159
|
+
state.polling = setInterval(do_poll, 60000); // Maintain the connection by pinging every 1min
|
160
|
+
}
|
161
|
+
|
162
|
+
function do_poll(){
|
163
|
+
if((!!config.idle_update) && updateReady) // Update on idle
|
164
|
+
window.location.reload();
|
165
|
+
else
|
166
|
+
send('ping');
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
//
|
171
|
+
// Sets up a new connection to the remote server
|
172
|
+
//
|
173
|
+
function setup_connection() {
|
174
|
+
jQuery.ajax('/tokens/servers', {
|
175
|
+
type: 'GET',
|
176
|
+
dataType: 'json',
|
177
|
+
success: function(data, textStatus, jqXHR){
|
178
|
+
config.servers = data;
|
179
|
+
|
180
|
+
if(!!window.WebSocket)
|
181
|
+
state.connection = new window.WebSocket("ws://" + config.servers[0].hostname + ":81/");
|
182
|
+
else if(!!window.MozWebSocket)
|
183
|
+
state.connection = new window.MozWebSocket("ws://" + config.servers[0].hostname + ":81/");
|
184
|
+
else
|
185
|
+
return;
|
186
|
+
|
187
|
+
// dispatch to the right handlers
|
188
|
+
state.connection.onmessage = function (evt) {
|
189
|
+
var json = JSON.parse(evt.data);
|
190
|
+
|
191
|
+
if (json.event == 'ready') {
|
192
|
+
//
|
193
|
+
// Re-register status events then call ready
|
194
|
+
//
|
195
|
+
for (event_name in bindings) {
|
196
|
+
try {
|
197
|
+
if(!system_calls[event_name]) {
|
198
|
+
var args = event_name.split('.');
|
199
|
+
args.splice(0,0, 'register');
|
200
|
+
send.apply( this, args );
|
201
|
+
}
|
202
|
+
} catch (err) { }
|
203
|
+
}
|
204
|
+
|
205
|
+
set_poll(); // Set the polling to occur
|
206
|
+
}
|
207
|
+
|
208
|
+
//
|
209
|
+
// Trigger callbacks
|
210
|
+
//
|
211
|
+
trigger(json.event, json.data);
|
212
|
+
};
|
213
|
+
|
214
|
+
state.connection.onclose = function () {
|
215
|
+
if (state.connected) {
|
216
|
+
state.connected = false;
|
217
|
+
if(!!state.polling) {
|
218
|
+
clearInterval(state.polling);
|
219
|
+
state.polling = false;
|
220
|
+
}
|
221
|
+
trigger('close');
|
222
|
+
}
|
223
|
+
}
|
224
|
+
state.connection.onopen = function () {
|
225
|
+
state.connected = true; // prevent multiple disconnect triggers
|
226
|
+
trigger('open');
|
227
|
+
}
|
228
|
+
},
|
229
|
+
error: function(jqXHR, textStatus, errorThrown){
|
230
|
+
//
|
231
|
+
// Damn...
|
232
|
+
//
|
233
|
+
;
|
234
|
+
}
|
235
|
+
});
|
236
|
+
}
|
237
|
+
setup_connection();
|
238
|
+
|
239
|
+
|
240
|
+
//
|
241
|
+
// Ensure the connection is resumed if disconnected
|
242
|
+
// We do this in this way for mobile devices when resumed from sleep to ensure they reconnect
|
243
|
+
//
|
244
|
+
function checkResume() {
|
245
|
+
if (state.connection == null || state.connection.readyState == state.connection.CLOSED) {
|
246
|
+
setup_connection();
|
247
|
+
}
|
248
|
+
}
|
249
|
+
state.resume = window.setInterval(checkResume, 1000);
|
250
|
+
AutomateEm.Controllers.push(this);
|
251
|
+
|
252
|
+
|
253
|
+
//
|
254
|
+
// Bind events for automation (first attempt, else fall back to interface for both auth and system)
|
255
|
+
//
|
256
|
+
var authCount = 0,
|
257
|
+
sysCallCount = 0,
|
258
|
+
oneKey;
|
259
|
+
|
260
|
+
this.bind('open', function(){
|
261
|
+
|
262
|
+
authCount = 0;
|
263
|
+
sysCallCount = 0;
|
264
|
+
oneKey = null;
|
265
|
+
|
266
|
+
});
|
267
|
+
|
268
|
+
function getCookie(c_name)
|
269
|
+
{
|
270
|
+
var i,x,y,ARRcookies=document.cookie.split(";");
|
271
|
+
for (i=0;i<ARRcookies.length;i++)
|
272
|
+
{
|
273
|
+
x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
|
274
|
+
y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
|
275
|
+
x=x.replace(/^\s+|\s+$/g,"");
|
276
|
+
if (x==c_name)
|
277
|
+
{
|
278
|
+
return unescape(y);
|
279
|
+
}
|
280
|
+
}
|
281
|
+
return null;
|
282
|
+
}
|
283
|
+
|
284
|
+
this.bind('authenticate', function(){
|
285
|
+
authCount += 1;
|
286
|
+
|
287
|
+
if(authCount == 1 && (!!config.auto_auth) && (!!config.system)) {
|
288
|
+
oneKey = getCookie('next_key');
|
289
|
+
if(!!oneKey){
|
290
|
+
send("authenticate", oneKey);
|
291
|
+
return false;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
authCount += 1;
|
296
|
+
});
|
297
|
+
|
298
|
+
this.bind('system', function(){
|
299
|
+
sysCallCount += 1;
|
300
|
+
|
301
|
+
if(sysCallCount == 1 && config.system !== false) { // 0 == false
|
302
|
+
send("system", config.system);
|
303
|
+
|
304
|
+
return false;
|
305
|
+
} // Auto login failure here will result in a disconnect
|
306
|
+
});
|
307
|
+
|
308
|
+
this.bind('offline', function(){
|
309
|
+
state.offline = true;
|
310
|
+
clearInterval(state.resume);
|
311
|
+
state.resume = window.setInterval(checkResume, 15000);
|
312
|
+
});
|
313
|
+
|
314
|
+
this.bind('ready', function(){
|
315
|
+
if(state.offline) {
|
316
|
+
state.offline = false;
|
317
|
+
clearInterval(state.resume);
|
318
|
+
state.resume = window.setInterval(checkResume, 1000);
|
319
|
+
}
|
320
|
+
|
321
|
+
if((!!config.auto_auth) && (!!config.system) && sysCallCount == 1 && authCount == 1) {
|
322
|
+
//
|
323
|
+
// Authenticate with the server
|
324
|
+
// Then we can safely reload the cache
|
325
|
+
// on cache success we accept the new key
|
326
|
+
//
|
327
|
+
jQuery.ajax('/tokens/new', {
|
328
|
+
type: 'GET',
|
329
|
+
dataType: 'text',
|
330
|
+
success: function(data, textStatus, jqXHR){
|
331
|
+
//
|
332
|
+
// Set the csrf token
|
333
|
+
// Get the new one-time-key
|
334
|
+
//
|
335
|
+
$('meta[name="csrf-token"]').attr('content', data);
|
336
|
+
|
337
|
+
jQuery.ajax('/tokens/authenticate', {
|
338
|
+
type: 'POST',
|
339
|
+
data: {
|
340
|
+
key: oneKey,
|
341
|
+
system: config.system
|
342
|
+
},
|
343
|
+
dataType: 'text',
|
344
|
+
success: function(data, textStatus, jqXHR){
|
345
|
+
// Accept the new key on success
|
346
|
+
jQuery.ajax('/tokens/accept', {
|
347
|
+
type: 'POST',
|
348
|
+
data: {
|
349
|
+
key: oneKey,
|
350
|
+
system: config.system
|
351
|
+
},
|
352
|
+
dataType: 'text',
|
353
|
+
success: function(data, textStatus, jqXHR){
|
354
|
+
//
|
355
|
+
// This can safely be ignored. Here for debugging
|
356
|
+
//
|
357
|
+
var yay = "success";
|
358
|
+
},
|
359
|
+
error: function(){
|
360
|
+
//
|
361
|
+
// This can safely be ignored. Here for debugging
|
362
|
+
//
|
363
|
+
var damn = "fail";
|
364
|
+
}
|
365
|
+
});
|
366
|
+
},
|
367
|
+
error: function(){
|
368
|
+
//
|
369
|
+
// This can safely be ignored. Here for debugging
|
370
|
+
//
|
371
|
+
var damn = "fail";
|
372
|
+
}
|
373
|
+
});
|
374
|
+
},
|
375
|
+
error: function(){
|
376
|
+
//
|
377
|
+
// This can safely be ignored. Here for debugging
|
378
|
+
//
|
379
|
+
var damn = "fail";
|
380
|
+
}
|
381
|
+
});
|
382
|
+
}
|
383
|
+
|
384
|
+
authCount = 0;
|
385
|
+
sysCallCount = 0;
|
386
|
+
});
|
387
|
+
|
388
|
+
//
|
389
|
+
// End Auto_auth ---------------
|
390
|
+
//
|
391
|
+
|
392
|
+
|
393
|
+
//
|
394
|
+
// Auto update functions
|
395
|
+
//
|
396
|
+
var appCache = window.applicationCache,
|
397
|
+
updateReady = false;
|
398
|
+
|
399
|
+
function bindCache(){
|
400
|
+
|
401
|
+
$(appCache).bind('updateready', function(){
|
402
|
+
appCache.swapCache(); // Swap cache has called key
|
403
|
+
|
404
|
+
if(!!config.forced_update)
|
405
|
+
window.location.reload();
|
406
|
+
else {
|
407
|
+
appCache = window.applicationCache;
|
408
|
+
bindCache();
|
409
|
+
updateReady = true;
|
410
|
+
}
|
411
|
+
});
|
412
|
+
|
413
|
+
}
|
414
|
+
|
415
|
+
if((!!config.idle_update) || (!!config.forced_update)) {
|
416
|
+
bindCache();
|
417
|
+
|
418
|
+
state.updater = setInterval('window.applicationCache.update();', 600000);
|
419
|
+
}
|
420
|
+
|
421
|
+
//
|
422
|
+
// Disconnects and removes the self reference to the object
|
423
|
+
// Once all external references are removed it will be garbage collected
|
424
|
+
//
|
425
|
+
this.destroy = function(){
|
426
|
+
clearInterval(state.resume);
|
427
|
+
clearInterval(state.updater);
|
428
|
+
if(state.connection != null)
|
429
|
+
state.connection.close();
|
430
|
+
var i;
|
431
|
+
for(i = 0; i < AutomateEm.Controllers.length; i = i + 1) {
|
432
|
+
if(AutomateEm.Controllers[i] == this) {
|
433
|
+
AutomateEm.Controllers.splice(i, 1);
|
434
|
+
break;
|
435
|
+
}
|
436
|
+
}
|
437
|
+
};
|
438
|
+
}
|
439
|
+
};
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class TokensController < ActionController::Base
|
4
|
+
|
5
|
+
protect_from_forgery
|
6
|
+
before_filter :auth_user, :only => [:accept]
|
7
|
+
layout nil
|
8
|
+
|
9
|
+
|
10
|
+
def authenticate # Allowed through by application controller
|
11
|
+
#
|
12
|
+
# Auth(gen)
|
13
|
+
# check the system matches (set user and system in session)
|
14
|
+
# respond with success
|
15
|
+
#
|
16
|
+
dev = TrustedDevice.try_to_login(params[:key], true) # true means gen the next key
|
17
|
+
if params[:system].present? && dev.present? && params[:system].to_i == dev.control_system_id
|
18
|
+
session[:token] = dev.user_id
|
19
|
+
session[:system] = dev.control_system_id
|
20
|
+
session[:key] = params[:key]
|
21
|
+
cookies.permanent[:next_key] = {:value => dev.next_key, :path => URI.parse(request.referer).path}
|
22
|
+
|
23
|
+
render :nothing => true # success!
|
24
|
+
else
|
25
|
+
render :nothing => true, :status => :forbidden # 403
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def accept
|
31
|
+
dev = TrustedDevice.where('user_id = ? AND control_system_id = ? AND one_time_key = ? AND (expires IS NULL OR expires > ?)',
|
32
|
+
session[:token], session[:system], session[:key], Time.now).first
|
33
|
+
|
34
|
+
if dev.present?
|
35
|
+
dev.accept_key
|
36
|
+
render :nothing => true # success!
|
37
|
+
else
|
38
|
+
render :nothing => true, :status => :forbidden # 403
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
#
|
44
|
+
# Build a new session for the interface if the existing one has expired
|
45
|
+
# This maintains the csrf security
|
46
|
+
# We don't want to reset the session if a valid user is already authenticated either
|
47
|
+
#
|
48
|
+
def new
|
49
|
+
reset_session unless session[:user].present?
|
50
|
+
|
51
|
+
render :text => form_authenticity_token
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def create
|
56
|
+
#
|
57
|
+
# Application controller ensures we are logged in as real user
|
58
|
+
# Ensure the user can access the control system requested (the control system does this too)
|
59
|
+
# Generate key, populate the session
|
60
|
+
#
|
61
|
+
user = session[:user].present? ? User.find(session[:user]) : nil # We have to be authed to get here
|
62
|
+
sys = user.control_systems.where('control_systems.id = ?', params[:system]).first unless user.nil?
|
63
|
+
if user.present? && sys.present?
|
64
|
+
|
65
|
+
dev = TrustedDevice.new
|
66
|
+
dev.reason = params[:trusted_device][:reason]
|
67
|
+
dev.user = user
|
68
|
+
dev.control_system = sys
|
69
|
+
dev.save
|
70
|
+
|
71
|
+
if !dev.new_record?
|
72
|
+
cookies.permanent[:next_key] = {:value => dev.one_time_key, :path => URI.parse(request.referer).path}
|
73
|
+
render :json => {} # success!
|
74
|
+
else
|
75
|
+
render :json => dev.errors.messages, :status => :not_acceptable # 406
|
76
|
+
end
|
77
|
+
else
|
78
|
+
if user.present?
|
79
|
+
render :json => {:control => 'could not find the system selected'}, :status => :forbidden # 403
|
80
|
+
else
|
81
|
+
render :json => {:you => 'are not authorised'}, :status => :forbidden # 403
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def servers
|
88
|
+
render :json => Server.all
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
|
95
|
+
def auth_user
|
96
|
+
redirect_to root_path unless session[:user].present? || session[:token].present?
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
data/app/models/setting.rb
CHANGED
@@ -19,7 +19,7 @@ class Setting < ActiveRecord::Base
|
|
19
19
|
if self[:text_value].blank?
|
20
20
|
self[:text_value] = ""
|
21
21
|
else
|
22
|
-
self[:text_value] = Encryptor.decrypt(Base64.decode64(self[:text_value]), {:key =>
|
22
|
+
self[:text_value] = Encryptor.decrypt(Base64.decode64(self[:text_value]), {:key => Rails.application.config.automate.encrypt_key, :algorithm => 'aes-256-cbc'})
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -29,7 +29,7 @@ class Setting < ActiveRecord::Base
|
|
29
29
|
if self[:text_value].blank?
|
30
30
|
self[:text_value] = ""
|
31
31
|
else
|
32
|
-
self[:text_value] = Base64.encode64(Encryptor.encrypt(self[:text_value], {:key =>
|
32
|
+
self[:text_value] = Base64.encode64(Encryptor.encrypt(self[:text_value], {:key => Rails.application.config.automate.encrypt_key, :algorithm => 'aes-256-cbc'}))
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
data/config/routes.rb
ADDED
@@ -14,20 +14,21 @@ module AutomateEm
|
|
14
14
|
@@load_lock.mon_synchronize {
|
15
15
|
begin
|
16
16
|
found = false
|
17
|
+
file = "#{dep.classname.underscore}.rb"
|
17
18
|
|
18
19
|
Rails.configuration.automate.module_paths.each do |path|
|
19
|
-
if File.exists?("#{path}/#{
|
20
|
-
load "#{path}/#{
|
20
|
+
if File.exists?("#{path}/#{file}")
|
21
|
+
load "#{path}/#{file}"
|
21
22
|
found = true
|
22
23
|
break
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
27
|
if not found
|
27
|
-
raise "File not found!"
|
28
|
+
raise "File not found! (#{file})"
|
28
29
|
end
|
29
30
|
|
30
|
-
@@modules[dep.id] = dep.classname.
|
31
|
+
@@modules[dep.id] = dep.classname.constantize
|
31
32
|
rescue => e
|
32
33
|
AutomateEm.print_error(System.logger, e, {
|
33
34
|
:message => "device module #{dep.actual_name} error whilst loading",
|
@@ -116,12 +117,15 @@ module AutomateEm
|
|
116
117
|
#
|
117
118
|
# Instance of a user module
|
118
119
|
#
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
begin
|
121
|
+
@instance = Modules[controllerDevice.dependency_id].new(controllerDevice.tls, controllerDevice.makebreak)
|
122
|
+
@instance.join_system(@system)
|
123
|
+
@@instances[@device] = @instance
|
124
|
+
@@devices[baselookup] = @instance
|
125
|
+
@@lookup[@instance] = [@device]
|
126
|
+
ensure
|
127
|
+
@@lookup_lock.unlock #UNLOCK!! so we can lookup settings in on_load
|
128
|
+
end
|
125
129
|
|
126
130
|
devBase = nil
|
127
131
|
|
@@ -179,13 +183,16 @@ module AutomateEm
|
|
179
183
|
#
|
180
184
|
# add parent may lock at this point!
|
181
185
|
#
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
186
|
+
begin
|
187
|
+
@instance = @@devices[baselookup]
|
188
|
+
@@lookup[@instance] << @device
|
189
|
+
@@instances[@device] = @instance
|
190
|
+
EM.defer do
|
191
|
+
@instance.join_system(@system)
|
192
|
+
end
|
193
|
+
ensure
|
194
|
+
@@lookup_lock.unlock #UNLOCK!!
|
187
195
|
end
|
188
|
-
@@lookup_lock.unlock #UNLOCK!!
|
189
196
|
end
|
190
197
|
end
|
191
198
|
end
|
@@ -190,7 +190,7 @@ module AutomateEm
|
|
190
190
|
if !@controller.active || force
|
191
191
|
if @logger.nil?
|
192
192
|
if Rails.env.production?
|
193
|
-
@logger = Logger.new("
|
193
|
+
@logger = Logger.new(Rails.root.join("log/system_#{@controller.id}.log").to_s, 10, 4194304)
|
194
194
|
else
|
195
195
|
@logger = Logger.new(STDOUT)
|
196
196
|
end
|
data/lib/automate-em/engine.rb
CHANGED
data/lib/automate-em/version.rb
CHANGED
@@ -12,12 +12,12 @@ class ModuleGenerator < Rails::Generators::NamedBase
|
|
12
12
|
scope = []
|
13
13
|
text = ""
|
14
14
|
param.map! {|item|
|
15
|
-
item = item.
|
15
|
+
item = item.camelcase
|
16
16
|
scope << item
|
17
17
|
text += "module #{scope.join('::')}; end\n"
|
18
18
|
item
|
19
19
|
}
|
20
|
-
param << name.
|
20
|
+
param << name.camelcase
|
21
21
|
scope = param.join('::')
|
22
22
|
|
23
23
|
|
@@ -27,7 +27,7 @@ class ModuleGenerator < Rails::Generators::NamedBase
|
|
27
27
|
text += <<-FILE
|
28
28
|
|
29
29
|
|
30
|
-
class #{scope} < AutomateEm::#{type.downcase.
|
30
|
+
class #{scope} < AutomateEm::#{type.downcase.camelcase}
|
31
31
|
def on_load
|
32
32
|
end
|
33
33
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: automate-em
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -194,6 +194,8 @@ executables: []
|
|
194
194
|
extensions: []
|
195
195
|
extra_rdoc_files: []
|
196
196
|
files:
|
197
|
+
- app/assets/javascripts/jquery.automate.js
|
198
|
+
- app/controllers/tokens_controller.rb
|
197
199
|
- app/models/controller_device.rb
|
198
200
|
- app/models/controller_http_service.rb
|
199
201
|
- app/models/controller_logic.rb
|
@@ -205,6 +207,7 @@ files:
|
|
205
207
|
- app/models/trusted_device.rb
|
206
208
|
- app/models/user_zone.rb
|
207
209
|
- app/models/zone.rb
|
210
|
+
- config/routes.rb
|
208
211
|
- db/migrate/20111001022500_init.rb
|
209
212
|
- db/migrate/20111017213801_one_time_key.rb
|
210
213
|
- db/migrate/20111021071632_encrypt_setting.rb
|
@@ -268,8 +271,10 @@ files:
|
|
268
271
|
- test/dummy/Rakefile
|
269
272
|
- test/dummy/README.rdoc
|
270
273
|
- test/dummy/script/rails
|
274
|
+
- test/functional/tokens_controller_test.rb
|
271
275
|
- test/integration/navigation_test.rb
|
272
276
|
- test/test_helper.rb
|
277
|
+
- test/unit/helpers/tokens_helper_test.rb
|
273
278
|
homepage: http://advancedcontrol.com.au/
|
274
279
|
licenses: []
|
275
280
|
post_install_message:
|
@@ -324,5 +329,7 @@ test_files:
|
|
324
329
|
- test/dummy/Rakefile
|
325
330
|
- test/dummy/README.rdoc
|
326
331
|
- test/dummy/script/rails
|
332
|
+
- test/functional/tokens_controller_test.rb
|
327
333
|
- test/integration/navigation_test.rb
|
328
334
|
- test/test_helper.rb
|
335
|
+
- test/unit/helpers/tokens_helper_test.rb
|