reworking the code and adding tests

This commit is contained in:
Dominic Bosch 2014-02-04 08:35:07 +01:00
parent ee4481c8e9
commit 88e248ad52
20 changed files with 602 additions and 233 deletions

View file

@ -19,15 +19,17 @@ path = require 'path'
###
##Module call
Calling the module as a function will make it look for the `relPath` property in the
Calling the module as a function will make it look for the `configPath` property in the
args object and then try to load a config file from that relative path.
@param {Object} args
###
exports = module.exports = ( args ) ->
args = args ? {}
log args
if typeof args.relPath is 'string'
loadConfigFile args.relPath
if typeof args.configPath is 'string'
loadConfigFile args.configPath
else
loadConfigFile path.join('config', 'config.json')
module.exports
###
@ -35,12 +37,12 @@ Tries to load a configuration file from the path relative to this module's paren
Reads the config file synchronously from the file system and try to parse it.
@private loadConfigFile
@param {String} relPath
@param {String} configPath
###
loadConfigFile = ( relPath ) =>
loadConfigFile = ( configPath ) =>
@config = null
try
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', relPath
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', configPath
if @config and @config.http_port and @config.db_port and
@config.crypto_key and @config.session_secret
log.print 'CF', 'config file loaded successfully'
@ -54,7 +56,6 @@ loadConfigFile = ( relPath ) =>
e.addInfo = 'no config ready'
log.error 'CF', e
loadConfigFile path.join('config', 'config.json')
###
Fetch a property from the configuration

View file

