renamed start scipts, added test for the webapi-eca engine

This commit is contained in:
Dominic Bosch 2014-02-19 14:14:08 +01:00
parent 3d9061a14f
commit 7a51aed47b
23 changed files with 364 additions and 318 deletions

View file

@ -6,7 +6,8 @@ Configuration
### ###
# **Requires:** # **Loads Modules:**
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html) and # - Node.js Modules: [fs](http://nodejs.org/api/fs.html) and
# [path](http://nodejs.org/api/path.html) # [path](http://nodejs.org/api/path.html)
fs = require 'fs' fs = require 'fs'
@ -45,7 +46,6 @@ loadConfigFile = ( configPath ) =>
'log' 'log'
'http-port' 'http-port'
'db-port' 'db-port'
'crypto-key'
] ]
#TODO Try to get rid of crypto key #TODO Try to get rid of crypto key
try try
@ -89,7 +89,7 @@ exports.getHttpPort = -> fetchProp 'http-port'
@public getDBPort() @public getDBPort()
### ###
exports.getDBPort = -> fetchProp 'db-port' exports.getDbPort = -> fetchProp 'db-port'
### ###
***Returns*** the log conf object ***Returns*** the log conf object

View file

@ -8,10 +8,7 @@ HTTP Listener
### ###
# **Requires:** # **Loads Modules:**
# - [Logging](logging.html)
log = require './logging'
# - [Request Handler](request-handler.html) # - [Request Handler](request-handler.html)
requestHandler = require './request-handler' requestHandler = require './request-handler'
@ -25,7 +22,8 @@ qs = require 'querystring'
express = require 'express' express = require 'express'
app = express() app = express()
#RedisStore = require('connect-redis')(express), # TODO use RedisStore for persistent sessions #TODO use RedisStore for persistent sessions
#RedisStore = require('connect-redis')(express),
### ###
Module call Module call
@ -34,9 +32,8 @@ Initializes the HTTP listener and its request handler.
@param {Object} args @param {Object} args
### ###
exports = module.exports = ( args ) -> exports = module.exports = ( args ) =>
args = args ? {} @log = args.logger
log args
requestHandler args requestHandler args
initRouting args[ 'http-port' ] initRouting args[ 'http-port' ]
module.exports module.exports
@ -47,15 +44,15 @@ Initializes the request routing and starts listening on the given port.
@param {int} port @param {int} port
@private initRouting( *fShutDown* ) @private initRouting( *fShutDown* )
### ###
initRouting = ( port ) -> initRouting = ( port ) =>
# Add cookie support for session handling. # Add cookie support for session handling.
app.use express.cookieParser() app.use express.cookieParser()
#TODO The session secret appriach needs to be fixed! #TODO The session secret approach needs to be fixed!
sess_sec = "149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw" sess_sec = "149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw"
app.use express.session { secret: sess_sec } app.use express.session { secret: sess_sec }
#At the moment there's no redis session backbone (didn't work straight away) #At the moment there's no redis session backbone (didn't work straight away)
log.print 'HL', 'no session backbone' @log.info 'HL | no session backbone'
# **Accepted requests to paths:** # **Accepted requests to paths:**
@ -83,10 +80,9 @@ initRouting = ( port ) ->
# - **`POST` to _"/user"_:** User requests are possible for all users with an account # - **`POST` to _"/user"_:** User requests are possible for all users with an account
app.post '/usercommand', requestHandler.handleUserCommand app.post '/usercommand', requestHandler.handleUserCommand
try try
app.listen port # inbound event channel @server = app.listen port # inbound event channel
catch e catch e
e.addInfo = 'opening port' @log.error e, 'HL | Unable to listen...'
log.error e
### ###
Adds the shutdown handler to the admin commands. Adds the shutdown handler to the admin commands.
@ -102,7 +98,11 @@ Shuts down the http listener.
@public shutDown() @public shutDown()
### ###
exports.shutDown = () -> exports.shutDown = () =>
log.print 'HL', 'Shutting down HTTP listener' @log.warn 'HL | Shutting down HTTP listener'
process.exit() # This is a bit brute force... console.log 'apppp'
console.log app
@server.close()
#TODO This is a bit brute force...
#process.exit()

View file

@ -9,7 +9,7 @@
# `node myapp.js | bunyan` # `node myapp.js | bunyan`
# **Requires:** # **Loads Modules:**
# - Node.js Module: [fs](http://nodejs.org/api/fs.html) and [path](http://nodejs.org/api/path.html) # - Node.js Module: [fs](http://nodejs.org/api/fs.html) and [path](http://nodejs.org/api/path.html)
fs = require 'fs' fs = require 'fs'

View file

