diff --git a/coffee/config.coffee b/coffee/config.coffee index e0d67bc..d0e40af 100644 --- a/coffee/config.coffee +++ b/coffee/config.coffee @@ -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 diff --git a/coffee/db_interface.coffee b/coffee/db_interface.coffee index 1ab956a..9a7c4d3 100644 --- a/coffee/db_interface.coffee +++ b/coffee/db_interface.coffee @@ -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) diff --git a/coffee/http_listener.coffee b/coffee/http_listener.coffee index c34e36c..6bac9ff 100644 --- a/coffee/http_listener.coffee +++ b/coffee/http_listener.coffee @@ -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... diff --git a/coffee/server.coffee b/coffee/server.coffee index cbcdaeb..4318db1 100644 --- a/coffee/server.coffee +++ b/coffee/server.coffee @@ -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!' diff --git a/js-coffee/config.js b/js-coffee/config.js index 70ad3fb..d5d3740 100644 --- a/js-coffee/config.js +++ b/js-coffee/config.js @@ -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 diff --git a/js-coffee/db_interface.js b/js-coffee/db_interface.js index de1ce4e..f7d7cae 100644 --- a/js-coffee/db_interface.js +++ b/js-coffee/db_interface.js @@ -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)); }; /* diff --git a/js-coffee/engine.js b/js-coffee/engine.js index 8f344af..0090eb6 100644 --- a/js-coffee/engine.js +++ b/js-coffee/engine.js @@ -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 }); diff --git a/js-coffee/http_listener.js b/js-coffee/http_listener.js index 4a41537..3efb1a1 100644 --- a/js-coffee/http_listener.js +++ b/js-coffee/http_listener.js @@ -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(); diff --git a/js-coffee/server.js b/js-coffee/server.js index 046081a..154bc43 100644 --- a/js-coffee/server.js +++ b/js-coffee/server.js @@ -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(); diff --git a/js/module_loader.js b/js/module_loader.js index a26d317..321a0bf 100644 --- a/js/module_loader.js +++ b/js/module_loader.js @@ -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 = { diff --git a/mod_actions/probinder/probinder.js b/mod_actions/probinder/probinder.js index 8435179..995e77c 100644 --- a/mod_actions/probinder/probinder.js +++ b/mod_actions/probinder/probinder.js @@ -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'); diff --git a/package.json b/package.json index 753c9d4..7d64d65 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/sandbox.js b/sandbox.js new file mode 100644 index 0000000..95e8a6d --- /dev/null +++ b/sandbox.js @@ -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)); \ No newline at end of file diff --git a/testing/jsonWrongConfig.json b/testing/jsonWrongConfig.json new file mode 100644 index 0000000..2da4358 --- /dev/null +++ b/testing/jsonWrongConfig.json @@ -0,0 +1,6 @@ +{ + "http_port": 2, + "db_port": 9, + "crypto_key": "", + "session_secret": "" +} \ No newline at end of file diff --git a/testing/test_config.coffee b/testing/test_config.coffee index 257d12e..0c1f735 100644 --- a/testing/test_config.coffee +++ b/testing/test_config.coffee @@ -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() \ No newline at end of file +exports.testNoConfigFile = ( test ) => + test.expect 1 + @conf + configPath: 'wrongpath.file' + test.strictEqual @conf.isReady(), false, 'Wrong path still loaded!' + test.done() diff --git a/testing/test_config.js b/testing/test_config.js index 7022d27..d8a838b 100644 --- a/testing/test_config.js +++ b/testing/test_config.js @@ -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(); }; diff --git a/testing/test_db_interface.coffee b/testing/test_db_interface.coffee index f61314c..4fad77f 100644 --- a/testing/test_db_interface.coffee +++ b/testing/test_db_interface.coffee @@ -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() \ No newline at end of file diff --git a/testing/test_db_interface.js b/testing/test_db_interface.js index 849d411..1d74bda 100644 --- a/testing/test_db_interface.js +++ b/testing/test_db_interface.js @@ -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); diff --git a/webpages/handlers/part_menubar.html b/webpages/handlers/part_menubar.html index 669fce7..4164317 100644 --- a/webpages/handlers/part_menubar.html +++ b/webpages/handlers/part_menubar.html @@ -1,8 +1,19 @@