@ -42,12 +42,16 @@ exports = module.exports = ( args ) =>
log args
config = require './config'
config args
@crypto_key = config.getCryptoKey()
@db = redis.createClient config.getDBPort(),
'localhost', { connect_timeout: 2000 }
@db.on "error", ( err ) ->
err.addInfo = 'message from DB'
log.error 'DB', err
@db?.quit()
if config.isReady()
@crypto_key = config.getCryptoKey()
@db = redis.createClient config.getDBPort(),
'localhost', { connect_timeout: 2000 }
@db.on 'error', ( err ) ->
err.addInfo = 'message from DB'
log.error 'DB', err
else
log.error 'DB', 'Initialization failed because of missing config file!'
###
Checks whether the db is connected and passes either an error on failure after
@ -56,7 +60,6 @@ ten attempts within five seconds, or nothing on success to the callback(err).
@public isConnected( *cb* )
@param {function} cb
###
#TODO check if timeout works with func in func
exports.isConnected = ( cb ) =>
if @db.connected then cb()
else
@ -66,13 +69,24 @@ exports.isConnected = ( cb ) =>
log.print 'DB', 'Successfully connected to DB!'
cb()
else if numAttempts++ < 10
setTimeout fCheckConnection, 500
setTimeout fCheckConnection, 100
else
e = new Error 'Connection to DB failed!'
log.error 'DB', e
cb e
setTimeout fCheckConnection, 500
cb new Error 'Connection to DB failed!'
setTimeout fCheckConnection, 100
###
Abstracts logging for simple action replies from the DB.
@private replyHandler( *action* )
@param {String} action
###
replyHandler = ( action ) ->
( err, reply ) ->
if err
err.addInfo = 'during "' + action + '"'
log.error 'DB', err
else
log.print 'DB', action + ': ' + reply
###
Push an event into the event queue.
@ -81,8 +95,11 @@ Push an event into the event queue.
@param {Object} event
###
exports.pushEvent = ( event ) =>
log.print 'DB', 'Event pushed into the queue: ' + event.eventid
@db.rpush 'event_queue', JSON.stringify(event)
if event
log.print 'DB', 'Event pushed into the queue: ' + event.eventid
@db.rpush 'event_queue', JSON.stringify( event )
else
log.error 'DB', 'Why would you give me an empty event...'
###
@ -91,9 +108,19 @@ Pop an event from the event queue and pass it to the callback(err, obj) function
@public popEvent( *cb* )
@param {function} cb
###
exports.popEvent = ( cb )=>
@db.lpop 'event_queue', cb
exports.popEvent = ( cb ) =>
makeObj = ( pcb ) ->
( err, obj ) ->
pcb err, JSON.parse( obj )
@db.lpop 'event_queue', makeObj( cb )
###
Purge the event queue.
@public purgeEventQueue()
###
exports.purgeEventQueue = () =>
@db.del 'event_queue', replyHandler 'purging event queue'
###
Hashes a string based on SHA-3-512.
@ -104,7 +131,7 @@ Hashes a string based on SHA-3-512.
hash = ( plainText ) =>
if !plainText? then return null
try
(crypto.SHA3 plainText, { outputLength: 512 }).toString()
( crypto.SHA3 plainText, { outputLength: 512 } ).toString()
catch err
err.addInfo = 'during hashing'
log.error 'DB', err
@ -145,20 +172,6 @@ decrypt = ( crypticText ) =>
log.error 'DB', err
null
###
Abstracts logging for simple action replies from the DB.
@private replyHandler( *action* )
@param {String} action
###
replyHandler = ( action ) ->
( err, reply ) ->
if err
err.addInfo = 'during "' + action + '"'
log.error 'DB', err
else
log.print 'DB', action + ': ' + reply
###
Fetches all linked data set keys from a linking set, fetches the single data objects
via the provided function and returns the results to the callback(err, obj) function.
@ -179,7 +192,6 @@ getSetRecords = ( set, fSingle, cb ) =>
else
semaphore = arrReply.length
objReplies = {}
#TODO What if the DB needs longer than two seconds to respond?...
setTimeout ->
if semaphore > 0
cb new Error('Timeout fetching ' + set)
@ -193,10 +205,10 @@ getSetRecords = ( set, fSingle, cb ) =>
else if not data
log.error 'DB', new Error 'Empty key in DB: ' + prop
else
objReplies[prop] = data
objReplies[ prop ] = data
if semaphore == 0
cb null, objReplies
fSingle reply, fCallback(reply) for reply in arrReply
fSingle reply, fCallback( reply ) for reply in arrReply
###
## Action Modules
@ -236,30 +248,30 @@ exports.getActionModules = ( cb ) ->
getSetRecords 'action-modules', exports.getActionModule, cb
###
Store a string representation of the authentication parameters for an action module.
Store user-specific action module parameters .
@public storeActionAuth( *userId, moduleId, data* )
@public storeActionParams( *userId, moduleId, data* )
@param {String} userId
@param {String} moduleId
@param {String} data
###
exports.storeActionAuth = ( userId, moduleId, data ) =>
log.print 'DB', 'storeActionAuth: ' + userId + ':' + moduleId
@db.set 'action-auth:' + userId + ':' + moduleId, hash(data),
replyHandler 'storing action auth ' + userId + ':' + moduleId
exports.storeActionParams = ( userId, moduleId, data ) =>
log.print 'DB', 'storeActionParams: ' + moduleId + ':' + userId
@db.set 'action-params:' + moduleId + ':' + userId, hash(data),
replyHandler 'storing action params ' + moduleId + ':' + userId
###
Query the DB for an action module authentication token associated to a user
Query the DB for user-specific action module parameters,
and pass it to the callback(err, obj) function.
@public getActionAuth( *userId, moduleId, cb* )
@public getActionParams( *userId, moduleId, cb* )
@param {String} userId
@param {String} moduleId
@param {function} cb
###
exports.getActionAuth = ( userId, moduleId, cb ) =>
log.print 'DB', 'getActionAuth: ' + userId + ':' + moduleId
@db.get 'action-auth:' + userId + ':' + moduleId, ( err, data ) ->
exports.getActionParams = ( userId, moduleId, cb ) =>
log.print 'DB', 'getActionParams: ' + moduleId + ':' + userId
@db.get 'action-params:' + moduleId + ':' + userId, ( err, data ) ->
cb err, decrypt data
@ -309,10 +321,10 @@ Store a string representation of user-specific parameters for an event module.
###
# TODO is used, remove unused ones
exports.storeEventParams = ( userId, moduleId, data ) =>
log.print 'DB', 'storeEventParams: ' + userId + ':' + moduleId
log.print 'DB', 'storeEventParams: ' + moduleId + ':' + userId
# TODO encryption based on user specific key?
@db.set 'event-params:' + moduleId + ':' + userId, encrypt(data),
replyHandler 'storing event auth ' + userId + ':' + moduleId
replyHandler 'storing event auth ' + moduleId + ':' + userId
###
Query the DB for an action module authentication token, associated with a user.
@ -323,8 +335,8 @@ Query the DB for an action module authentication token, associated with a user.
@param {function} cb
###
exports.getEventAuth = ( userId, moduleId, cb ) =>
log.print 'DB', 'getEventAuth: ' + userId + ':' + moduleId
@db.get 'event-auth:' + userId + ':' + moduleId, ( err, data ) ->
log.print 'DB', 'getEventAuth: ' + moduleId + ':' + userId
@db.get 'event-auth:' + moduleId + ':' + userId, ( err, data ) ->
cb err, decrypt data
@ -335,16 +347,17 @@ exports.getEventAuth = ( userId, moduleId, cb ) =>
###
Store a string representation of a rule in the DB.
@public storeRule( *id, data* )
@param {String} id
@public storeRule( *ruleId, userId, data* )
@param {String} ruleId
@param {String} userId
@param {String} data
###
exports.storeRule = ( id, user, data ) =>
log.print 'DB', 'storeRule: ' + id
@db.sadd 'rules', id + ':' + user, replyHandler 'storing rule key "' + id + ':' + user + '"'
@db.sadd 'user:' + user + ':rules', id, replyHandler 'storing rule key to "user:' + user + ':rules"'
@db.sadd 'rule:' + id + ':users', user, replyHandler 'storing user key to "rule:' + id + ':users"'
@db.set 'rule:' + id + ':' + user, data, replyHandler 'storing rule "' + id + ':' + user + '"'
exports.storeRule = ( ruleId, userId, data ) =>
log.print 'DB', 'storeRule: ' + ruleId
@db.sadd 'rules', ruleId + ':' + user, replyHandler 'storing rule key "' + ruleId + ':' + user + '"'
@db.sadd 'user-set:' + user + ':rules', ruleId, replyHandler 'storing rule key to "user:' + user + ':rules"'
@db.sadd 'rule-set:' + ruleId + ':users', user, replyHandler 'storing user key to "rule:' + ruleId + ':users"'
@db.set 'rule:' + ruleId + ':' + user, data, replyHandler 'storing rule "' + ruleId + ':' + user + '"'
###
Query the DB for a rule and pass it to the callback(err, obj) function.
@ -391,10 +404,11 @@ Associate a role with a user.
@param {String} username
@param {String} role
###
exports.storeUserRole = ( username, role ) =>
exports.storeUserRole = ( userId, roleId ) =>
log.print 'DB', 'storeUserRole: ' + username + ':' + role
@db.sadd 'user-roles:' + username, role, replyHandler 'adding role ' + role + ' to user ' + username
@db.sadd 'role-users:' + role, username, replyHandler 'adding user ' + username + ' to role ' + role
@db.sadd 'roles', role, replyHandler 'adding role ' + role + ' to role index set'
@db.sadd 'user:' + userId + ':roles', role, replyHandler 'adding role ' + role + ' to user ' + username
@db.sadd 'role:' + roleId + ':users', username, replyHandler 'adding user ' + username + ' to role ' + role
###
Fetch all roles of a user and pass them to the callback(err, obj)