@ -19,7 +19,7 @@ Persistence
### ###
# **Requires:** # **Loads Modules:**
# - External Modules: # - External Modules:
# [crypto-js](https://github.com/evanvosberg/crypto-js) and # [crypto-js](https://github.com/evanvosberg/crypto-js) and
@ -30,28 +30,21 @@ redis = require 'redis'
### ###
Module call Module call
----------- -----------
Initializes the DB connection. Requires a valid configuration file which contains Initializes the DB connection with the given `db-port` property in the `args` object.
a db port and a crypto key.
@param {Object} args @param {Object} args
### ###
exports = module.exports = ( args ) => exports = module.exports = ( args ) =>
@log = args.logger @log = args.logger
#TODO remove config, do it through args
config = require './config'
config args
@db?.quit() @db?.quit()
if config.isReady() #TODO we need to have a secure concept here, private keys per user
@crypto_key = config.getCryptoKey() @crypto_key = "}f6y1y}B{.an$}2c$Yl.$mSnF\\HX149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw;:DPV;4gy:qf]Zq{\"6sgK{,}^\"!]O;qBM3G?]h_`Psw=b6bVXKXry7*"
@db = redis.createClient config.getDBPort(), @db = redis.createClient args[ 'db-port' ],
'localhost', { connect_timeout: 2000 } 'localhost', { connect_timeout: 2000 }
@db.on 'error', ( err ) => @db.on 'error', ( err ) =>
err.addInfo = 'message from DB' @log.warn err, 'message from DB'
@log.error 'DB', err @ep = new IndexedModules( 'event-poller', @db, @log )
@ep = new IndexedModules( 'event-poller', @db, @log ) @ai = new IndexedModules( 'action-invoker', @db, @log )
@ai = new IndexedModules( 'action-invoker', @db, @log )
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 Checks whether the db is connected and passes either an error on failure after
@ -66,7 +59,7 @@ exports.isConnected = ( cb ) =>
numAttempts = 0 numAttempts = 0
fCheckConnection = => fCheckConnection = =>
if @db.connected if @db.connected
@log.info 'DB', 'Successfully connected to DB!' @log.info 'DB | Successfully connected to DB!'
cb() cb()
else if numAttempts++ < 10 else if numAttempts++ < 10
setTimeout fCheckConnection, 100 setTimeout fCheckConnection, 100
@ -83,10 +76,9 @@ Abstracts logging for simple action replies from the DB.
replyHandler = ( action ) => replyHandler = ( action ) =>
( err, reply ) => ( err, reply ) =>
if err if err
err.addInfo = "during '#{ action }'" @log.warn err, "during '#{ action }'"
@log.error 'DB', err
else else
@log.info 'DB', "#{ action }: #{ reply }" @log.info "DB | #{ action }: #{ reply }"
### ###
Push an event into the event queue. Push an event into the event queue.
@ -96,10 +88,10 @@ Push an event into the event queue.
### ###
exports.pushEvent = ( oEvent ) => exports.pushEvent = ( oEvent ) =>
if oEvent if oEvent
@log.info 'DB', "Event pushed into the queue: '#{ oEvent.eventid }'" @log.info "DB | Event pushed into the queue: '#{ oEvent.eventid }'"
@db.rpush 'event_queue', JSON.stringify( oEvent ) @db.rpush 'event_queue', JSON.stringify( oEvent )
else else
@log.error 'DB', 'Why would you give me an empty event...' @log.warn 'DB | Why would you give me an empty event...'
### ###
@ -133,8 +125,7 @@ hash = ( plainText ) =>
try try
( crypto.SHA3 plainText, { outputLength: 512 } ).toString() ( crypto.SHA3 plainText, { outputLength: 512 } ).toString()
catch err catch err
err.addInfo = 'during hashing' @log.warn err, 'DB | during hashing'
@log.error 'DB', err
null null
@ -149,8 +140,7 @@ encrypt = ( plainText ) =>
try try
crypto.AES.encrypt plainText, @crypto_key crypto.AES.encrypt plainText, @crypto_key
catch err catch err
err.addInfo = 'during encryption' @log.warn err, 'DB | during encryption'
@log.error 'DB', err
null null
### ###
@ -165,8 +155,7 @@ decrypt = ( crypticText ) =>
dec = crypto.AES.decrypt crypticText, @crypto_key dec = crypto.AES.decrypt crypticText, @crypto_key
dec.toString(crypto.enc.Utf8) dec.toString(crypto.enc.Utf8)
catch err catch err
err.addInfo = 'during decryption' @log.warn err, 'DB | during decryption'
@log.error 'DB', err
null null
### ###
@ -181,13 +170,12 @@ data objects via the provided function and returns the results to cb(err, obj).
the retrieved data or an error the retrieved data or an error
### ###
getSetRecords = ( set, fSingle, cb ) => getSetRecords = ( set, fSingle, cb ) =>
@log.info 'DB', "Fetching set records: '#{ set }'" @log.info "DB | Fetching set records: '#{ set }'"
# Fetch all members of the set # Fetch all members of the set
@db.smembers set, ( err, arrReply ) => @db.smembers set, ( err, arrReply ) =>
if err if err
# If an error happens we return it to the callback function # If an error happens we return it to the callback function
err.addInfo = "fetching '#{ set }'" @log.warn err, "DB | fetching '#{ set }'"
@log.error 'DB', err
cb err cb err
else if arrReply.length == 0 else if arrReply.length == 0
# If the set was empty we return null to the callback # If the set was empty we return null to the callback
@ -210,11 +198,10 @@ getSetRecords = ( set, fSingle, cb ) =>
( err, data ) => ( err, data ) =>
--semaphore --semaphore
if err if err
err.addInfo = "fetching single element: '#{ prop }'" @log.warn err, "DB | fetching single element: '#{ prop }'"
@log.error 'DB', err
else if not data else if not data
# There was no data behind the key # There was no data behind the key
@log.error 'DB', new Error "Empty key in DB: '#{ prop }'" @log.warn new Error "Empty key in DB: '#{ prop }'"
else else
# We found a valid record and add it to the reply object # We found a valid record and add it to the reply object
objReplies[ prop ] = data objReplies[ prop ] = data
@ -229,52 +216,52 @@ getSetRecords = ( set, fSingle, cb ) =>
class IndexedModules class IndexedModules
constructor: ( @setname, @db, @log ) -> constructor: ( @setname, @db, @log ) ->
@log.info 'DB', "Instantiated indexed modules for '#{ @setname }'" @log.info "DB | Instantiated indexed modules for '#{ @setname }'"
storeModule: ( mId, data ) => storeModule: ( mId, data ) =>
@log.info 'DB', "storeModule(#{ @setname }): #{ mId }" @log.info "DB | storeModule(#{ @setname }): #{ mId }"
@db.sadd "#{ @setname }s", mId, @db.sadd "#{ @setname }s", mId,
replyHandler "Storing '#{ @setname }' key '#{ mId }'" replyHandler "Storing '#{ @setname }' key '#{ mId }'"
@db.set "#{ @setname }:#{ mId }", data, @db.set "#{ @setname }:#{ mId }", data,
replyHandler "Storing '#{ @setname }:#{ mId }'" replyHandler "Storing '#{ @setname }:#{ mId }'"
getModule: ( mId, cb ) => getModule: ( mId, cb ) =>
@log.info 'DB', "getModule('#{ @setname }): #{ mId }'" @log.info "DB | getModule('#{ @setname }): #{ mId }'"
@db.get "#{ @setname }:#{ mId }", cb @db.get "#{ @setname }:#{ mId }", cb
getModuleIds: ( cb ) => getModuleIds: ( cb ) =>
@log.info 'DB', "getModuleIds(#{ @setname })" @log.info "DB | getModuleIds(#{ @setname })"
@db.smembers "#{ @setname }s", cb @db.smembers "#{ @setname }s", cb
getModules: ( cb ) => getModules: ( cb ) =>
@log.info 'DB', "getModules(#{ @setname })" @log.info "DB | getModules(#{ @setname })"
getSetRecords "#{ @setname }s", @getModule, cb getSetRecords "#{ @setname }s", @getModule, cb
deleteModule: ( mId ) => deleteModule: ( mId ) =>
@log.info 'DB', "deleteModule(#{ @setname }): #{ mId }" @log.info "DB | deleteModule(#{ @setname }): #{ mId }"
@db.srem "#{ @setname }s", mId, @db.srem "#{ @setname }s", mId,
replyHandler "Deleting '#{ @setname }' key '#{ mId }'" replyHandler "Deleting '#{ @setname }' key '#{ mId }'"
@db.del "#{ @setname }:#{ mId }", @db.del "#{ @setname }:#{ mId }",
replyHandler "Deleting '#{ @setname }:#{ mId }'" replyHandler "Deleting '#{ @setname }:#{ mId }'"
storeParameters: ( mId, userId, data ) => storeParameters: ( mId, userId, data ) =>
@log.info 'DB', "storeParameters(#{ @setname }): '#{ mId }:#{ userId }'" @log.info "DB | storeParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }", @db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "Storing '#{ @setname }' module parameters key '#{ mId }'" replyHandler "Storing '#{ @setname }' module parameters key '#{ mId }'"
@db.set "#{ @setname }-params:#{ mId }:#{ userId }", encrypt(data), @db.set "#{ @setname }-params:#{ mId }:#{ userId }", encrypt(data),
replyHandler "Storing '#{ @setname }' module parameters '#{ mId }:#{ userId }'" replyHandler "Storing '#{ @setname }' module parameters '#{ mId }:#{ userId }'"
getParameters: ( mId, userId, cb ) => getParameters: ( mId, userId, cb ) =>
@log.info 'DB', "getParameters(#{ @setname }): '#{ mId }:#{ userId }'" @log.info "DB | getParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@db.get "#{ @setname }-params:#{ mId }:#{ userId }", ( err, data ) -> @db.get "#{ @setname }-params:#{ mId }:#{ userId }", ( err, data ) ->
cb err, decrypt data cb err, decrypt data
getParametersIds: ( cb ) => getParametersIds: ( cb ) =>
@log.info 'DB', "getParametersIds(#{ @setname })" @log.info "DB | getParametersIds(#{ @setname })"
@db.smembers "#{ @setname }-params", cb @db.smembers "#{ @setname }-params", cb
deleteParameters: ( mId, userId ) => deleteParameters: ( mId, userId ) =>
@log.info 'DB', "deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'" @log.info "DB | deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@db.srem "#{ @setname }-params", "#{ mId }:#{ userId }", @db.srem "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "Deleting '#{ @setname }-params' key '#{ mId }:#{ userId }'" replyHandler "Deleting '#{ @setname }-params' key '#{ mId }:#{ userId }'"
@db.del "#{ @setname }-params:#{ mId }:#{ userId }", @db.del "#{ @setname }-params:#{ mId }:#{ userId }",
@ -479,7 +466,7 @@ Query the DB for a rule and pass it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRule = ( ruleId, cb ) => exports.getRule = ( ruleId, cb ) =>
@log.info 'DB', "getRule: '#{ ruleId }'" @log.info "DB | getRule: '#{ ruleId }'"
@db.get "rule:#{ ruleId }", cb @db.get "rule:#{ ruleId }", cb
### ###
@ -489,7 +476,7 @@ Fetch all rules and pass them to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRules = ( cb ) => exports.getRules = ( cb ) =>
@log.info 'DB', 'Fetching all Rules' @log.info 'DB | Fetching all Rules'
getSetRecords 'rules', exports.getRule, cb getSetRecords 'rules', exports.getRule, cb
### ###
@ -499,7 +486,7 @@ Fetch all rule IDs and hand it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRuleIds = ( cb ) => exports.getRuleIds = ( cb ) =>
@log.info 'DB', 'Fetching all Rule IDs' @log.info 'DB | Fetching all Rule IDs'
@db.smembers 'rules', cb @db.smembers 'rules', cb
### ###
@ -510,7 +497,7 @@ Store a string representation of a rule in the DB.
@param {String} data @param {String} data
### ###
exports.storeRule = ( ruleId, data ) => exports.storeRule = ( ruleId, data ) =>
@log.info 'DB', "storeRule: '#{ ruleId }'" @log.info "DB | storeRule: '#{ ruleId }'"
@db.sadd 'rules', "#{ ruleId }", @db.sadd 'rules', "#{ ruleId }",
replyHandler "storing rule key '#{ ruleId }'" replyHandler "storing rule key '#{ ruleId }'"
@db.set "rule:#{ ruleId }", data, @db.set "rule:#{ ruleId }", data,
@ -524,7 +511,7 @@ Delete a string representation of a rule.
@param {String} userId @param {String} userId
### ###
exports.deleteRule = ( ruleId ) => exports.deleteRule = ( ruleId ) =>
@log.info 'DB', "deleteRule: '#{ ruleId }'" @log.info "DB | deleteRule: '#{ ruleId }'"
@db.srem "rules", ruleId, replyHandler "Deleting rule key '#{ ruleId }'" @db.srem "rules", ruleId, replyHandler "Deleting rule key '#{ ruleId }'"
@db.del "rule:#{ ruleId }", replyHandler "Deleting rule '#{ ruleId }'" @db.del "rule:#{ ruleId }", replyHandler "Deleting rule '#{ ruleId }'"
@ -552,7 +539,7 @@ Associate a rule to a user.
@param {String} userId @param {String} userId
### ###
exports.linkRule = ( ruleId, userId ) => exports.linkRule = ( ruleId, userId ) =>
@log.info 'DB', "linkRule: '#{ ruleId }' for user '#{ userId }'" @log.info "DB | linkRule: '#{ ruleId }' for user '#{ userId }'"
@db.sadd "rule:#{ ruleId }:users", userId, @db.sadd "rule:#{ ruleId }:users", userId,
replyHandler "storing user '#{ userId }' for rule key '#{ ruleId }'" replyHandler "storing user '#{ userId }' for rule key '#{ ruleId }'"
@db.sadd "user:#{ userId }:rules", ruleId, @db.sadd "user:#{ userId }:rules", ruleId,
@ -566,7 +553,7 @@ Get rules linked to a user and hand it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getUserLinkedRules = ( userId, cb ) => exports.getUserLinkedRules = ( userId, cb ) =>
@log.info 'DB', "getUserLinkedRules: for user '#{ userId }'" @log.info "DB | getUserLinkedRules: for user '#{ userId }'"
@db.smembers "user:#{ userId }:rules", cb @db.smembers "user:#{ userId }:rules", cb
### ###
@ -577,7 +564,7 @@ Get users linked to a rule and hand it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRuleLinkedUsers = ( ruleId, cb ) => exports.getRuleLinkedUsers = ( ruleId, cb ) =>
@log.info 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'" @log.info "DB | getRuleLinkedUsers: for rule '#{ ruleId }'"
@db.smembers "rule:#{ ruleId }:users", cb @db.smembers "rule:#{ ruleId }:users", cb
### ###
@ -588,7 +575,7 @@ Delete an association of a rule to a user.
@param {String} userId @param {String} userId
### ###
exports.unlinkRule = ( ruleId, userId ) => exports.unlinkRule = ( ruleId, userId ) =>
@log.info 'DB', "unlinkRule: '#{ ruleId }:#{ userId }'" @log.info "DB | unlinkRule: '#{ ruleId }:#{ userId }'"
@db.srem "rule:#{ ruleId }:users", userId, @db.srem "rule:#{ ruleId }:users", userId,
replyHandler "removing user '#{ userId }' for rule key '#{ ruleId }'" replyHandler "removing user '#{ userId }' for rule key '#{ ruleId }'"
@db.srem "user:#{ userId }:rules", ruleId, @db.srem "user:#{ userId }:rules", ruleId,
@ -602,7 +589,7 @@ Activate a rule.
@param {String} userId @param {String} userId
### ###
exports.activateRule = ( ruleId, userId ) => exports.activateRule = ( ruleId, userId ) =>
@log.info 'DB', "activateRule: '#{ ruleId }' for '#{ userId }'" @log.info "DB | activateRule: '#{ ruleId }' for '#{ userId }'"
@db.sadd "rule:#{ ruleId }:active-users", userId, @db.sadd "rule:#{ ruleId }:active-users", userId,
replyHandler "storing activated user '#{ userId }' in rule '#{ ruleId }'" replyHandler "storing activated user '#{ userId }' in rule '#{ ruleId }'"
@db.sadd "user:#{ userId }:active-rules", ruleId, @db.sadd "user:#{ userId }:active-rules", ruleId,
@ -616,7 +603,7 @@ Get rules activated for a user and hand it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getUserActivatedRules = ( userId, cb ) => exports.getUserActivatedRules = ( userId, cb ) =>
@log.info 'DB', "getUserActivatedRules: for user '#{ userId }'" @log.info "DB | getUserActivatedRules: for user '#{ userId }'"
@db.smembers "user:#{ userId }:active-rules", cb @db.smembers "user:#{ userId }:active-rules", cb
### ###
@ -627,7 +614,7 @@ Get users activated for a rule and hand it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRuleActivatedUsers = ( ruleId, cb ) => exports.getRuleActivatedUsers = ( ruleId, cb ) =>
@log.info 'DB', "getRuleActivatedUsers: for rule '#{ ruleId }'" @log.info "DB | getRuleActivatedUsers: for rule '#{ ruleId }'"
@db.smembers "rule:#{ ruleId }:active-users", cb @db.smembers "rule:#{ ruleId }:active-users", cb
### ###
@ -638,7 +625,7 @@ Deactivate a rule.
@param {String} userId @param {String} userId
### ###
exports.deactivateRule = ( ruleId, userId ) => exports.deactivateRule = ( ruleId, userId ) =>
@log.info 'DB', "deactivateRule: '#{ ruleId }' for '#{ userId }'" @log.info "DB | deactivateRule: '#{ ruleId }' for '#{ userId }'"
@db.srem "rule:#{ ruleId }:active-users", userId, @db.srem "rule:#{ ruleId }:active-users", userId,
replyHandler "removing activated user '#{ userId }' in rule '#{ ruleId }'" replyHandler "removing activated user '#{ userId }' in rule '#{ ruleId }'"
@db.srem "user:#{ userId }:active-rules", ruleId, @db.srem "user:#{ userId }:active-rules", ruleId,
@ -651,7 +638,7 @@ Fetch all active ruleIds and pass them to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getAllActivatedRuleIdsPerUser = ( cb ) => exports.getAllActivatedRuleIdsPerUser = ( cb ) =>
@log.info 'DB', "Fetching all active rules" @log.info "DB | Fetching all active rules"
@db.smembers 'users', ( err, obj ) => @db.smembers 'users', ( err, obj ) =>
result = {} result = {}
if obj.length is 0 if obj.length is 0
@ -681,7 +668,7 @@ The password should be hashed before it is passed to this function.
exports.storeUser = ( objUser ) => exports.storeUser = ( objUser ) =>
#TODO Only store user if not already existing, or at least only then add a private key #TODO Only store user if not already existing, or at least only then add a private key
#for his encryption. we would want to have one private key per user, right? #for his encryption. we would want to have one private key per user, right?
@log.info 'DB', "storeUser: '#{ objUser.username }'" @log.info "DB | storeUser: '#{ objUser.username }'"
if objUser and objUser.username and objUser.password if objUser and objUser.username and objUser.password
@db.sadd 'users', objUser.username, @db.sadd 'users', objUser.username,
replyHandler "storing user key '#{ objUser.username }'" replyHandler "storing user key '#{ objUser.username }'"
@ -689,7 +676,7 @@ exports.storeUser = ( objUser ) =>
@db.hmset "user:#{ objUser.username }", objUser, @db.hmset "user:#{ objUser.username }", objUser,
replyHandler "storing user properties '#{ objUser.username }'" replyHandler "storing user properties '#{ objUser.username }'"
else else
@log.error 'DB', new Error 'username or password was missing' @log.warn new Error 'DB | username or password was missing'
### ###
Fetch all user IDs and pass them to cb(err, obj). Fetch all user IDs and pass them to cb(err, obj).
@ -698,7 +685,7 @@ Fetch all user IDs and pass them to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getUserIds = ( cb ) => exports.getUserIds = ( cb ) =>
@log.info 'DB', "getUserIds" @log.info "DB | getUserIds"
@db.smembers "users", cb @db.smembers "users", cb
### ###
@ -709,7 +696,7 @@ Fetch a user by id and pass it to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getUser = ( userId, cb ) => exports.getUser = ( userId, cb ) =>
@log.info 'DB', "getUser: '#{ userId }'" @log.info "DB | getUser: '#{ userId }'"
@db.hgetall "user:#{ userId }", cb @db.hgetall "user:#{ userId }", cb
### ###
@ -719,7 +706,7 @@ Deletes a user and all his associated linked and active rules.
@param {String} userId @param {String} userId
### ###
exports.deleteUser = ( userId ) => exports.deleteUser = ( userId ) =>
@log.info 'DB', "deleteUser: '#{ userId }'" @log.info "DB | deleteUser: '#{ userId }'"
@db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'" @db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'"
@db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'" @db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'"
@ -763,14 +750,14 @@ because we only store hashes of passwords for security6 reasons.
### ###
#TODO verify and test whole function #TODO verify and test whole function
exports.loginUser = ( userId, password, cb ) => exports.loginUser = ( userId, password, cb ) =>
@log.info 'DB', "User '#{ userId }' tries to log in" @log.info "DB | User '#{ userId }' tries to log in"
fCheck = ( pw ) => fCheck = ( pw ) =>
( err, obj ) => ( err, obj ) =>
if err if err
cb err, null cb err, null
else if obj and obj.password else if obj and obj.password
if pw == obj.password if pw == obj.password
@log.info 'DB', "User '#{ obj.username }' logged in!" @log.info "DB | User '#{ obj.username }' logged in!"
cb null, obj cb null, obj
else else
cb (new Error 'Wrong credentials!'), null cb (new Error 'Wrong credentials!'), null
@ -793,7 +780,7 @@ Associate a role with a user.
@param {String} role @param {String} role
### ###
exports.storeUserRole = ( userId, role ) => exports.storeUserRole = ( userId, role ) =>
@log.info 'DB', "storeUserRole: '#{ userId }:#{ role }'" @log.info "DB | storeUserRole: '#{ userId }:#{ role }'"
@db.sadd 'roles', role, replyHandler "adding role '#{ role }' to role index set" @db.sadd 'roles', role, replyHandler "adding role '#{ role }' to role index set"
@db.sadd "user:#{ userId }:roles", role, @db.sadd "user:#{ userId }:roles", role,
replyHandler "adding role '#{ role }' to user '#{ userId }'" replyHandler "adding role '#{ role }' to user '#{ userId }'"
@ -808,7 +795,7 @@ Fetch all roles of a user and pass them to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getUserRoles = ( userId, cb ) => exports.getUserRoles = ( userId, cb ) =>
@log.info 'DB', "getUserRoles: '#{ userId }'" @log.info "DB | getUserRoles: '#{ userId }'"
@db.smembers "user:#{ userId }:roles", cb @db.smembers "user:#{ userId }:roles", cb
### ###
@ -819,7 +806,7 @@ Fetch all users of a role and pass them to cb(err, obj).
@param {function} cb @param {function} cb
### ###
exports.getRoleUsers = ( role, cb ) => exports.getRoleUsers = ( role, cb ) =>
@log.info 'DB', "getRoleUsers: '#{ role }'" @log.info "DB | getRoleUsers: '#{ role }'"
@db.smembers "role:#{ role }:users", cb @db.smembers "role:#{ role }:users", cb
### ###
@ -830,7 +817,7 @@ Remove a role from a user.
@param {String} userId @param {String} userId
### ###
exports.removeUserRole = ( userId, role ) => exports.removeUserRole = ( userId, role ) =>
@log.info 'DB', "removeRoleFromUser: role '#{ role }', user '#{ userId }'" @log.info "DB | removeRoleFromUser: role '#{ role }', user '#{ userId }'"
@db.srem "user:#{ userId }:roles", role, @db.srem "user:#{ userId }:roles", role,
replyHandler "Removing role '#{ role }' from user '#{ userId }'" replyHandler "Removing role '#{ role }' from user '#{ userId }'"
@db.srem "role:#{ role }:users", userId, @db.srem "role:#{ role }:users", userId,

View file

@ -2,14 +2,14 @@
Request Handler Request Handler
============ ============
> TODO Add documentation > The request handler (surprisingly) handles requests made through HTTP to
> the [HTTP Listener](http-listener.html). It will handle user requests for
> pages as well as POST requests such as user login, module storing, event
> invocation and also admin commands.
### ###
# **Requires:** # **Loads Modules:**
# - [Logging](logging.html)
log = require './logging'
# - [Persistence](persistence.html) # - [Persistence](persistence.html)
db = require './persistence' db = require './persistence'
@ -40,8 +40,7 @@ objUserCmds =
objAdminCmds = {} objAdminCmds = {}
exports = module.exports = ( args ) -> exports = module.exports = ( args ) ->
args = args ? {} log = args.logger
log args
db args db args
mm args mm args
mm.addDBLink db mm.addDBLink db
@ -105,7 +104,7 @@ exports.handleLogin = ( req, resp ) ->
db.loginUser obj.username, obj.password, ( err, usr ) -> db.loginUser obj.username, obj.password, ( err, usr ) ->
if(err) if(err)
# Tapping on fingers, at least in log... # Tapping on fingers, at least in log...
log.print 'RH', "AUTH-UH-OH (#{obj.username}): " + err.message log.warn err, "RH | AUTH-UH-OH (#{obj.username})"
else else
# no error, so we can associate the user object from the DB to the session # no error, so we can associate the user object from the DB to the session
req.session.user = usr req.session.user = usr
@ -280,7 +279,7 @@ exports.handleAdmin = ( req, resp ) =>
if req.session and req.session.user if req.session and req.session.user
if req.session.user.isAdmin is "true" if req.session.user.isAdmin is "true"
q = req.query q = req.query
log.print 'RH', 'Received admin request: ' + req.originalUrl log.info 'RH | Received admin request: ' + req.originalUrl
if q.cmd if q.cmd
@objAdminCmds[q.cmd]? q, answerHandler req, resp, true @objAdminCmds[q.cmd]? q, answerHandler req, resp, true
else else

View file

@ -1,16 +0,0 @@
bunyan = require 'bunyan'
opt =
name: "webapi-eca"
opt.streams = [
{
level: 'info'
stream: process.stdout
},
{
level: 'info'
path: 'logs/server.log'
}
]
# Finally we create the bunyan logger
logger = bunyan.createLogger opt
logger.info 'weeee'

View file