View file

@ -30,10 +30,6 @@ app = express()
#RedisStore = require('connect-redis')(express), # TODO use RedisStore for persistent sessions
# Just to have at least something. I know all of you know it now ;-P
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)'
###
Module call
-----------
@ -48,16 +44,20 @@ exports = module.exports = ( args ) ->
log args
config args
requestHandler args
#TODO check whether this really does what it's supposed to do (fetch wrong sess property)
sess_sec = config.getSessionSecret() || sess_sec
module.exports
###
Adds the shutdown handler to the admin commands.
@param {function} fshutDown
@public addHandlers( *fShutDown* )
###
exports.addHandlers = ( fShutDown ) ->
requestHandler.addHandlers fShutDown
# Add cookie support for session handling.
app.use express.cookieParser()
app.use express.session { secret: sess_sec }
# At the moment there's no redis session backbone (didn't work straight away)
app.use express.session { secret: config.getSessionSecret() }
#At the moment there's no redis session backbone (didn't work straight away)
log.print 'HL', 'no session backbone'
# **Accepted requests to paths:**
@ -95,6 +95,11 @@ exports.addHandlers = ( fShutDown ) ->
e.addInfo = 'opening port'
log.error e
###
Shuts down the http listener.
@public shutDown()
###
exports.shutDown = () ->
log.print 'HL', 'Shutting down HTTP listener'
process.exit() # This is a bit brute force...

View file

@ -62,7 +62,7 @@ This function is invoked right after the module is loaded and starts the server.
###
init = ->
log.print 'RS', 'STARTING SERVER'
conf args
# > Check whether the config file is ready, which is required to start the server.
if !conf.isReady()
log.error 'RS', 'Config file not ready!'

View file