@ -10,7 +10,7 @@ WebAPI-ECA Engine
> See below in the optimist CLI preparation for allowed optional parameters `[opt]`. > See below in the optimist CLI preparation for allowed optional parameters `[opt]`.
### ###
# **Requires:** # **Loads Modules:**
# - [Logging](logging.html) # - [Logging](logging.html)
logger = require './logging' logger = require './logging'
@ -92,20 +92,19 @@ Error handling of the express port listener requires special attention,
thus we have to catch the process error, which is issued if thus we have to catch the process error, which is issued if
the port is already in use. the port is already in use.
### ###
process.on 'uncaughtException', ( err ) -> process.on 'uncaughtException', ( err ) =>
switch err.errno switch err.errno
when 'EADDRINUSE' when 'EADDRINUSE'
err.addInfo = 'http-port already in use, shutting down!' @log.error err, 'RS | http-port already in use, shutting down!'
log.error 'RS', err
shutDown() shutDown()
# else log.error 'RS', err # else @log.error 'RS', err
else throw err else throw err
### ###
This function is invoked right after the module is loaded and starts the server. This function is invoked right after the module is loaded and starts the server.
@private init() @private init()
### ###
init = -> init = =>
conf argv.c conf argv.c
# > Check whether the config file is ready, which is required to start the server. # > Check whether the config file is ready, which is required to start the server.
if !conf.isReady() if !conf.isReady()
@ -125,36 +124,39 @@ init = ->
logconf[ 'nolog' ] = argv.n logconf[ 'nolog' ] = argv.n
try try
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ] fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
log = logger logconf @log = logger.getLogger logconf
log.info 'RS | STARTING SERVER' @log.info 'RS | STARTING SERVER'
args = args =
logger: log logger: @log
logconf: logconf logconf: logconf
# > Fetch the `http-port` argument # > Fetch the `http-port` argument
args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort() args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort()
args[ 'db-port' ] = parseInt argv.w || conf.getDbPort()
log.info 'RS | Initialzing DB' @log.info 'RS | Initialzing DB'
db args db args
# > We only proceed with the initialization if the DB is ready # > We only proceed with the initialization if the DB is ready
db.isConnected ( err, result ) -> db.isConnected ( err, result ) =>
if !err if err
shutDown()
else
# > Initialize all required modules with the args object. # > Initialize all required modules with the args object.
log.info 'RS | Initialzing engine' @log.info 'RS | Initialzing engine'
engine args engine args
log.info 'RS | Initialzing http listener' @log.info 'RS | Initialzing http listener'
http args http args
# > Distribute handlers between modules to link the application. # > Distribute handlers between modules to link the application.
log.info 'RS | Passing handlers to engine' @log.info 'RS | Passing handlers to engine'
engine.addPersistence db engine.addPersistence db
log.info 'RS | Passing handlers to http listener' @log.info 'RS | Passing handlers to http listener'
#TODO engine pushEvent needs to go into redis queue #TODO engine pushEvent needs to go into redis queue
http.addShutdownHandler shutDown http.addShutdownHandler shutDown
#TODO loadAction and addRule will be removed #TODO loadAction and addRule will be removed
#mm.addHandlers db, engine.loadActionModule, engine.addRule #mm.addHandlers db, engine.loadActionModule, engine.addRule
log.info 'RS | For e child process for the event poller' @log.info 'RS | Forking child process for the event poller'
cliArgs = [ cliArgs = [
args.logconf['mode'] args.logconf['mode']
args.logconf['io-level'] args.logconf['io-level']
@ -169,10 +171,11 @@ Shuts down the server.
@private shutDown() @private shutDown()
### ###
shutDown = -> shutDown = =>
log.warn 'RS | Received shut down command!' @log.warn 'RS | Received shut down command!'
engine?.shutDown() engine?.shutDown()
http?.shutDown() http?.shutDown()
process.exit()
### ###
## Process Commands ## Process Commands
@ -182,6 +185,9 @@ from the parent process (e.g. the testing suite)
### ###
process.on 'message', ( cmd ) -> procCmds[cmd]?() process.on 'message', ( cmd ) -> procCmds[cmd]?()
process.on 'SIGINT', shutDown
process.on 'SIGTERM', shutDown
# The die command redirects to the shutDown function. # The die command redirects to the shutDown function.
procCmds.die = shutDown procCmds.die = shutDown

View file

@ -52,7 +52,7 @@ Configuration
loadConfigFile = function(configPath) { loadConfigFile = function(configPath) {
var confProperties, e, isReady, prop, _i, _len; var confProperties, e, isReady, prop, _i, _len;
_this.config = null; _this.config = null;
confProperties = ['log', 'http-port', 'db-port', 'crypto-key']; confProperties = ['log', 'http-port', 'db-port'];
try { try {
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath))); _this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath)));
isReady = true; isReady = true;
@ -115,7 +115,7 @@ Configuration
*/ */
exports.getDBPort = function() { exports.getDbPort = function() {
return fetchProp('db-port'); return fetchProp('db-port');
}; };

View file

@ -1,17 +1,15 @@
'use strict'; 'use strict';
var path = require('path'), var path = require('path'),
log = require('./logging'),
// qEvents = new (require('./queue')).Queue(), //TODO export queue into redis // qEvents = new (require('./queue')).Queue(), //TODO export queue into redis
regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X
listRules = {}, listRules = {},
listActionModules = {}, listActionModules = {},
isRunning = true, isRunning = true,
mm, poller, db; mm, poller, db, log;
exports = module.exports = function( args ) { exports = module.exports = function( args ) {
args = args || {}; log = args.logger;
log(args);
mm = require('./module-manager')(args); mm = require('./module-manager')(args);
return module.exports; return module.exports;
}; };
@ -28,12 +26,12 @@ exports.addPersistence = function(db_link) {
// if(err) log.error('EN', 'retrieving Action Modules from DB!'); // if(err) log.error('EN', 'retrieving Action Modules from DB!');
// else { // else {
// if(!obj) { // if(!obj) {
// log.print('EN', 'No Action Modules found in DB!'); // log.info('EN', 'No Action Modules found in DB!');
// loadRulesFromDB(); // loadRulesFromDB();
// } else { // } else {
// var m; // var m;
// for(var el in obj) { // for(var el in obj) {
// log.print('EN', 'Loading Action Module from DB: ' + el); // log.info('EN', 'Loading Action Module from DB: ' + el);
// try{ // try{
// m = mm.requireFromString(obj[el], el); // m = mm.requireFromString(obj[el], el);
// db.getActionModuleAuth(el, function(mod) { // db.getActionModuleAuth(el, function(mod) {
@ -75,7 +73,7 @@ exports.loadActionModule = function(name, objModule) {
// TODO only load module once, load user specific parameters per user // TODO only load module once, load user specific parameters per user
// when rule is activated by user. invoked action then uses user specific // when rule is activated by user. invoked action then uses user specific
// parameters // parameters
log.print('EN', 'Action module "' + name + '" loaded'); log.info('EN', 'Action module "' + name + '" loaded');
listActionModules[name] = objModule; listActionModules[name] = objModule;
}; };
@ -89,17 +87,17 @@ exports.getActionModule = function(name) {
*/ */
exports.addRule = function(objRule) { exports.addRule = function(objRule) {
//TODO validate rule //TODO validate rule
log.print('EN', 'Loading Rule'); log.info('EN', 'Loading Rule');
log.print('EN', objRule); log.info('EN', objRule);
log.print('EN', 'Loading Rule: ' + objRule.id); log.info('EN', 'Loading Rule: ' + objRule.id);
if(listRules[objRule.id]) log.print('EN', 'Replacing rule: ' + objRule.id); if(listRules[objRule.id]) log.info('EN', 'Replacing rule: ' + objRule.id);
listRules[objRule.id] = objRule; listRules[objRule.id] = objRule;
// Notify poller about eventual candidate // Notify poller about eventual candidate
try { try {
poller.send('event|'+objRule.event); poller.send('event|'+objRule.event);
} catch (err) { } catch (err) {
log.print('EN', 'Unable to inform poller about new active rule!'); log.info('EN', 'Unable to inform poller about new active rule!');
} }
}; };
@ -119,7 +117,7 @@ function pollQueue() {
* @param {Object} evt The event object * @param {Object} evt The event object
*/ */
function processEvent(evt) { function processEvent(evt) {
log.print('EN', 'processing event: ' + evt.event + '(' + evt.eventid + ')'); log.info('EN', 'processing event: ' + evt.event + '(' + evt.eventid + ')');
var actions = checkEvent(evt); var actions = checkEvent(evt);
for(var i = 0; i < actions.length; i++) { for(var i = 0; i < actions.length; i++) {
invokeAction(evt, actions[i]); invokeAction(evt, actions[i]);
@ -137,7 +135,7 @@ function checkEvent(evt) {
//TODO this needs to get depth safe, not only data but eventually also //TODO this needs to get depth safe, not only data but eventually also
// on one level above (eventid and other meta) // on one level above (eventid and other meta)
if(listRules[rn].event === evt.event && validConditions(evt.payload, listRules[rn])) { if(listRules[rn].event === evt.event && validConditions(evt.payload, listRules[rn])) {
log.print('EN', 'Rule "' + rn + '" fired'); log.info('EN', 'Rule "' + rn + '" fired');
actions = actions.concat(listRules[rn].actions); actions = actions.concat(listRules[rn].actions);
} }
} }
@ -181,7 +179,7 @@ function invokeAction(evt, action) {
log.error('EN', 'during action execution: ' + err); log.error('EN', 'during action execution: ' + err);
} }
} }
else log.print('EN', 'No api interface found for: ' + action.module); else log.info('EN', 'No api interface found for: ' + action.module);
} }
/** /**
@ -229,7 +227,7 @@ function preprocessActionArguments(evt, act, res) {
} }
exports.shutDown = function() { exports.shutDown = function() {
log.print('EN', 'Shutting down Poller and DB Link'); log.info('EN', 'Shutting down Poller and DB Link');
isRunning = false; isRunning = false;
if(poller) poller.send('cmd|shutdown'); if(poller) poller.send('cmd|shutdown');
if(db) db.shutDown(); if(db) db.shutDown();

View file

@ -29,7 +29,7 @@ function init() {
logconf['file-path'] = process.argv[5] logconf['file-path'] = process.argv[5]
logconf['nolog'] = process.argv[6] logconf['nolog'] = process.argv[6]
log = logger(logconf); log = logger.getLogger(logconf);
var args = { logger: log }; var args = { logger: log };
(ml = require('./module-manager'))(args); (ml = require('./module-manager'))(args);
(db = require('./persistence'))(args); (db = require('./persistence'))(args);
@ -39,6 +39,12 @@ function init() {
log.info('Event Poller instantiated'); log.info('Event Poller instantiated');
}; };
function shutDown() {
log.info('EP', 'Shutting down DB Link');
isRunning = false;
if(db) db.shutDown();
process.exit();
}
function loadEventModule(el, cb) { function loadEventModule(el, cb) {
if(db && ml) db.getEventModule(el, function(err, obj) { if(db && ml) db.getEventModule(el, function(err, obj) {
@ -47,7 +53,7 @@ function loadEventModule(el, cb) {
else log.error('EP', 'Retrieving Event Module ' + el + ' from DB!'); else log.error('EP', 'Retrieving Event Module ' + el + ' from DB!');
} }
else { else {
// log.print('EP', 'Loading Event Module: ' + el); // log.info('EP', 'Loading Event Module: ' + el);
try { try {
var m = ml.requireFromString(obj, el); var m = ml.requireFromString(obj, el);
db.getEventModuleAuth(el, function(mod) { db.getEventModuleAuth(el, function(mod) {
@ -71,13 +77,13 @@ function fetchPollFunctionFromModule(mod, func) {
if(mod) mod = mod[func[i]]; if(mod) mod = mod[func[i]];
} }
if(mod) { if(mod) {
log.print('EP', 'Found active event module "' + func.join('->') + '", adding it to polling list'); log.info('EP', 'Found active event module "' + func.join('->') + '", adding it to polling list');
//FIXME change this to [module][prop] = module; because like this identical properties get overwritten //FIXME change this to [module][prop] = module; because like this identical properties get overwritten
// also add some on a per user basis information because this should go into a user context for the users // also add some on a per user basis information because this should go into a user context for the users
// that sat up this rule! // that sat up this rule!
listPoll[func.join('->')] = mod; listPoll[func.join('->')] = mod;
} else { } else {
log.print('EP', 'No property "' + func.join('->') + '" found'); log.info('EP', 'No property "' + func.join('->') + '" found');
} }
} }
@ -88,11 +94,11 @@ function initMessageActions() {
if(listEventModules[arrModule[0]]) { if(listEventModules[arrModule[0]]) {
fetchPollFunctionFromModule(listEventModules[arrModule[0]], arrModule); fetchPollFunctionFromModule(listEventModules[arrModule[0]], arrModule);
} else { } else {
log.print('EP', 'Event Module ' + arrModule[0] + ' needs to be loaded, doing it now...'); log.info('EP', 'Event Module ' + arrModule[0] + ' needs to be loaded, doing it now...');
loadEventModule(arrModule[0], function(err, obj) { loadEventModule(arrModule[0], function(err, obj) {
if(err || !obj) log.error('EP', 'Event Module "' + arrModule[0] + '" not found: ' + err); if(err || !obj) log.error('EP', 'Event Module "' + arrModule[0] + '" not found: ' + err);
else { else {
log.print('EP', 'Event Module ' + arrModule[0] + ' found and loaded'); log.info('EP', 'Event Module ' + arrModule[0] + ' found and loaded');
fetchPollFunctionFromModule(obj, arrModule); fetchPollFunctionFromModule(obj, arrModule);
} }
}); });
@ -115,14 +121,13 @@ function initMessageActions() {
if(func) func(arrProps); if(func) func(arrProps);
} }
}); });
// very important so the process doesnt linger on when the paren process is killed
process.on('disconnect', shutDown);
} }
function initAdminCommands() { function initAdminCommands() {
listAdminCommands['shutdown'] = function(args) { listAdminCommands['shutdown'] = shutDown
log.print('EP', 'Shutting down DB Link');
isRunning = false;
if(db) db.shutDown();
};
} }
function checkRemotes() { function checkRemotes() {

View file

@ -10,9 +10,8 @@ HTTP Listener
(function() { (function() {
var app, exports, express, initRouting, log, path, qs, requestHandler; var app, exports, express, initRouting, path, qs, requestHandler,
_this = this;
log = require('./logging');
requestHandler = require('./request-handler'); requestHandler = require('./request-handler');
@ -34,8 +33,7 @@ HTTP Listener
exports = module.exports = function(args) { exports = module.exports = function(args) {
args = args != null ? args : {}; _this.log = args.logger;
log(args);
requestHandler(args); requestHandler(args);
initRouting(args['http-port']); initRouting(args['http-port']);
return module.exports; return module.exports;
@ -56,7 +54,7 @@ HTTP Listener
app.use(express.session({ app.use(express.session({
secret: sess_sec secret: sess_sec
})); }));
log.print('HL', 'no session backbone'); _this.log.info('HL | no session backbone');
app.use('/', express["static"](path.resolve(__dirname, '..', 'webpages', 'public'))); app.use('/', express["static"](path.resolve(__dirname, '..', 'webpages', 'public')));
app.get('/admin', requestHandler.handleAdmin); app.get('/admin', requestHandler.handleAdmin);
app.get('/forge_modules', requestHandler.handleForgeModules); app.get('/forge_modules', requestHandler.handleForgeModules);
@ -67,11 +65,10 @@ HTTP Listener
app.post('/logout', requestHandler.handleLogout); app.post('/logout', requestHandler.handleLogout);
app.post('/usercommand', requestHandler.handleUserCommand); app.post('/usercommand', requestHandler.handleUserCommand);
try { try {
return app.listen(port); return _this.server = app.listen(port);
} catch (_error) { } catch (_error) {
e = _error; e = _error;
e.addInfo = 'opening port'; return _this.log.error(e, 'HL | Unable to listen...');
return log.error(e);
} }
}; };
@ -95,8 +92,10 @@ HTTP Listener
exports.shutDown = function() { exports.shutDown = function() {
log.print('HL', 'Shutting down HTTP listener'); _this.log.warn('HL | Shutting down HTTP listener');
return process.exit(); console.log('apppp');
console.log(app);
return _this.server.close();
}; };
}).call(this); }).call(this);

View file

@ -11,12 +11,12 @@
var fs = require('fs'), var fs = require('fs'),
path = require('path'), path = require('path'),
log = require('./logging'), log,
db, funcLoadAction, funcLoadRule; db, funcLoadAction, funcLoadRule;
exports = module.exports = function(args) { exports = module.exports = function(args) {
args = args || {}; args = args || {};
log(args); log = args.logger;
return module.exports; return module.exports;
}; };
@ -82,7 +82,7 @@ exports.loadModules = function(directory, callback) {
log.error('LM', 'loading modules directory: ' + err); log.error('LM', 'loading modules directory: ' + err);
return; return;
} }
log.print('LM', 'Loading ' + list.length + ' modules from "' + directory + '"'); log.info('LM', 'Loading ' + list.length + ' modules from "' + directory + '"');
list.forEach(function (file) { list.forEach(function (file) {
fs.stat(path.resolve(__dirname, '..', directory, file), function (err, stat) { fs.stat(path.resolve(__dirname, '..', directory, file), function (err, stat) {
if (stat && stat.isDirectory()) { if (stat && stat.isDirectory()) {

View file

@ -32,35 +32,27 @@ Persistence
/* /*
Module call Module call
----------- -----------
Initializes the DB connection. Requires a valid configuration file which contains Initializes the DB connection with the given `db-port` property in the `args` object.
a db port and a crypto key.
@param {Object} args @param {Object} args
*/ */
exports = module.exports = function(args) { exports = module.exports = function(args) {
var config, _ref; var _ref;
_this.log = args.logger; _this.log = args.logger;
config = require('./config');
config(args);
if ((_ref = _this.db) != null) { if ((_ref = _this.db) != null) {
_ref.quit(); _ref.quit();
} }
if (config.isReady()) { _this.crypto_key = "}f6y1y}B{.an$}2c$Yl.$mSnF\\HX149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw;:DPV;4gy:qf]Zq{\"6sgK{,}^\"!]O;qBM3G?]h_`Psw=b6bVXKXry7*";
_this.crypto_key = config.getCryptoKey(); _this.db = redis.createClient(args['db-port'], 'localhost', {
_this.db = redis.createClient(config.getDBPort(), 'localhost', { connect_timeout: 2000
connect_timeout: 2000 });
}); _this.db.on('error', function(err) {
_this.db.on('error', function(err) { return _this.log.warn(err, 'message from DB');
err.addInfo = 'message from DB'; });
return _this.log.error('DB', err); _this.ep = new IndexedModules('event-poller', _this.db, _this.log);
}); return _this.ai = new IndexedModules('action-invoker', _this.db, _this.log);
_this.ep = new IndexedModules('event-poller', _this.db, _this.log);
return _this.ai = new IndexedModules('action-invoker', _this.db, _this.log);
} else {
return _this.log.error('DB', 'Initialization failed because of missing config file!');
}
}; };
/* /*
@ -80,7 +72,7 @@ Persistence
numAttempts = 0; numAttempts = 0;
fCheckConnection = function() { fCheckConnection = function() {
if (_this.db.connected) { if (_this.db.connected) {
_this.log.info('DB', 'Successfully connected to DB!'); _this.log.info('DB | Successfully connected to DB!');
return cb(); return cb();
} else if (numAttempts++ < 10) { } else if (numAttempts++ < 10) {
return setTimeout(fCheckConnection, 100); return setTimeout(fCheckConnection, 100);
@ -103,10 +95,9 @@ Persistence
replyHandler = function(action) { replyHandler = function(action) {
return function(err, reply) { return function(err, reply) {
if (err) { if (err) {
err.addInfo = "during '" + action + "'"; return _this.log.warn(err, "during '" + action + "'");
return _this.log.error('DB', err);
} else { } else {
return _this.log.info('DB', "" + action + ": " + reply); return _this.log.info("DB | " + action + ": " + reply);
} }
}; };
}; };
@ -121,10 +112,10 @@ Persistence
exports.pushEvent = function(oEvent) { exports.pushEvent = function(oEvent) {
if (oEvent) { if (oEvent) {
_this.log.info('DB', "Event pushed into the queue: '" + oEvent.eventid + "'"); _this.log.info("DB | Event pushed into the queue: '" + oEvent.eventid + "'");
return _this.db.rpush('event_queue', JSON.stringify(oEvent)); return _this.db.rpush('event_queue', JSON.stringify(oEvent));
} else { } else {
return _this.log.error('DB', 'Why would you give me an empty event...'); return _this.log.warn('DB | Why would you give me an empty event...');
} }
}; };
@ -176,8 +167,7 @@ Persistence
})).toString(); })).toString();
} catch (_error) { } catch (_error) {
err = _error; err = _error;
err.addInfo = 'during hashing'; _this.log.warn(err, 'DB | during hashing');
_this.log.error('DB', err);
return null; return null;
} }
}; };
@ -199,8 +189,7 @@ Persistence
return crypto.AES.encrypt(plainText, _this.crypto_key); return crypto.AES.encrypt(plainText, _this.crypto_key);
} catch (_error) { } catch (_error) {
err = _error; err = _error;
err.addInfo = 'during encryption'; _this.log.warn(err, 'DB | during encryption');
_this.log.error('DB', err);
return null; return null;
} }
}; };
@ -223,8 +212,7 @@ Persistence
return dec.toString(crypto.enc.Utf8); return dec.toString(crypto.enc.Utf8);
} catch (_error) { } catch (_error) {
err = _error; err = _error;
err.addInfo = 'during decryption'; _this.log.warn(err, 'DB | during decryption');
_this.log.error('DB', err);
return null; return null;
} }
}; };
@ -243,12 +231,11 @@ Persistence
getSetRecords = function(set, fSingle, cb) { getSetRecords = function(set, fSingle, cb) {
_this.log.info('DB', "Fetching set records: '" + set + "'"); _this.log.info("DB | Fetching set records: '" + set + "'");
return _this.db.smembers(set, function(err, arrReply) { return _this.db.smembers(set, function(err, arrReply) {
var fCallback, objReplies, reply, semaphore, _i, _len, _results; var fCallback, objReplies, reply, semaphore, _i, _len, _results;
if (err) { if (err) {
err.addInfo = "fetching '" + set + "'"; _this.log.warn(err, "DB | fetching '" + set + "'");
_this.log.error('DB', err);
return cb(err); return cb(err);
} else if (arrReply.length === 0) { } else if (arrReply.length === 0) {
return cb(); return cb();
@ -264,10 +251,9 @@ Persistence
return function(err, data) { return function(err, data) {
--semaphore; --semaphore;
if (err) { if (err) {
err.addInfo = "fetching single element: '" + prop + "'"; _this.log.warn(err, "DB | fetching single element: '" + prop + "'");
_this.log.error('DB', err);
} else if (!data) { } else if (!data) {
_this.log.error('DB', new Error("Empty key in DB: '" + prop + "'")); _this.log.warn(new Error("Empty key in DB: '" + prop + "'"));
} else { } else {
objReplies[prop] = data; objReplies[prop] = data;
} }
@ -300,56 +286,56 @@ Persistence
this.getModuleIds = __bind(this.getModuleIds, this); this.getModuleIds = __bind(this.getModuleIds, this);
this.getModule = __bind(this.getModule, this); this.getModule = __bind(this.getModule, this);
this.storeModule = __bind(this.storeModule, this); this.storeModule = __bind(this.storeModule, this);
this.log.info('DB', "Instantiated indexed modules for '" + this.setname + "'"); this.log.info("DB | Instantiated indexed modules for '" + this.setname + "'");
} }
IndexedModules.prototype.storeModule = function(mId, data) { IndexedModules.prototype.storeModule = function(mId, data) {
this.log.info('DB', "storeModule(" + this.setname + "): " + mId); this.log.info("DB | storeModule(" + this.setname + "): " + mId);
this.db.sadd("" + this.setname + "s", mId, replyHandler("Storing '" + this.setname + "' key '" + mId + "'")); this.db.sadd("" + this.setname + "s", mId, replyHandler("Storing '" + this.setname + "' key '" + mId + "'"));
return this.db.set("" + this.setname + ":" + mId, data, replyHandler("Storing '" + this.setname + ":" + mId + "'")); return this.db.set("" + this.setname + ":" + mId, data, replyHandler("Storing '" + this.setname + ":" + mId + "'"));
}; };
IndexedModules.prototype.getModule = function(mId, cb) { IndexedModules.prototype.getModule = function(mId, cb) {
this.log.info('DB', "getModule('" + this.setname + "): " + mId + "'"); this.log.info("DB | getModule('" + this.setname + "): " + mId + "'");
return this.db.get("" + this.setname + ":" + mId, cb); return this.db.get("" + this.setname + ":" + mId, cb);
}; };
IndexedModules.prototype.getModuleIds = function(cb) { IndexedModules.prototype.getModuleIds = function(cb) {
this.log.info('DB', "getModuleIds(" + this.setname + ")"); this.log.info("DB | getModuleIds(" + this.setname + ")");
return this.db.smembers("" + this.setname + "s", cb); return this.db.smembers("" + this.setname + "s", cb);
}; };
IndexedModules.prototype.getModules = function(cb) { IndexedModules.prototype.getModules = function(cb) {
this.log.info('DB', "getModules(" + this.setname + ")"); this.log.info("DB | getModules(" + this.setname + ")");
return getSetRecords("" + this.setname + "s", this.getModule, cb); return getSetRecords("" + this.setname + "s", this.getModule, cb);
}; };
IndexedModules.prototype.deleteModule = function(mId) { IndexedModules.prototype.deleteModule = function(mId) {
this.log.info('DB', "deleteModule(" + this.setname + "): " + mId); this.log.info("DB | deleteModule(" + this.setname + "): " + mId);
this.db.srem("" + this.setname + "s", mId, replyHandler("Deleting '" + this.setname + "' key '" + mId + "'")); this.db.srem("" + this.setname + "s", mId, replyHandler("Deleting '" + this.setname + "' key '" + mId + "'"));
return this.db.del("" + this.setname + ":" + mId, replyHandler("Deleting '" + this.setname + ":" + mId + "'")); return this.db.del("" + this.setname + ":" + mId, replyHandler("Deleting '" + this.setname + ":" + mId + "'"));
}; };
IndexedModules.prototype.storeParameters = function(mId, userId, data) { IndexedModules.prototype.storeParameters = function(mId, userId, data) {
this.log.info('DB', "storeParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); this.log.info("DB | storeParameters(" + this.setname + "): '" + mId + ":" + userId + "'");
this.db.sadd("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Storing '" + this.setname + "' module parameters key '" + mId + "'")); this.db.sadd("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Storing '" + this.setname + "' module parameters key '" + mId + "'"));
return this.db.set("" + this.setname + "-params:" + mId + ":" + userId, encrypt(data), replyHandler("Storing '" + this.setname + "' module parameters '" + mId + ":" + userId + "'")); return this.db.set("" + this.setname + "-params:" + mId + ":" + userId, encrypt(data), replyHandler("Storing '" + this.setname + "' module parameters '" + mId + ":" + userId + "'"));
}; };
IndexedModules.prototype.getParameters = function(mId, userId, cb) { IndexedModules.prototype.getParameters = function(mId, userId, cb) {
this.log.info('DB', "getParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); this.log.info("DB | getParameters(" + this.setname + "): '" + mId + ":" + userId + "'");
return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, function(err, data) { return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, function(err, data) {
return cb(err, decrypt(data)); return cb(err, decrypt(data));
}); });
}; };
IndexedModules.prototype.getParametersIds = function(cb) { IndexedModules.prototype.getParametersIds = function(cb) {
this.log.info('DB', "getParametersIds(" + this.setname + ")"); this.log.info("DB | getParametersIds(" + this.setname + ")");
return this.db.smembers("" + this.setname + "-params", cb); return this.db.smembers("" + this.setname + "-params", cb);
}; };
IndexedModules.prototype.deleteParameters = function(mId, userId) { IndexedModules.prototype.deleteParameters = function(mId, userId) {
this.log.info('DB', "deleteParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); this.log.info("DB | deleteParameters(" + this.setname + "): '" + mId + ":" + userId + "'");
this.db.srem("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params' key '" + mId + ":" + userId + "'")); this.db.srem("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params' key '" + mId + ":" + userId + "'"));
return this.db.del("" + this.setname + "-params:" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params:" + mId + ":" + userId + "'")); return this.db.del("" + this.setname + "-params:" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params:" + mId + ":" + userId + "'"));
}; };
@ -613,7 +599,7 @@ Persistence
exports.getRule = function(ruleId, cb) { exports.getRule = function(ruleId, cb) {
_this.log.info('DB', "getRule: '" + ruleId + "'"); _this.log.info("DB | getRule: '" + ruleId + "'");
return _this.db.get("rule:" + ruleId, cb); return _this.db.get("rule:" + ruleId, cb);
}; };
@ -626,7 +612,7 @@ Persistence
exports.getRules = function(cb) { exports.getRules = function(cb) {
_this.log.info('DB', 'Fetching all Rules'); _this.log.info('DB | Fetching all Rules');
return getSetRecords('rules', exports.getRule, cb); return getSetRecords('rules', exports.getRule, cb);
}; };
@ -639,7 +625,7 @@ Persistence
exports.getRuleIds = function(cb) { exports.getRuleIds = function(cb) {
_this.log.info('DB', 'Fetching all Rule IDs'); _this.log.info('DB | Fetching all Rule IDs');
return _this.db.smembers('rules', cb); return _this.db.smembers('rules', cb);
}; };
@ -653,7 +639,7 @@ Persistence
exports.storeRule = function(ruleId, data) { exports.storeRule = function(ruleId, data) {
_this.log.info('DB', "storeRule: '" + ruleId + "'"); _this.log.info("DB | storeRule: '" + ruleId + "'");
_this.db.sadd('rules', "" + ruleId, replyHandler("storing rule key '" + ruleId + "'")); _this.db.sadd('rules', "" + ruleId, replyHandler("storing rule key '" + ruleId + "'"));
return _this.db.set("rule:" + ruleId, data, replyHandler("storing rule '" + ruleId + "'")); return _this.db.set("rule:" + ruleId, data, replyHandler("storing rule '" + ruleId + "'"));
}; };
@ -668,7 +654,7 @@ Persistence
exports.deleteRule = function(ruleId) { exports.deleteRule = function(ruleId) {
_this.log.info('DB', "deleteRule: '" + ruleId + "'"); _this.log.info("DB | deleteRule: '" + ruleId + "'");
_this.db.srem("rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "'")); _this.db.srem("rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "'"));
_this.db.del("rule:" + ruleId, replyHandler("Deleting rule '" + ruleId + "'")); _this.db.del("rule:" + ruleId, replyHandler("Deleting rule '" + ruleId + "'"));
_this.db.smembers("rule:" + ruleId + ":users", function(err, obj) { _this.db.smembers("rule:" + ruleId + ":users", function(err, obj) {
@ -709,7 +695,7 @@ Persistence
exports.linkRule = function(ruleId, userId) { exports.linkRule = function(ruleId, userId) {
_this.log.info('DB', "linkRule: '" + ruleId + "' for user '" + userId + "'"); _this.log.info("DB | linkRule: '" + ruleId + "' for user '" + userId + "'");
_this.db.sadd("rule:" + ruleId + ":users", userId, replyHandler("storing user '" + userId + "' for rule key '" + ruleId + "'")); _this.db.sadd("rule:" + ruleId + ":users", userId, replyHandler("storing user '" + userId + "' for rule key '" + ruleId + "'"));
return _this.db.sadd("user:" + userId + ":rules", ruleId, replyHandler("storing rule key '" + ruleId + "' for user '" + userId + "'")); return _this.db.sadd("user:" + userId + ":rules", ruleId, replyHandler("storing rule key '" + ruleId + "' for user '" + userId + "'"));
}; };
@ -724,7 +710,7 @@ Persistence
exports.getUserLinkedRules = function(userId, cb) { exports.getUserLinkedRules = function(userId, cb) {
_this.log.info('DB', "getUserLinkedRules: for user '" + userId + "'"); _this.log.info("DB | getUserLinkedRules: for user '" + userId + "'");
return _this.db.smembers("user:" + userId + ":rules", cb); return _this.db.smembers("user:" + userId + ":rules", cb);
}; };
@ -738,7 +724,7 @@ Persistence
exports.getRuleLinkedUsers = function(ruleId, cb) { exports.getRuleLinkedUsers = function(ruleId, cb) {
_this.log.info('DB', "getRuleLinkedUsers: for rule '" + ruleId + "'"); _this.log.info("DB | getRuleLinkedUsers: for rule '" + ruleId + "'");
return _this.db.smembers("rule:" + ruleId + ":users", cb); return _this.db.smembers("rule:" + ruleId + ":users", cb);
}; };
@ -752,7 +738,7 @@ Persistence
exports.unlinkRule = function(ruleId, userId) { exports.unlinkRule = function(ruleId, userId) {
_this.log.info('DB', "unlinkRule: '" + ruleId + ":" + userId + "'"); _this.log.info("DB | unlinkRule: '" + ruleId + ":" + userId + "'");
_this.db.srem("rule:" + ruleId + ":users", userId, replyHandler("removing user '" + userId + "' for rule key '" + ruleId + "'")); _this.db.srem("rule:" + ruleId + ":users", userId, replyHandler("removing user '" + userId + "' for rule key '" + ruleId + "'"));
return _this.db.srem("user:" + userId + ":rules", ruleId, replyHandler("removing rule key '" + ruleId + "' for user '" + userId + "'")); return _this.db.srem("user:" + userId + ":rules", ruleId, replyHandler("removing rule key '" + ruleId + "' for user '" + userId + "'"));
}; };
@ -767,7 +753,7 @@ Persistence
exports.activateRule = function(ruleId, userId) { exports.activateRule = function(ruleId, userId) {
_this.log.info('DB', "activateRule: '" + ruleId + "' for '" + userId + "'"); _this.log.info("DB | activateRule: '" + ruleId + "' for '" + userId + "'");
_this.db.sadd("rule:" + ruleId + ":active-users", userId, replyHandler("storing activated user '" + userId + "' in rule '" + ruleId + "'")); _this.db.sadd("rule:" + ruleId + ":active-users", userId, replyHandler("storing activated user '" + userId + "' in rule '" + ruleId + "'"));
return _this.db.sadd("user:" + userId + ":active-rules", ruleId, replyHandler("storing activated rule '" + ruleId + "' in user '" + userId + "'")); return _this.db.sadd("user:" + userId + ":active-rules", ruleId, replyHandler("storing activated rule '" + ruleId + "' in user '" + userId + "'"));
}; };
@ -782,7 +768,7 @@ Persistence
exports.getUserActivatedRules = function(userId, cb) { exports.getUserActivatedRules = function(userId, cb) {
_this.log.info('DB', "getUserActivatedRules: for user '" + userId + "'"); _this.log.info("DB | getUserActivatedRules: for user '" + userId + "'");
return _this.db.smembers("user:" + userId + ":active-rules", cb); return _this.db.smembers("user:" + userId + ":active-rules", cb);
}; };
@ -796,7 +782,7 @@ Persistence
exports.getRuleActivatedUsers = function(ruleId, cb) { exports.getRuleActivatedUsers = function(ruleId, cb) {
_this.log.info('DB', "getRuleActivatedUsers: for rule '" + ruleId + "'"); _this.log.info("DB | getRuleActivatedUsers: for rule '" + ruleId + "'");
return _this.db.smembers("rule:" + ruleId + ":active-users", cb); return _this.db.smembers("rule:" + ruleId + ":active-users", cb);
}; };
@ -810,7 +796,7 @@ Persistence
exports.deactivateRule = function(ruleId, userId) { exports.deactivateRule = function(ruleId, userId) {
_this.log.info('DB', "deactivateRule: '" + ruleId + "' for '" + userId + "'"); _this.log.info("DB | deactivateRule: '" + ruleId + "' for '" + userId + "'");
_this.db.srem("rule:" + ruleId + ":active-users", userId, replyHandler("removing activated user '" + userId + "' in rule '" + ruleId + "'")); _this.db.srem("rule:" + ruleId + ":active-users", userId, replyHandler("removing activated user '" + userId + "' in rule '" + ruleId + "'"));
return _this.db.srem("user:" + userId + ":active-rules", ruleId, replyHandler("removing activated rule '" + ruleId + "' in user '" + userId + "'")); return _this.db.srem("user:" + userId + ":active-rules", ruleId, replyHandler("removing activated rule '" + ruleId + "' in user '" + userId + "'"));
}; };
@ -824,7 +810,7 @@ Persistence
exports.getAllActivatedRuleIdsPerUser = function(cb) { exports.getAllActivatedRuleIdsPerUser = function(cb) {
_this.log.info('DB', "Fetching all active rules"); _this.log.info("DB | Fetching all active rules");
return _this.db.smembers('users', function(err, obj) { return _this.db.smembers('users', function(err, obj) {
var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results; var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results;
result = {}; result = {};
@ -867,13 +853,13 @@ Persistence
exports.storeUser = function(objUser) { exports.storeUser = function(objUser) {
_this.log.info('DB', "storeUser: '" + objUser.username + "'"); _this.log.info("DB | storeUser: '" + objUser.username + "'");
if (objUser && objUser.username && objUser.password) { if (objUser && objUser.username && objUser.password) {
_this.db.sadd('users', objUser.username, replyHandler("storing user key '" + objUser.username + "'")); _this.db.sadd('users', objUser.username, replyHandler("storing user key '" + objUser.username + "'"));
objUser.password = objUser.password; objUser.password = objUser.password;
return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties '" + objUser.username + "'")); return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties '" + objUser.username + "'"));
} else { } else {
return _this.log.error('DB', new Error('username or password was missing')); return _this.log.warn(new Error('DB | username or password was missing'));
} }
}; };
@ -886,7 +872,7 @@ Persistence
exports.getUserIds = function(cb) { exports.getUserIds = function(cb) {
_this.log.info('DB', "getUserIds"); _this.log.info("DB | getUserIds");
return _this.db.smembers("users", cb); return _this.db.smembers("users", cb);
}; };
@ -900,7 +886,7 @@ Persistence
exports.getUser = function(userId, cb) { exports.getUser = function(userId, cb) {
_this.log.info('DB', "getUser: '" + userId + "'"); _this.log.info("DB | getUser: '" + userId + "'");
return _this.db.hgetall("user:" + userId, cb); return _this.db.hgetall("user:" + userId, cb);
}; };
@ -913,7 +899,7 @@ Persistence
exports.deleteUser = function(userId) { exports.deleteUser = function(userId) {
_this.log.info('DB', "deleteUser: '" + userId + "'"); _this.log.info("DB | deleteUser: '" + userId + "'");
_this.db.srem("users", userId, replyHandler("Deleting user key '" + userId + "'")); _this.db.srem("users", userId, replyHandler("Deleting user key '" + userId + "'"));
_this.db.del("user:" + userId, replyHandler("Deleting user '" + userId + "'")); _this.db.del("user:" + userId, replyHandler("Deleting user '" + userId + "'"));
_this.db.smembers("user:" + userId + ":rules", function(err, obj) { _this.db.smembers("user:" + userId + ":rules", function(err, obj) {
@ -972,14 +958,14 @@ Persistence
exports.loginUser = function(userId, password, cb) { exports.loginUser = function(userId, password, cb) {
var fCheck; var fCheck;
_this.log.info('DB', "User '" + userId + "' tries to log in"); _this.log.info("DB | User '" + userId + "' tries to log in");
fCheck = function(pw) { fCheck = function(pw) {
return function(err, obj) { return function(err, obj) {
if (err) { if (err) {
return cb(err, null); return cb(err, null);
} else if (obj && obj.password) { } else if (obj && obj.password) {
if (pw === obj.password) { if (pw === obj.password) {
_this.log.info('DB', "User '" + obj.username + "' logged in!"); _this.log.info("DB | User '" + obj.username + "' logged in!");
return cb(null, obj); return cb(null, obj);
} else { } else {
return cb(new Error('Wrong credentials!'), null); return cb(new Error('Wrong credentials!'), null);
@ -1007,7 +993,7 @@ Persistence
exports.storeUserRole = function(userId, role) { exports.storeUserRole = function(userId, role) {
_this.log.info('DB', "storeUserRole: '" + userId + ":" + role + "'"); _this.log.info("DB | storeUserRole: '" + userId + ":" + role + "'");
_this.db.sadd('roles', role, replyHandler("adding role '" + role + "' to role index set")); _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 '" + userId + "'")); _this.db.sadd("user:" + userId + ":roles", role, replyHandler("adding role '" + role + "' to user '" + userId + "'"));
return _this.db.sadd("role:" + role + ":users", userId, replyHandler("adding user '" + userId + "' to role '" + role + "'")); return _this.db.sadd("role:" + role + ":users", userId, replyHandler("adding user '" + userId + "' to role '" + role + "'"));
@ -1023,7 +1009,7 @@ Persistence
exports.getUserRoles = function(userId, cb) { exports.getUserRoles = function(userId, cb) {
_this.log.info('DB', "getUserRoles: '" + userId + "'"); _this.log.info("DB | getUserRoles: '" + userId + "'");
return _this.db.smembers("user:" + userId + ":roles", cb); return _this.db.smembers("user:" + userId + ":roles", cb);
}; };
@ -1037,7 +1023,7 @@ Persistence
exports.getRoleUsers = function(role, cb) { exports.getRoleUsers = function(role, cb) {
_this.log.info('DB', "getRoleUsers: '" + role + "'"); _this.log.info("DB | getRoleUsers: '" + role + "'");
return _this.db.smembers("role:" + role + ":users", cb); return _this.db.smembers("role:" + role + ":users", cb);
}; };
@ -1051,7 +1037,7 @@ Persistence
exports.removeUserRole = function(userId, role) { exports.removeUserRole = function(userId, role) {
_this.log.info('DB', "removeRoleFromUser: role '" + role + "', user '" + userId + "'"); _this.log.info("DB | removeRoleFromUser: role '" + role + "', user '" + userId + "'");
_this.db.srem("user:" + userId + ":roles", role, replyHandler("Removing role '" + role + "' from user '" + userId + "'")); _this.db.srem("user:" + userId + ":roles", role, replyHandler("Removing role '" + role + "' from user '" + userId + "'"));
return _this.db.srem("role:" + role + ":users", userId, replyHandler("Removing user '" + userId + "' from role '" + role + "'")); return _this.db.srem("role:" + role + ":users", userId, replyHandler("Removing user '" + userId + "' from role '" + role + "'"));
}; };

View file

@ -3,16 +3,17 @@
Request Handler Request Handler
============ ============
> TODO Add documentation > The request handler (surprisingly) handles requests made through HTTP to
> the [HTTP Listener](http-listener.html). It will handle user requests for
> pages as well as POST requests such as user login, module storing, event
> invocation and also admin commands.
*/ */
(function() { (function() {
var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, log, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage, var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage,
_this = this; _this = this;
log = require('./logging');
db = require('./persistence'); db = require('./persistence');
mm = require('./module-manager'); mm = require('./module-manager');
@ -38,9 +39,8 @@ Request Handler
objAdminCmds = {}; objAdminCmds = {};
exports = module.exports = function(args) { exports = module.exports = function(args) {
var user, users, _i, _len; var log, user, users, _i, _len;
args = args != null ? args : {}; log = args.logger;
log(args);
db(args); db(args);
mm(args); mm(args);
mm.addDBLink(db); mm.addDBLink(db);
@ -122,7 +122,7 @@ Request Handler
obj = qs.parse(body); obj = qs.parse(body);
return db.loginUser(obj.username, obj.password, function(err, usr) { return db.loginUser(obj.username, obj.password, function(err, usr) {
if (err) { if (err) {
log.print('RH', ("AUTH-UH-OH (" + obj.username + "): ") + err.message); log.warn(err, "RH | AUTH-UH-OH (" + obj.username + ")");
} else { } else {
req.session.user = usr; req.session.user = usr;
} }
@ -341,7 +341,7 @@ Request Handler
if (req.session && req.session.user) { if (req.session && req.session.user) {
if (req.session.user.isAdmin === "true") { if (req.session.user.isAdmin === "true") {
q = req.query; q = req.query;
log.print('RH', 'Received admin request: ' + req.originalUrl); log.info('RH | Received admin request: ' + req.originalUrl);
if (q.cmd) { if (q.cmd) {
return typeof (_base = _this.objAdminCmds)[_name = q.cmd] === "function" ? _base[_name](q, answerHandler(req, resp, true)) : void 0; return typeof (_base = _this.objAdminCmds)[_name = q.cmd] === "function" ? _base[_name](q, answerHandler(req, resp, true)) : void 0;
} else { } else {

View file

@ -1,25 +0,0 @@
// Generated by CoffeeScript 1.6.3
(function() {
var bunyan, logger, opt;
bunyan = require('bunyan');
opt = {
name: "webapi-eca"
};
opt.streams = [
{
level: 'info',
stream: process.stdout
}, {
level: 'info',
path: 'logs/server.log'
}
];
logger = bunyan.createLogger(opt);
logger.info('weeee');
}).call(this);

View file

@ -13,7 +13,8 @@ WebAPI-ECA Engine
(function() { (function() {
var argv, conf, cp, db, engine, fs, http, init, logger, opt, optimist, path, procCmds, shutDown, usage; var argv, conf, cp, db, engine, fs, http, init, logger, opt, optimist, path, procCmds, shutDown, usage,
_this = this;
logger = require('./logging'); logger = require('./logging');
@ -98,8 +99,7 @@ WebAPI-ECA Engine
process.on('uncaughtException', function(err) { process.on('uncaughtException', function(err) {
switch (err.errno) { switch (err.errno) {
case 'EADDRINUSE': case 'EADDRINUSE':
err.addInfo = 'http-port already in use, shutting down!'; _this.log.error(err, 'RS | http-port already in use, shutting down!');
log.error('RS', err);
return shutDown(); return shutDown();
default: default:
throw err; throw err;
@ -114,7 +114,7 @@ WebAPI-ECA Engine
init = function() { init = function() {
var args, log, logconf; var args, logconf;
conf(argv.c); conf(argv.c);
if (!conf.isReady()) { if (!conf.isReady()) {
console.error('FAIL: Config file not ready! Shutting down...'); console.error('FAIL: Config file not ready! Shutting down...');
@ -139,27 +139,30 @@ WebAPI-ECA Engine
try { try {
fs.unlinkSync(path.resolve(__dirname, '..', 'logs', logconf['file-path'])); fs.unlinkSync(path.resolve(__dirname, '..', 'logs', logconf['file-path']));
} catch (_error) {} } catch (_error) {}
log = logger(logconf); _this.log = logger.getLogger(logconf);
log.info('RS | STARTING SERVER'); _this.log.info('RS | STARTING SERVER');
args = { args = {
logger: log, logger: _this.log,
logconf: logconf logconf: logconf
}; };
args['http-port'] = parseInt(argv.w || conf.getHttpPort()); args['http-port'] = parseInt(argv.w || conf.getHttpPort());
log.info('RS | Initialzing DB'); args['db-port'] = parseInt(argv.w || conf.getDbPort());
_this.log.info('RS | Initialzing DB');
db(args); db(args);
return db.isConnected(function(err, result) { return db.isConnected(function(err, result) {
var cliArgs, poller; var cliArgs, poller;
if (!err) { if (err) {
log.info('RS | Initialzing engine'); return shutDown();
} else {
_this.log.info('RS | Initialzing engine');
engine(args); engine(args);
log.info('RS | Initialzing http listener'); _this.log.info('RS | Initialzing http listener');
http(args); http(args);
log.info('RS | Passing handlers to engine'); _this.log.info('RS | Passing handlers to engine');
engine.addPersistence(db); engine.addPersistence(db);
log.info('RS | Passing handlers to http listener'); _this.log.info('RS | Passing handlers to http listener');
http.addShutdownHandler(shutDown); http.addShutdownHandler(shutDown);
log.info('RS | For e child process for the event poller'); _this.log.info('RS | Forking child process for the event poller');
cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']]; cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']];
return poller = cp.fork(path.resolve(__dirname, 'event-poller'), cliArgs); return poller = cp.fork(path.resolve(__dirname, 'event-poller'), cliArgs);
} }
@ -174,11 +177,14 @@ WebAPI-ECA Engine
shutDown = function() { shutDown = function() {
log.warn('RS | Received shut down command!'); _this.log.warn('RS | Received shut down command!');
if (engine != null) { if (engine != null) {
engine.shutDown(); engine.shutDown();
} }
return http != null ? http.shutDown() : void 0; if (http != null) {
http.shutDown();
}
return process.exit();
}; };
/* /*
@ -193,6 +199,10 @@ WebAPI-ECA Engine
return typeof procCmds[cmd] === "function" ? procCmds[cmd]() : void 0; return typeof procCmds[cmd] === "function" ? procCmds[cmd]() : void 0;
}); });
process.on('SIGINT', shutDown);
process.on('SIGTERM', shutDown);
procCmds.die = shutDown; procCmds.die = shutDown;
init(); init();

0
logs/.gitignore vendored Normal file
View file

0
logs/testing/.gitignore vendored Normal file
View file

View file

@ -21,10 +21,9 @@ exports.testParameters = ( test ) =>
'file-level' 'file-level'
'file-path' 'file-path'
] ]
test.expect 4 + reqProp.length test.expect 3 + reqProp.length
test.ok @conf.getHttpPort(), 'HTTP port does not exist!' test.ok @conf.getHttpPort(), 'HTTP port does not exist!'
test.ok @conf.getDBPort(), 'DB port does not exist!' test.ok @conf.getDbPort(), 'DB port does not exist!'
test.ok @conf.getCryptoKey(), 'Crypto key does not exist!'
logconf = @conf.getLogConf() logconf = @conf.getLogConf()
test.ok logconf, 'Log config does not exist!' test.ok logconf, 'Log config does not exist!'
for prop in reqProp for prop in reqProp

View file

@ -5,8 +5,10 @@ exports.setUp = ( cb ) =>
@log = logger.getLogger @log = logger.getLogger
nolog: true nolog: true
@db = require @path.join '..', 'js-coffee', 'persistence' @db = require @path.join '..', 'js-coffee', 'persistence'
@db opts =
logger: @log logger: @log
opts[ 'db-port' ] = 6379
@db opts
cb() cb()
exports.tearDown = ( cb ) => exports.tearDown = ( cb ) =>
@ -31,22 +33,14 @@ exports.Availability =
test.ifError err, 'Connection failed!' test.ifError err, 'Connection failed!'
test.done() test.done()
testNoConfig: ( test ) => # We cannot test for no db-port, since node-redis then assumes standard port
testWrongDbPort: ( test ) =>
test.expect 1 test.expect 1
@db opts =
logger: @log logger: @log
configPath: 'nonexistingconf.file' opts[ 'db-port' ] = 63214
@db.isConnected ( err ) -> @db opts
test.ok err, 'Still connected!?'
test.done()
testWrongConfig: ( test ) =>
test.expect 1
@db
logger: @log
configPath: @path.join 'testing', 'jsonWrongConfig.json'
@db.isConnected ( err ) -> @db.isConnected ( err ) ->
test.ok err, 'Still connected!?' test.ok err, 'Still connected!?'
test.done() test.done()

View file

@ -0,0 +1,104 @@
cp = require 'child_process'
path = require 'path'
# exports.setUp = ( cb ) =>
# cb()
# exports.tearDown = ( cb ) =>
# @engine.send('die')
# cb()
# # TODO wrong db-port or http-port will make the engine stop properly before starting
# # goes hand in hand with wrong config file
# # http command shutdown does it properly, as well as sending the process the die command
exports.testShutDown = ( test ) =>
test.expect 1
isRunning = true
pth = path.resolve 'js-coffee', 'webapi-eca'
engine = cp.fork pth, [ '-n' ] # [ '-i' , 'warn' ]
engine.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
fWaitForStartup = () ->
engine.send 'die'
setTimeout fWaitForDeath, 5000
# Garbage collect eventually still running process
fWaitForDeath = () ->
if isRunning
test.ok false, 'Engine didn\'t shut down!'
engine.kill()
test.done()
setTimeout fWaitForStartup, 1000
exports.testKill = ( test ) =>
test.expect 1
pth = path.resolve 'js-coffee', 'webapi-eca'
engine = cp.fork pth, [ '-n' ] # [ '-i' , 'warn' ]
fWaitForStartup = () ->
engine.kill()
setTimeout fWaitForDeath, 1000
# Garbage collect eventually still running process
fWaitForDeath = () ->
test.ok engine.killed, 'Engine didn\'t shut down!'
test.done()
setTimeout fWaitForStartup, 1000
exports.testHttpPortAlreadyUsed = ( test ) =>
test.expect 1
isRunning = true
pth = path.resolve 'js-coffee', 'webapi-eca'
@engine_one = cp.fork pth, ['-n'] # [ '-i' , 'warn' ]
fWaitForFirstStartup = () =>
@engine_two = cp.fork pth, ['-n'] # [ '-i' , 'warn' ]
@engine_two.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
setTimeout fWaitForDeath, 3000
# Garbage collect eventually still running process
fWaitForDeath = () =>
if isRunning
test.ok false, 'Engine didn\'t shut down!'
test.done()
@engine_one.kill()
@engine_two.kill()
setTimeout fWaitForFirstStartup, 1000
exports.testHttpPortInvalid = ( test ) =>
test.expect 1
isRunning = true
pth = path.resolve 'js-coffee', 'webapi-eca'
engine = cp.fork pth, ['-n', '-w', '-1'] # [ '-i' , 'warn' ]
engine.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
# Garbage collect eventually still running process
fWaitForDeath = () =>
if isRunning
test.ok false, 'Engine didn\'t shut down!'
test.done()
engine.kill()
setTimeout fWaitForDeath, 1000