@ -20,7 +20,7 @@ Configuration
/*
##Module call
Calling the module as a function will make it look for the `relPath` property in the
Calling the module as a function will make it look for the `configPath` property in the
args object and then try to load a config file from that relative path.
@param {Object} args
*/
@ -29,8 +29,10 @@ Configuration
exports = module.exports = function(args) {
args = args != null ? args : {};
log(args);
if (typeof args.relPath === 'string') {
loadConfigFile(args.relPath);
if (typeof args.configPath === 'string') {
loadConfigFile(args.configPath);
} else {
loadConfigFile(path.join('config', 'config.json'));
}
return module.exports;
};
@ -40,15 +42,15 @@ Configuration
Reads the config file synchronously from the file system and try to parse it.
@private loadConfigFile
@param {String} relPath
@param {String} configPath
*/
loadConfigFile = function(relPath) {
loadConfigFile = function(configPath) {
var e;
_this.config = null;
try {
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', relPath)));
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath)));
if (_this.config && _this.config.http_port && _this.config.db_port && _this.config.crypto_key && _this.config.session_secret) {
return log.print('CF', 'config file loaded successfully');
} else {
@ -61,8 +63,6 @@ Configuration
}
};
loadConfigFile(path.join('config', 'config.json'));
/*
Fetch a property from the configuration

View file

@ -41,19 +41,26 @@ DB Interface
exports = module.exports = function(args) {
var config;
var config, _ref;
args = args != null ? args : {};
log(args);
config = require('./config');
config(args);
_this.crypto_key = config.getCryptoKey();
_this.db = redis.createClient(config.getDBPort(), 'localhost', {
connect_timeout: 2000
});
return _this.db.on("error", function(err) {
err.addInfo = 'message from DB';
return log.error('DB', err);
});
if ((_ref = _this.db) != null) {
_ref.quit();
}
if (config.isReady()) {
_this.crypto_key = config.getCryptoKey();
_this.db = redis.createClient(config.getDBPort(), 'localhost', {
connect_timeout: 2000
});
return _this.db.on('error', function(err) {
err.addInfo = 'message from DB';
return log.error('DB', err);
});
} else {
return log.error('DB', 'Initialization failed because of missing config file!');
}
};
/*
@ -72,22 +79,38 @@ DB Interface
} else {
numAttempts = 0;
fCheckConnection = function() {
var e;
if (_this.db.connected) {
log.print('DB', 'Successfully connected to DB!');
return cb();
} else if (numAttempts++ < 10) {
return setTimeout(fCheckConnection, 500);
return setTimeout(fCheckConnection, 100);
} else {
e = new Error('Connection to DB failed!');
log.error('DB', e);
return cb(e);
return cb(new Error('Connection to DB failed!'));
}
};
return setTimeout(fCheckConnection, 500);
return setTimeout(fCheckConnection, 100);
}
};
/*
Abstracts logging for simple action replies from the DB.
@private replyHandler( *action* )
@param {String} action
*/
replyHandler = function(action) {
return function(err, reply) {
if (err) {
err.addInfo = 'during "' + action + '"';
return log.error('DB', err);
} else {
return log.print('DB', action + ': ' + reply);
}
};
};
/*
Push an event into the event queue.
@ -97,8 +120,12 @@ DB Interface
exports.pushEvent = function(event) {
log.print('DB', 'Event pushed into the queue: ' + event.eventid);
return _this.db.rpush('event_queue', JSON.stringify(event));
if (event) {
log.print('DB', 'Event pushed into the queue: ' + event.eventid);
return _this.db.rpush('event_queue', JSON.stringify(event));
} else {
return log.error('DB', 'Why would you give me an empty event...');
}
};
/*
@ -110,7 +137,24 @@ DB Interface
exports.popEvent = function(cb) {
return _this.db.lpop('event_queue', cb);
var makeObj;
makeObj = function(pcb) {
return function(err, obj) {
return pcb(err, JSON.parse(obj));
};
};
return _this.db.lpop('event_queue', makeObj(cb));
};
/*
Purge the event queue.
@public purgeEventQueue()
*/
exports.purgeEventQueue = function() {
return _this.db.del('event_queue', replyHandler('purging event queue'));
};
/*
@ -188,25 +232,6 @@ DB Interface
}
};
/*
Abstracts logging for simple action replies from the DB.
@private replyHandler( *action* )
@param {String} action
*/
replyHandler = function(action) {
return function(err, reply) {
if (err) {
err.addInfo = 'during "' + action + '"';
return log.error('DB', err);
} else {
return log.print('DB', action + ': ' + reply);
}
};
};
/*
Fetches all linked data set keys from a linking set, fetches the single data objects
via the provided function and returns the results to the callback(err, obj) function.
@ -308,34 +333,34 @@ DB Interface
};
/*
Store a string representation of the authentication parameters for an action module.
Store user-specific action module parameters .
@public storeActionAuth( *userId, moduleId, data* )
@public storeActionParams( *userId, moduleId, data* )
@param {String} userId
@param {String} moduleId
@param {String} data
*/
exports.storeActionAuth = function(userId, moduleId, data) {
log.print('DB', 'storeActionAuth: ' + userId + ':' + moduleId);
return _this.db.set('action-auth:' + userId + ':' + moduleId, hash(data), replyHandler('storing action auth ' + userId + ':' + moduleId));
exports.storeActionParams = function(userId, moduleId, data) {
log.print('DB', 'storeActionParams: ' + moduleId + ':' + userId);
return _this.db.set('action-params:' + moduleId + ':' + userId, hash(data), replyHandler('storing action params ' + moduleId + ':' + userId));
};
/*
Query the DB for an action module authentication token associated to a user
Query the DB for user-specific action module parameters,
and pass it to the callback(err, obj) function.
@public getActionAuth( *userId, moduleId, cb* )
@public getActionParams( *userId, moduleId, cb* )
@param {String} userId
@param {String} moduleId
@param {function} cb
*/
exports.getActionAuth = function(userId, moduleId, cb) {
log.print('DB', 'getActionAuth: ' + userId + ':' + moduleId);
return _this.db.get('action-auth:' + userId + ':' + moduleId, function(err, data) {
exports.getActionParams = function(userId, moduleId, cb) {
log.print('DB', 'getActionParams: ' + moduleId + ':' + userId);
return _this.db.get('action-params:' + moduleId + ':' + userId, function(err, data) {
return cb(err, decrypt(data));
});
};
@ -397,8 +422,8 @@ DB Interface
exports.storeEventParams = function(userId, moduleId, data) {
log.print('DB', 'storeEventParams: ' + userId + ':' + moduleId);
return _this.db.set('event-params:' + moduleId + ':' + userId, encrypt(data), replyHandler('storing event auth ' + userId + ':' + moduleId));
log.print('DB', 'storeEventParams: ' + moduleId + ':' + userId);
return _this.db.set('event-params:' + moduleId + ':' + userId, encrypt(data), replyHandler('storing event auth ' + moduleId + ':' + userId));
};
/*
@ -412,8 +437,8 @@ DB Interface
exports.getEventAuth = function(userId, moduleId, cb) {
log.print('DB', 'getEventAuth: ' + userId + ':' + moduleId);
return _this.db.get('event-auth:' + userId + ':' + moduleId, function(err, data) {
log.print('DB', 'getEventAuth: ' + moduleId + ':' + userId);
return _this.db.get('event-auth:' + moduleId + ':' + userId, function(err, data) {
return cb(err, decrypt(data));
});
};
@ -426,18 +451,19 @@ DB Interface
/*
Store a string representation of a rule in the DB.
@public storeRule( *id, data* )
@param {String} id
@public storeRule( *ruleId, userId, data* )
@param {String} ruleId
@param {String} userId
@param {String} data
*/
exports.storeRule = function(id, user, data) {
log.print('DB', 'storeRule: ' + id);
_this.db.sadd('rules', id + ':' + user, replyHandler('storing rule key "' + id + ':' + user + '"'));
_this.db.sadd('user:' + user + ':rules', id, replyHandler('storing rule key to "user:' + user + ':rules"'));
_this.db.sadd('rule:' + id + ':users', user, replyHandler('storing user key to "rule:' + id + ':users"'));
return _this.db.set('rule:' + id + ':' + user, data, replyHandler('storing rule "' + id + ':' + user + '"'));
exports.storeRule = function(ruleId, userId, data) {
log.print('DB', 'storeRule: ' + ruleId);
_this.db.sadd('rules', ruleId + ':' + user, replyHandler('storing rule key "' + ruleId + ':' + user + '"'));
_this.db.sadd('user-set:' + user + ':rules', ruleId, replyHandler('storing rule key to "user:' + user + ':rules"'));
_this.db.sadd('rule-set:' + ruleId + ':users', user, replyHandler('storing user key to "rule:' + ruleId + ':users"'));
return _this.db.set('rule:' + ruleId + ':' + user, data, replyHandler('storing rule "' + ruleId + ':' + user + '"'));
};
/*
@ -495,10 +521,11 @@ DB Interface
*/
exports.storeUserRole = function(username, role) {
exports.storeUserRole = function(userId, roleId) {
log.print('DB', 'storeUserRole: ' + username + ':' + role);
_this.db.sadd('user-roles:' + username, role, replyHandler('adding role ' + role + ' to user ' + username));
return _this.db.sadd('role-users:' + role, username, replyHandler('adding user ' + username + ' to role ' + role));
_this.db.sadd('roles', role, replyHandler('adding role ' + role + ' to role index set'));
_this.db.sadd('user:' + userId + ':roles', role, replyHandler('adding role ' + role + ' to user ' + username));
return _this.db.sadd('role:' + roleId + ':users', username, replyHandler('adding user ' + username + ' to role ' + role));
};
/*

View file

@ -110,9 +110,9 @@ exports.addRule = function(objRule) {
function pollQueue() {
if(isRunning) {
db.popEvent(function (err, text) {
if(!err && text) {
processEvent(JSON.parse(text));
db.popEvent(function (err, obj) {
if(!err && obj) {
processEvent(obj);
}
setTimeout(pollQueue, 50); //TODO adapt to load
});

View file

@ -10,7 +10,7 @@ HTTP Listener
(function() {
var app, config, exports, express, log, path, qs, requestHandler, sess_sec;
var app, config, exports, express, log, path, qs, requestHandler;
log = require('./logging');
@ -26,8 +26,6 @@ HTTP Listener
app = express();
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)';
/*
Module call
-----------
@ -44,16 +42,23 @@ HTTP Listener
log(args);
config(args);
requestHandler(args);
sess_sec = config.getSessionSecret() || sess_sec;
return module.exports;
};
/*
Adds the shutdown handler to the admin commands.
@param {function} fshutDown
@public addHandlers( *fShutDown* )
*/
exports.addHandlers = function(fShutDown) {
var e, http_port;
requestHandler.addHandlers(fShutDown);
app.use(express.cookieParser());
app.use(express.session({
secret: sess_sec
secret: config.getSessionSecret()
}));
log.print('HL', 'no session backbone');
app.use('/', express["static"](path.resolve(__dirname, '..', 'webpages', 'public')));
@ -79,6 +84,13 @@ HTTP Listener
}
};
/*
Shuts down the http listener.
@public shutDown()
*/
exports.shutDown = function() {
log.print('HL', 'Shutting down HTTP listener');
return process.exit();

View file

@ -67,6 +67,7 @@ TODO how about we allow spawning child processes with servers based on address?
init = function() {
log.print('RS', 'STARTING SERVER');
conf(args);
if (!conf.isReady()) {
log.error('RS', 'Config file not ready!');
process.exit();

View file

@ -1,5 +1,6 @@
'use strict';
var cs = require('coffee-script');
var fs = require('fs'),
path = require('path'),
log = require('./logging');
@ -12,6 +13,10 @@ exports = module.exports = function(args) {
exports.requireFromString = function(src, name, dir) {
if(!dir) dir = __dirname;
// Allow coffee scripts!
console.log(cs.compile(src));
var id = path.resolve(dir, name, name + '.vm');
var vm = require('vm'),
sandbox = {

View file

@ -7,6 +7,10 @@
var urlService = 'https://probinder.com/service/',
credentials = null;
exports.validUserParams = function() {
}
function loadCredentials(cred) {
if(!cred || !cred.username || !cred.password) {
console.error('ERROR: ProBinder AM credentials file corrupt');

View file

@ -17,7 +17,8 @@
"needle": "0.6.1",
"nodeunit": "0.8.2",
"redis": "0.9.0",
"request": "2.27.0"
"request": "2.27.0",
"coffee-script": "1.6.3"
},
"__comment": {
"dependencies": {

5
sandbox.js Normal file
View file

@ -0,0 +1,5 @@
var cs = require('coffee-script');
var fs = require('fs');
var csSrc = fs.readFileSync('coffee/config.coffee', { encoding: "utf-8" });
// csSrc = "log = require './logging'";
console.log(cs.compile(csSrc));

View file

@ -0,0 +1,6 @@
{
"http_port": 2,
"db_port": 9,
"crypto_key": "",
"session_secret": ""
}

View file

@ -1,20 +1,32 @@
exports.testRequire = (test) ->
conf = require '../js-coffee/config'
conf { logType: 2 }
test.ok conf.isReady(), 'File exists'
conf { relPath: 'wrongpath' }
test.strictEqual conf.isReady(), false
exports.setUp = ( cb ) =>
@conf = require '../js-coffee/config'
@conf
logType: 2
cb()
exports.testRequire = ( test ) =>
test.expect 1
test.ok @conf.isReady(), 'File does not exist!'
test.done()
exports.testParametersReady = (test) ->
exports.testParameters = ( test ) =>
test.expect 4
test.ok @conf.getHttpPort(), 'HTTP port does not exist!'
test.ok @conf.getDBPort(), 'DB port does not exist!'
test.ok @conf.getCryptoKey(), 'Crypto key does not exist!'
test.ok @conf.getSessionSecret(), 'Session Secret does not exist!'
test.done()
conf = require '../js-coffee/config'
conf { logType: 2 }
console.log conf
test.ok conf.getHttpPort(), 'HTTP port exists'
test.ok conf.getDBPort(), 'DB port exists'
test.ok conf.getCryptoKey(), 'Crypto key exists'
test.ok conf.getSessionSecret(), 'Session Secret exists'
exports.testDifferentConfigFile = ( test ) =>
test.expect 1
@conf
configPath: 'testing/jsonWrongConfig.json'
test.ok @conf.isReady(), 'Different path not loaded!'
test.done()
test.done()
exports.testNoConfigFile = ( test ) =>
test.expect 1
@conf
configPath: 'wrongpath.file'
test.strictEqual @conf.isReady(), false, 'Wrong path still loaded!'
test.done()

View file

@ -1,30 +1,45 @@
// Generated by CoffeeScript 1.6.3
(function() {
exports.testRequire = function(test) {
var conf;
conf = require('../js-coffee/config');
conf({
var _this = this;
exports.setUp = function(cb) {
_this.conf = require('../js-coffee/config');
_this.conf({
logType: 2
});
test.ok(conf.isReady(), 'File exists');
conf({
relPath: 'wrongpath'
});
test.strictEqual(conf.isReady(), false);
return cb();
};
exports.testRequire = function(test) {
test.expect(1);
test.ok(_this.conf.isReady(), 'File does not exist!');
return test.done();
};
exports.testParametersReady = function(test) {
var conf;
conf = require('../js-coffee/config');
conf({
logType: 2
exports.testParameters = function(test) {
test.expect(4);
test.ok(_this.conf.getHttpPort(), 'HTTP port does not exist!');
test.ok(_this.conf.getDBPort(), 'DB port does not exist!');
test.ok(_this.conf.getCryptoKey(), 'Crypto key does not exist!');
test.ok(_this.conf.getSessionSecret(), 'Session Secret does not exist!');
return test.done();
};
exports.testDifferentConfigFile = function(test) {
test.expect(1);
_this.conf({
configPath: 'testing/jsonWrongConfig.json'
});
console.log(conf);
test.ok(conf.getHttpPort(), 'HTTP port exists');
test.ok(conf.getDBPort(), 'DB port exists');
test.ok(conf.getCryptoKey(), 'Crypto key exists');
test.ok(conf.getSessionSecret(), 'Session Secret exists');
test.ok(_this.conf.isReady(), 'Different path not loaded!');
return test.done();
};
exports.testNoConfigFile = function(test) {
test.expect(1);
_this.conf({
configPath: 'wrongpath.file'
});
test.strictEqual(_this.conf.isReady(), false, 'Wrong path still loaded!');
return test.done();
};

View file

@ -1,15 +1,128 @@
exports.testRequire = (test) ->
db = require '../js-coffee/db_interface'
test.ok db, 'DB interface loaded'
db { logType: 2 }
test.ok conf.isReady(), 'File exists'
test.ok conf.getHttpPort(), 'HTTP port exists'
test.ok conf.getDBPort(), 'DB port exists'
test.ok conf.getCryptoKey(), 'Crypto key exists'
test.ok conf.getSessionSecret(), 'Session Secret exists'
exports.setUp = ( cb ) =>
@db = require '../js-coffee/db_interface'
@db logType: 2
cb()
conf { relPath: 'wrongpath' }
test.strictEqual conf.isReady(), false
test.done()
exports.availability =
testRequire: ( test ) =>
test.expect 1
test.ok @db, 'DB interface loaded'
test.done()
testConnect: ( test ) =>
test.expect 1
@db.isConnected ( err ) ->
test.ifError err, 'Connection failed!'
test.done()
testNoConfig: ( test ) =>
test.expect 1
@db
configPath: 'nonexistingconf.file'
@db.isConnected ( err ) ->
test.ok err, 'Still connected!?'
test.done()
testWrongConfig: ( test ) =>
test.expect 1
@db { configPath: 'testing/jsonWrongConfig.json' }
@db.isConnected ( err ) ->
test.ok err, 'Still connected!?'
test.done()
testPurgeQueue: ( test ) =>
test.expect 2
@db.pushEvent @evt1
@db.purgeEventQueue()
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during pop after purging!'
test.strictEqual obj, null, 'There was an event in the queue!?'
test.done()
exports.events =
setUp: ( cb ) =>
@evt1 =
eventid: '1'
event: 'mail'
@evt2 =
eventid: '2'
event: 'mail'
@db.purgeEventQueue()
cb()
testEmptyPopping: ( test ) =>
test.expect 2
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during pop after purging!'
test.strictEqual obj, null, 'There was an event in the queue!?'
test.done()
testEmptyPushing: ( test ) =>
test.expect 2
@db.pushEvent null
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during non-empty pushing!'
test.strictEqual obj, null, 'There was an event in the queue!?'
test.done()
testPushing: ( test ) =>
test.expect 1
fPush = ->
@db.pushEvent null
@db.pushEvent @evt1
test.throws fPush, Error, 'This should not throw an error'
test.done()
testNonEmptyPopping: ( test ) =>
test.expect 3
@db.pushEvent @evt1
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during non-empty popping!'
test.notStrictEqual obj, null, 'There was no event in the queue!'
test.deepEqual @evt1, obj, 'Wrong event in queue!'
test.done()
testMultiplePushAndPops: ( test ) =>
test.expect 6
numForks = 2
isFinished = () ->
test.done() if --numForks is 0
@db.pushEvent @evt1
@db.pushEvent @evt2
# eventually it would be wise to not care about the order of events
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during multiple push and pop!'
test.notStrictEqual obj, null, 'There was no event in the queue!'
test.deepEqual @evt1, obj, 'Wrong event in queue!'
isFinished()
@db.popEvent ( err, obj ) =>
test.ifError err, 'Error during multiple push and pop!'
test.notStrictEqual obj, null, 'There was no event in the queue!'
test.deepEqual @evt2, obj, 'Wrong event in queue!'
isFinished()
exports.action_modules =
test: (test) =>
test.ok false, 'implement testing!'
test.done()
exports.event_modules =
test: (test) =>
test.done()
exports.rules =
test: (test) =>
test.done()
exports.users =
test: (test) =>
test.done()
exports.tearDown = ( cb ) =>
@db.shutDown()
cb()

View file

@ -1,22 +1,164 @@
// Generated by CoffeeScript 1.6.3
(function() {
exports.testRequire = function(test) {
var db;
db = require('../js-coffee/db_interface');
test.ok(db, 'DB interface loaded');
db({
var _this = this;
exports.setUp = function(cb) {
_this.db = require('../js-coffee/db_interface');
_this.db({
logType: 2
});
test.ok(conf.isReady(), 'File exists');
test.ok(conf.getHttpPort(), 'HTTP port exists');
test.ok(conf.getDBPort(), 'DB port exists');
test.ok(conf.getCryptoKey(), 'Crypto key exists');
test.ok(conf.getSessionSecret(), 'Session Secret exists');
conf({
relPath: 'wrongpath'
});
test.strictEqual(conf.isReady(), false);
return test.done();
return cb();
};
exports.availability = {
testRequire: function(test) {
test.expect(1);
test.ok(_this.db, 'DB interface loaded');
return test.done();
},
testConnect: function(test) {
test.expect(1);
return _this.db.isConnected(function(err) {
test.ifError(err, 'Connection failed!');
return test.done();
});
},
testNoConfig: function(test) {
test.expect(1);
_this.db({
configPath: 'nonexistingconf.file'
});
return _this.db.isConnected(function(err) {
test.ok(err, 'Still connected!?');
return test.done();
});
},
testWrongConfig: function(test) {
test.expect(1);
_this.db({
configPath: 'testing/jsonWrongConfig.json'
});
return _this.db.isConnected(function(err) {
test.ok(err, 'Still connected!?');
return test.done();
});
},
testPurgeQueue: function(test) {
test.expect(2);
_this.db.pushEvent(_this.evt1);
_this.db.purgeEventQueue();
return _this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during pop after purging!');
test.strictEqual(obj, null, 'There was an event in the queue!?');
return test.done();
});
}
};
exports.events = {
setUp: function(cb) {
_this.evt1 = {
eventid: '1',
event: 'mail'
};
_this.evt2 = {
eventid: '2',
event: 'mail'
};
_this.db.purgeEventQueue();
return cb();
},
testEmptyPopping: function(test) {
test.expect(2);
return _this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during pop after purging!');
test.strictEqual(obj, null, 'There was an event in the queue!?');
return test.done();
});
},
testEmptyPushing: function(test) {
test.expect(2);
_this.db.pushEvent(null);
return _this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during non-empty pushing!');
test.strictEqual(obj, null, 'There was an event in the queue!?');
return test.done();
});
},
testPushing: function(test) {
var fPush;
test.expect(1);
fPush = function() {
this.db.pushEvent(null);
return this.db.pushEvent(this.evt1);
};
test.throws(fPush, Error, 'This should not throw an error');
return test.done();
},
testNonEmptyPopping: function(test) {
test.expect(3);
_this.db.pushEvent(_this.evt1);
return _this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during non-empty popping!');
test.notStrictEqual(obj, null, 'There was no event in the queue!');
test.deepEqual(_this.evt1, obj, 'Wrong event in queue!');
return test.done();
});
},
testMultiplePushAndPops: function(test) {
var isFinished, numForks;
test.expect(6);
numForks = 2;
isFinished = function() {
if (--numForks === 0) {
return test.done();
}
};
_this.db.pushEvent(_this.evt1);
_this.db.pushEvent(_this.evt2);
_this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during multiple push and pop!');
test.notStrictEqual(obj, null, 'There was no event in the queue!');
test.deepEqual(_this.evt1, obj, 'Wrong event in queue!');
return isFinished();
});
return _this.db.popEvent(function(err, obj) {
test.ifError(err, 'Error during multiple push and pop!');
test.notStrictEqual(obj, null, 'There was no event in the queue!');
test.deepEqual(_this.evt2, obj, 'Wrong event in queue!');
return isFinished();
});
}
};
exports.action_modules = {
test: function(test) {
test.ok(false, 'implement testing!');
return test.done();
}
};
exports.event_modules = {
test: function(test) {
return test.done();
}
};
exports.rules = {
test: function(test) {
return test.done();
}
};
exports.users = {
test: function(test) {
return test.done();
}
};
exports.tearDown = function(cb) {
_this.db.shutDown();
return cb();
};
}).call(this);

View file

@ -1,8 +1,19 @@
<div id="menubar">
<div id="menubar_menu">menu</div>
<div id="menubar_logout">logout</div>
<div id="menubar_modules">forge modules</div>
<div id="menubar_rules">forge rules</div>
<div id="menubar_event">invoke events</div>
<div id="menubar_logout">logout</div>
<script>
$('#menubar_logout').click(function() {
$('#menubar_modules').click(function() {
window.location.href = 'forge_modules';
});
$('#menubar_rules').click(function() {
window.location.href = 'forge_rules';
});
$('#menubar_event').click(function() {
window.location.href = 'invoke_event';
});
$('#menubar_logout').click(function() {
$.post('/logout').done(function() {
window.location.href = document.URL;
});

View file

@ -21,20 +21,15 @@ textarea {
background-color: #DDD;
}
#menubar_menu {
float: left;
margin:0 auto;
#menubar div {
height: 100%;
float: left;
padding-left: 10px;
padding-right: 10px;
cursor: pointer;
}
#menubar_logout {
height: 100%;
float: right;
padding-left: 10px;
padding-right: 10px;
cursor: pointer;
}
#menubar_logout:hover {
#menubar div:hover {
background-color: #AAA;
}