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

View file

@ -8,10 +8,7 @@ HTTP Listener
###
# **Requires:**
# - [Logging](logging.html)
log = require './logging'
# **Loads Modules:**
# - [Request Handler](request-handler.html)
requestHandler = require './request-handler'
@ -25,7 +22,8 @@ qs = require 'querystring'
express = require '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
@ -34,9 +32,8 @@ Initializes the HTTP listener and its request handler.
@param {Object} args
###
exports = module.exports = ( args ) ->
args = args ? {}
log args
exports = module.exports = ( args ) =>
@log = args.logger
requestHandler args
initRouting args[ 'http-port' ]
module.exports
@ -47,15 +44,15 @@ Initializes the request routing and starts listening on the given port.
@param {int} port
@private initRouting( *fShutDown* )
###
initRouting = ( port ) ->
initRouting = ( port ) =>
# Add cookie support for session handling.
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"
app.use express.session { secret: sess_sec }
#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:**
@ -83,10 +80,9 @@ initRouting = ( port ) ->
# - **`POST` to _"/user"_:** User requests are possible for all users with an account
app.post '/usercommand', requestHandler.handleUserCommand
try
app.listen port # inbound event channel
@server = app.listen port # inbound event channel
catch e
e.addInfo = 'opening port'
log.error e
@log.error e, 'HL | Unable to listen...'
###
Adds the shutdown handler to the admin commands.
@ -102,7 +98,11 @@ Shuts down the http listener.
@public shutDown()
###
exports.shutDown = () ->
log.print 'HL', 'Shutting down HTTP listener'
process.exit() # This is a bit brute force...
exports.shutDown = () =>
@log.warn 'HL | Shutting down HTTP listener'
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`
# **Requires:**
# **Loads Modules:**
# - Node.js Module: [fs](http://nodejs.org/api/fs.html) and [path](http://nodejs.org/api/path.html)
fs = require 'fs'

View file

@ -19,7 +19,7 @@ Persistence
###
# **Requires:**
# **Loads Modules:**
# - External Modules:
# [crypto-js](https://github.com/evanvosberg/crypto-js) and
@ -30,28 +30,21 @@ redis = require 'redis'
###
Module call
-----------
Initializes the DB connection. Requires a valid configuration file which contains
a db port and a crypto key.
Initializes the DB connection with the given `db-port` property in the `args` object.
@param {Object} args
###
exports = module.exports = ( args ) =>
@log = args.logger
#TODO remove config, do it through args
config = require './config'
config args
@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
@ep = new IndexedModules( 'event-poller', @db, @log )
@ai = new IndexedModules( 'action-invoker', @db, @log )
else
@log.error 'DB', 'Initialization failed because of missing config file!'
#TODO we need to have a secure concept here, private keys per user
@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 args[ 'db-port' ],
'localhost', { connect_timeout: 2000 }
@db.on 'error', ( err ) =>
@log.warn err, 'message from DB'
@ep = new IndexedModules( 'event-poller', @db, @log )
@ai = new IndexedModules( 'action-invoker', @db, @log )
###
Checks whether the db is connected and passes either an error on failure after
@ -66,7 +59,7 @@ exports.isConnected = ( cb ) =>
numAttempts = 0
fCheckConnection = =>
if @db.connected
@log.info 'DB', 'Successfully connected to DB!'
@log.info 'DB | Successfully connected to DB!'
cb()
else if numAttempts++ < 10
setTimeout fCheckConnection, 100
@ -83,10 +76,9 @@ Abstracts logging for simple action replies from the DB.
replyHandler = ( action ) =>
( err, reply ) =>
if err
err.addInfo = "during '#{ action }'"
@log.error 'DB', err
@log.warn err, "during '#{ action }'"
else
@log.info 'DB', "#{ action }: #{ reply }"
@log.info "DB | #{ action }: #{ reply }"
###
Push an event into the event queue.
@ -96,10 +88,10 @@ Push an event into the event queue.
###
exports.pushEvent = ( 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 )
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
( crypto.SHA3 plainText, { outputLength: 512 } ).toString()
catch err
err.addInfo = 'during hashing'
@log.error 'DB', err
@log.warn err, 'DB | during hashing'
null
@ -149,8 +140,7 @@ encrypt = ( plainText ) =>
try
crypto.AES.encrypt plainText, @crypto_key
catch err
err.addInfo = 'during encryption'
@log.error 'DB', err
@log.warn err, 'DB | during encryption'
null
###
@ -165,8 +155,7 @@ decrypt = ( crypticText ) =>
dec = crypto.AES.decrypt crypticText, @crypto_key
dec.toString(crypto.enc.Utf8)
catch err
err.addInfo = 'during decryption'
@log.error 'DB', err
@log.warn err, 'DB | during decryption'
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
###
getSetRecords = ( set, fSingle, cb ) =>
@log.info 'DB', "Fetching set records: '#{ set }'"
@log.info "DB | Fetching set records: '#{ set }'"
# Fetch all members of the set
@db.smembers set, ( err, arrReply ) =>
if err
# If an error happens we return it to the callback function
err.addInfo = "fetching '#{ set }'"
@log.error 'DB', err
@log.warn err, "DB | fetching '#{ set }'"
cb err
else if arrReply.length == 0
# If the set was empty we return null to the callback
@ -210,11 +198,10 @@ getSetRecords = ( set, fSingle, cb ) =>
( err, data ) =>
--semaphore
if err
err.addInfo = "fetching single element: '#{ prop }'"
@log.error 'DB', err
@log.warn err, "DB | fetching single element: '#{ prop }'"
else if not data
# 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
# We found a valid record and add it to the reply object
objReplies[ prop ] = data
@ -229,52 +216,52 @@ getSetRecords = ( set, fSingle, cb ) =>
class IndexedModules
constructor: ( @setname, @db, @log ) ->
@log.info 'DB', "Instantiated indexed modules for '#{ @setname }'"
@log.info "DB | Instantiated indexed modules for '#{ @setname }'"
storeModule: ( mId, data ) =>
@log.info 'DB', "storeModule(#{ @setname }): #{ mId }"
@log.info "DB | storeModule(#{ @setname }): #{ mId }"
@db.sadd "#{ @setname }s", mId,
replyHandler "Storing '#{ @setname }' key '#{ mId }'"
@db.set "#{ @setname }:#{ mId }", data,
replyHandler "Storing '#{ @setname }:#{ mId }'"
getModule: ( mId, cb ) =>
@log.info 'DB', "getModule('#{ @setname }): #{ mId }'"
@log.info "DB | getModule('#{ @setname }): #{ mId }'"
@db.get "#{ @setname }:#{ mId }", cb
getModuleIds: ( cb ) =>
@log.info 'DB', "getModuleIds(#{ @setname })"
@log.info "DB | getModuleIds(#{ @setname })"
@db.smembers "#{ @setname }s", cb
getModules: ( cb ) =>
@log.info 'DB', "getModules(#{ @setname })"
@log.info "DB | getModules(#{ @setname })"
getSetRecords "#{ @setname }s", @getModule, cb
deleteModule: ( mId ) =>
@log.info 'DB', "deleteModule(#{ @setname }): #{ mId }"
@log.info "DB | deleteModule(#{ @setname }): #{ mId }"
@db.srem "#{ @setname }s", mId,
replyHandler "Deleting '#{ @setname }' key '#{ mId }'"
@db.del "#{ @setname }:#{ mId }",
replyHandler "Deleting '#{ @setname }:#{ mId }'"
storeParameters: ( mId, userId, data ) =>
@log.info 'DB', "storeParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@log.info "DB | storeParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "Storing '#{ @setname }' module parameters key '#{ mId }'"
@db.set "#{ @setname }-params:#{ mId }:#{ userId }", encrypt(data),
replyHandler "Storing '#{ @setname }' module parameters '#{ mId }:#{ userId }'"
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 ) ->
cb err, decrypt data
getParametersIds: ( cb ) =>
@log.info 'DB', "getParametersIds(#{ @setname })"
@log.info "DB | getParametersIds(#{ @setname })"
@db.smembers "#{ @setname }-params", cb
deleteParameters: ( mId, userId ) =>
@log.info 'DB', "deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@log.info "DB | deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'"
@db.srem "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "Deleting '#{ @setname }-params' key '#{ 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
###
exports.getRule = ( ruleId, cb ) =>
@log.info 'DB', "getRule: '#{ ruleId }'"
@log.info "DB | getRule: '#{ ruleId }'"
@db.get "rule:#{ ruleId }", cb
###
@ -489,7 +476,7 @@ Fetch all rules and pass them to cb(err, obj).
@param {function} cb
###
exports.getRules = ( cb ) =>
@log.info 'DB', 'Fetching all Rules'
@log.info 'DB | Fetching all Rules'
getSetRecords 'rules', exports.getRule, cb
###
@ -499,7 +486,7 @@ Fetch all rule IDs and hand it to cb(err, obj).
@param {function} cb
###
exports.getRuleIds = ( cb ) =>
@log.info 'DB', 'Fetching all Rule IDs'
@log.info 'DB | Fetching all Rule IDs'
@db.smembers 'rules', cb
###
@ -510,7 +497,7 @@ Store a string representation of a rule in the DB.
@param {String} data
###
exports.storeRule = ( ruleId, data ) =>
@log.info 'DB', "storeRule: '#{ ruleId }'"
@log.info "DB | storeRule: '#{ ruleId }'"
@db.sadd 'rules', "#{ ruleId }",
replyHandler "storing rule key '#{ ruleId }'"
@db.set "rule:#{ ruleId }", data,
@ -524,7 +511,7 @@ Delete a string representation of a rule.
@param {String} userId
###
exports.deleteRule = ( ruleId ) =>
@log.info 'DB', "deleteRule: '#{ ruleId }'"
@log.info "DB | deleteRule: '#{ ruleId }'"
@db.srem "rules", ruleId, replyHandler "Deleting rule key '#{ ruleId }'"
@db.del "rule:#{ ruleId }", replyHandler "Deleting rule '#{ ruleId }'"
@ -552,7 +539,7 @@ Associate a rule to a user.
@param {String} 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,
replyHandler "storing user '#{ userId }' for rule key '#{ 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
###
exports.getUserLinkedRules = ( userId, cb ) =>
@log.info 'DB', "getUserLinkedRules: for user '#{ userId }'"
@log.info "DB | getUserLinkedRules: for user '#{ userId }'"
@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
###
exports.getRuleLinkedUsers = ( ruleId, cb ) =>
@log.info 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'"
@log.info "DB | getRuleLinkedUsers: for rule '#{ ruleId }'"
@db.smembers "rule:#{ ruleId }:users", cb
###
@ -588,7 +575,7 @@ Delete an association of a rule to a user.
@param {String} userId
###
exports.unlinkRule = ( ruleId, userId ) =>
@log.info 'DB', "unlinkRule: '#{ ruleId }:#{ userId }'"
@log.info "DB | unlinkRule: '#{ ruleId }:#{ userId }'"
@db.srem "rule:#{ ruleId }:users", userId,
replyHandler "removing user '#{ userId }' for rule key '#{ ruleId }'"
@db.srem "user:#{ userId }:rules", ruleId,
@ -602,7 +589,7 @@ Activate a rule.
@param {String} 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,
replyHandler "storing activated user '#{ userId }' in rule '#{ 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
###
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
###
@ -627,7 +614,7 @@ Get users activated for a rule and hand it to cb(err, obj).
@param {function} 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
###
@ -638,7 +625,7 @@ Deactivate a rule.
@param {String} 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,
replyHandler "removing activated user '#{ userId }' in rule '#{ 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
###
exports.getAllActivatedRuleIdsPerUser = ( cb ) =>
@log.info 'DB', "Fetching all active rules"
@log.info "DB | Fetching all active rules"
@db.smembers 'users', ( err, obj ) =>
result = {}
if obj.length is 0
@ -681,7 +668,7 @@ The password should be hashed before it is passed to this function.
exports.storeUser = ( objUser ) =>
#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?
@log.info 'DB', "storeUser: '#{ objUser.username }'"
@log.info "DB | storeUser: '#{ objUser.username }'"
if objUser and objUser.username and objUser.password
@db.sadd 'users', objUser.username,
replyHandler "storing user key '#{ objUser.username }'"
@ -689,7 +676,7 @@ exports.storeUser = ( objUser ) =>
@db.hmset "user:#{ objUser.username }", objUser,
replyHandler "storing user properties '#{ objUser.username }'"
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).
@ -698,7 +685,7 @@ Fetch all user IDs and pass them to cb(err, obj).
@param {function} cb
###
exports.getUserIds = ( cb ) =>
@log.info 'DB', "getUserIds"
@log.info "DB | getUserIds"
@db.smembers "users", cb
###
@ -709,7 +696,7 @@ Fetch a user by id and pass it to cb(err, obj).
@param {function} cb
###
exports.getUser = ( userId, cb ) =>
@log.info 'DB', "getUser: '#{ userId }'"
@log.info "DB | getUser: '#{ userId }'"
@db.hgetall "user:#{ userId }", cb
###
@ -719,7 +706,7 @@ Deletes a user and all his associated linked and active rules.
@param {String} userId
###
exports.deleteUser = ( userId ) =>
@log.info 'DB', "deleteUser: '#{ userId }'"
@log.info "DB | deleteUser: '#{ userId }'"
@db.srem "users", userId, replyHandler "Deleting user key '#{ 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
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 ) =>
( err, obj ) =>
if err
cb err, null
else if obj and 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
else
cb (new Error 'Wrong credentials!'), null
@ -793,7 +780,7 @@ Associate a role with a user.
@param {String} 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 "user:#{ userId }:roles", role,
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
###
exports.getUserRoles = ( userId, cb ) =>
@log.info 'DB', "getUserRoles: '#{ userId }'"
@log.info "DB | getUserRoles: '#{ userId }'"
@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
###
exports.getRoleUsers = ( role, cb ) =>
@log.info 'DB', "getRoleUsers: '#{ role }'"
@log.info "DB | getRoleUsers: '#{ role }'"
@db.smembers "role:#{ role }:users", cb
###
@ -830,7 +817,7 @@ Remove a role from a user.
@param {String} userId
###
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,
replyHandler "Removing role '#{ role }' from user '#{ userId }'"
@db.srem "role:#{ role }:users", userId,

View file

@ -2,14 +2,14 @@
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:**
# - [Logging](logging.html)
log = require './logging'
# **Loads Modules:**
# - [Persistence](persistence.html)
db = require './persistence'
@ -40,8 +40,7 @@ objUserCmds =
objAdminCmds = {}
exports = module.exports = ( args ) ->
args = args ? {}
log args
log = args.logger
db args
mm args
mm.addDBLink db
@ -105,7 +104,7 @@ exports.handleLogin = ( req, resp ) ->
db.loginUser obj.username, obj.password, ( err, usr ) ->
if(err)
# 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
# no error, so we can associate the user object from the DB to the session
req.session.user = usr
@ -280,7 +279,7 @@ exports.handleAdmin = ( req, resp ) =>
if req.session and req.session.user
if req.session.user.isAdmin is "true"
q = req.query
log.print 'RH', 'Received admin request: ' + req.originalUrl
log.info 'RH | Received admin request: ' + req.originalUrl
if q.cmd
@objAdminCmds[q.cmd]? q, answerHandler req, resp, true
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]`.
###
# **Requires:**
# **Loads Modules:**
# - [Logging](logging.html)
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
the port is already in use.
###
process.on 'uncaughtException', ( err ) ->
process.on 'uncaughtException', ( err ) =>
switch err.errno
when 'EADDRINUSE'
err.addInfo = 'http-port already in use, shutting down!'
log.error 'RS', err
@log.error err, 'RS | http-port already in use, shutting down!'
shutDown()
# else log.error 'RS', err
# else @log.error 'RS', err
else throw err
###
This function is invoked right after the module is loaded and starts the server.
@private init()
###
init = ->
init = =>
conf argv.c
# > Check whether the config file is ready, which is required to start the server.
if !conf.isReady()
@ -125,36 +124,39 @@ init = ->
logconf[ 'nolog' ] = argv.n
try
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
log = logger logconf
log.info 'RS | STARTING SERVER'
@log = logger.getLogger logconf
@log.info 'RS | STARTING SERVER'
args =
logger: log
logger: @log
logconf: logconf
# > Fetch the `http-port` argument
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
# > We only proceed with the initialization if the DB is ready
db.isConnected ( err, result ) ->
if !err
db.isConnected ( err, result ) =>
if err
shutDown()
else
# > Initialize all required modules with the args object.
log.info 'RS | Initialzing engine'
@log.info 'RS | Initialzing engine'
engine args
log.info 'RS | Initialzing http listener'
@log.info 'RS | Initialzing http listener'
http args
# > 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
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
http.addShutdownHandler shutDown
#TODO loadAction and addRule will be removed
#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 = [
args.logconf['mode']
args.logconf['io-level']
@ -169,10 +171,11 @@ Shuts down the server.
@private shutDown()
###
shutDown = ->
log.warn 'RS | Received shut down command!'
shutDown = =>
@log.warn 'RS | Received shut down command!'
engine?.shutDown()
http?.shutDown()
process.exit()
###
## Process Commands
@ -182,6 +185,9 @@ from the parent process (e.g. the testing suite)
###
process.on 'message', ( cmd ) -> procCmds[cmd]?()
process.on 'SIGINT', shutDown
process.on 'SIGTERM', shutDown
# The die command redirects to the shutDown function.
procCmds.die = shutDown

View file

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

View file

@ -1,17 +1,15 @@
'use strict';
var path = require('path'),
log = require('./logging'),
// qEvents = new (require('./queue')).Queue(), //TODO export queue into redis
regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X
listRules = {},
listActionModules = {},
isRunning = true,
mm, poller, db;
mm, poller, db, log;
exports = module.exports = function( args ) {
args = args || {};
log(args);
log = args.logger;
mm = require('./module-manager')(args);
return module.exports;
};
@ -28,12 +26,12 @@ exports.addPersistence = function(db_link) {
// if(err) log.error('EN', 'retrieving Action Modules from DB!');
// else {
// if(!obj) {
// log.print('EN', 'No Action Modules found in DB!');
// log.info('EN', 'No Action Modules found in DB!');
// loadRulesFromDB();
// } else {
// var m;
// for(var el in obj) {
// log.print('EN', 'Loading Action Module from DB: ' + el);
// log.info('EN', 'Loading Action Module from DB: ' + el);
// try{
// m = mm.requireFromString(obj[el], el);
// 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
// when rule is activated by user. invoked action then uses user specific
// parameters
log.print('EN', 'Action module "' + name + '" loaded');
log.info('EN', 'Action module "' + name + '" loaded');
listActionModules[name] = objModule;
};
@ -89,17 +87,17 @@ exports.getActionModule = function(name) {
*/
exports.addRule = function(objRule) {
//TODO validate rule
log.print('EN', 'Loading Rule');
log.print('EN', objRule);
log.print('EN', 'Loading Rule: ' + objRule.id);
if(listRules[objRule.id]) log.print('EN', 'Replacing rule: ' + objRule.id);
log.info('EN', 'Loading Rule');
log.info('EN', objRule);
log.info('EN', 'Loading Rule: ' + objRule.id);
if(listRules[objRule.id]) log.info('EN', 'Replacing rule: ' + objRule.id);
listRules[objRule.id] = objRule;
// Notify poller about eventual candidate
try {
poller.send('event|'+objRule.event);
} 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
*/
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);
for(var i = 0; i < actions.length; 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
// on one level above (eventid and other meta)
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);
}
}
@ -181,7 +179,7 @@ function invokeAction(evt, action) {
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() {
log.print('EN', 'Shutting down Poller and DB Link');
log.info('EN', 'Shutting down Poller and DB Link');
isRunning = false;
if(poller) poller.send('cmd|shutdown');
if(db) db.shutDown();

View file

@ -29,7 +29,7 @@ function init() {
logconf['file-path'] = process.argv[5]
logconf['nolog'] = process.argv[6]
log = logger(logconf);
log = logger.getLogger(logconf);
var args = { logger: log };
(ml = require('./module-manager'))(args);
(db = require('./persistence'))(args);
@ -39,6 +39,12 @@ function init() {
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) {
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.print('EP', 'Loading Event Module: ' + el);
// log.info('EP', 'Loading Event Module: ' + el);
try {
var m = ml.requireFromString(obj, el);
db.getEventModuleAuth(el, function(mod) {
@ -71,13 +77,13 @@ function fetchPollFunctionFromModule(mod, func) {
if(mod) mod = mod[func[i]];
}
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
// 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!
listPoll[func.join('->')] = mod;
} 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]]) {
fetchPollFunctionFromModule(listEventModules[arrModule[0]], arrModule);
} 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) {
if(err || !obj) log.error('EP', 'Event Module "' + arrModule[0] + '" not found: ' + err);
else {
log.print('EP', 'Event Module ' + arrModule[0] + ' found and loaded');
log.info('EP', 'Event Module ' + arrModule[0] + ' found and loaded');
fetchPollFunctionFromModule(obj, arrModule);
}
});
@ -115,14 +121,13 @@ function initMessageActions() {
if(func) func(arrProps);
}
});
// very important so the process doesnt linger on when the paren process is killed
process.on('disconnect', shutDown);
}
function initAdminCommands() {
listAdminCommands['shutdown'] = function(args) {
log.print('EP', 'Shutting down DB Link');
isRunning = false;
if(db) db.shutDown();
};
listAdminCommands['shutdown'] = shutDown
}
function checkRemotes() {

View file

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

View file

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

View file

@ -32,35 +32,27 @@ Persistence
/*
Module call
-----------
Initializes the DB connection. Requires a valid configuration file which contains
a db port and a crypto key.
Initializes the DB connection with the given `db-port` property in the `args` object.
@param {Object} args
*/
exports = module.exports = function(args) {
var config, _ref;
var _ref;
_this.log = args.logger;
config = require('./config');
config(args);
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
});
_this.db.on('error', function(err) {
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);
} else {
return _this.log.error('DB', 'Initialization failed because of missing config file!');
}
_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.db = redis.createClient(args['db-port'], 'localhost', {
connect_timeout: 2000
});
_this.db.on('error', function(err) {
return _this.log.warn(err, 'message from DB');
});
_this.ep = new IndexedModules('event-poller', _this.db, _this.log);
return _this.ai = new IndexedModules('action-invoker', _this.db, _this.log);
};
/*
@ -80,7 +72,7 @@ Persistence
numAttempts = 0;
fCheckConnection = function() {
if (_this.db.connected) {
_this.log.info('DB', 'Successfully connected to DB!');
_this.log.info('DB | Successfully connected to DB!');
return cb();
} else if (numAttempts++ < 10) {
return setTimeout(fCheckConnection, 100);
@ -103,10 +95,9 @@ Persistence
replyHandler = function(action) {
return function(err, reply) {
if (err) {
err.addInfo = "during '" + action + "'";
return _this.log.error('DB', err);
return _this.log.warn(err, "during '" + action + "'");
} else {
return _this.log.info('DB', "" + action + ": " + reply);
return _this.log.info("DB | " + action + ": " + reply);
}
};
};
@ -121,10 +112,10 @@ Persistence
exports.pushEvent = function(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));
} 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();
} catch (_error) {
err = _error;
err.addInfo = 'during hashing';
_this.log.error('DB', err);
_this.log.warn(err, 'DB | during hashing');
return null;
}
};
@ -199,8 +189,7 @@ Persistence
return crypto.AES.encrypt(plainText, _this.crypto_key);
} catch (_error) {
err = _error;
err.addInfo = 'during encryption';
_this.log.error('DB', err);
_this.log.warn(err, 'DB | during encryption');
return null;
}
};
@ -223,8 +212,7 @@ Persistence
return dec.toString(crypto.enc.Utf8);
} catch (_error) {
err = _error;
err.addInfo = 'during decryption';
_this.log.error('DB', err);
_this.log.warn(err, 'DB | during decryption');
return null;
}
};
@ -243,12 +231,11 @@ Persistence
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) {
var fCallback, objReplies, reply, semaphore, _i, _len, _results;
if (err) {
err.addInfo = "fetching '" + set + "'";
_this.log.error('DB', err);
_this.log.warn(err, "DB | fetching '" + set + "'");
return cb(err);
} else if (arrReply.length === 0) {
return cb();
@ -264,10 +251,9 @@ Persistence
return function(err, data) {
--semaphore;
if (err) {
err.addInfo = "fetching single element: '" + prop + "'";
_this.log.error('DB', err);
_this.log.warn(err, "DB | fetching single element: '" + prop + "'");
} 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 {
objReplies[prop] = data;
}
@ -300,56 +286,56 @@ Persistence
this.getModuleIds = __bind(this.getModuleIds, this);
this.getModule = __bind(this.getModule, 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) {
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 + "'"));
return this.db.set("" + this.setname + ":" + mId, data, replyHandler("Storing '" + this.setname + ":" + mId + "'"));
};
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);
};
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);
};
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);
};
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 + "'"));
return this.db.del("" + this.setname + ":" + mId, replyHandler("Deleting '" + this.setname + ":" + mId + "'"));
};
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 + "'"));
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) {
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 cb(err, decrypt(data));
});
};
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);
};
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 + "'"));
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) {
_this.log.info('DB', "getRule: '" + ruleId + "'");
_this.log.info("DB | getRule: '" + ruleId + "'");
return _this.db.get("rule:" + ruleId, cb);
};
@ -626,7 +612,7 @@ Persistence
exports.getRules = function(cb) {
_this.log.info('DB', 'Fetching all Rules');
_this.log.info('DB | Fetching all Rules');
return getSetRecords('rules', exports.getRule, cb);
};
@ -639,7 +625,7 @@ Persistence
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);
};
@ -653,7 +639,7 @@ Persistence
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 + "'"));
return _this.db.set("rule:" + ruleId, data, replyHandler("storing rule '" + ruleId + "'"));
};
@ -668,7 +654,7 @@ Persistence
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.del("rule:" + ruleId, replyHandler("Deleting rule '" + ruleId + "'"));
_this.db.smembers("rule:" + ruleId + ":users", function(err, obj) {
@ -709,7 +695,7 @@ Persistence
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 + "'"));
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) {
_this.log.info('DB', "getUserLinkedRules: for user '" + userId + "'");
_this.log.info("DB | getUserLinkedRules: for user '" + userId + "'");
return _this.db.smembers("user:" + userId + ":rules", cb);
};
@ -738,7 +724,7 @@ Persistence
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);
};
@ -752,7 +738,7 @@ Persistence
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 + "'"));
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) {
_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 + "'"));
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) {
_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);
};
@ -796,7 +782,7 @@ Persistence
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);
};
@ -810,7 +796,7 @@ Persistence
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 + "'"));
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) {
_this.log.info('DB', "Fetching all active rules");
_this.log.info("DB | Fetching all active rules");
return _this.db.smembers('users', function(err, obj) {
var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results;
result = {};
@ -867,13 +853,13 @@ Persistence
exports.storeUser = function(objUser) {
_this.log.info('DB', "storeUser: '" + objUser.username + "'");
_this.log.info("DB | storeUser: '" + objUser.username + "'");
if (objUser && objUser.username && objUser.password) {
_this.db.sadd('users', objUser.username, replyHandler("storing user key '" + objUser.username + "'"));
objUser.password = objUser.password;
return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties '" + objUser.username + "'"));
} 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) {
_this.log.info('DB', "getUserIds");
_this.log.info("DB | getUserIds");
return _this.db.smembers("users", cb);
};
@ -900,7 +886,7 @@ Persistence
exports.getUser = function(userId, cb) {
_this.log.info('DB', "getUser: '" + userId + "'");
_this.log.info("DB | getUser: '" + userId + "'");
return _this.db.hgetall("user:" + userId, cb);
};
@ -913,7 +899,7 @@ Persistence
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.del("user:" + userId, replyHandler("Deleting user '" + userId + "'"));
_this.db.smembers("user:" + userId + ":rules", function(err, obj) {
@ -972,14 +958,14 @@ Persistence
exports.loginUser = function(userId, password, cb) {
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) {
return function(err, obj) {
if (err) {
return cb(err, null);
} else if (obj && 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);
} else {
return cb(new Error('Wrong credentials!'), null);
@ -1007,7 +993,7 @@ Persistence
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("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 + "'"));
@ -1023,7 +1009,7 @@ Persistence
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);
};
@ -1037,7 +1023,7 @@ Persistence
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);
};
@ -1051,7 +1037,7 @@ Persistence
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 + "'"));
return _this.db.srem("role:" + role + ":users", userId, replyHandler("Removing user '" + userId + "' from role '" + role + "'"));
};

View file

@ -3,16 +3,17 @@
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() {
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;
log = require('./logging');
db = require('./persistence');
mm = require('./module-manager');
@ -38,9 +39,8 @@ Request Handler
objAdminCmds = {};
exports = module.exports = function(args) {
var user, users, _i, _len;
args = args != null ? args : {};
log(args);
var log, user, users, _i, _len;
log = args.logger;
db(args);
mm(args);
mm.addDBLink(db);
@ -122,7 +122,7 @@ Request Handler
obj = qs.parse(body);
return db.loginUser(obj.username, obj.password, function(err, usr) {
if (err) {
log.print('RH', ("AUTH-UH-OH (" + obj.username + "): ") + err.message);
log.warn(err, "RH | AUTH-UH-OH (" + obj.username + ")");
} else {
req.session.user = usr;
}
@ -341,7 +341,7 @@ Request Handler
if (req.session && req.session.user) {
if (req.session.user.isAdmin === "true") {
q = req.query;
log.print('RH', 'Received admin request: ' + req.originalUrl);
log.info('RH | Received admin request: ' + req.originalUrl);
if (q.cmd) {
return typeof (_base = _this.objAdminCmds)[_name = q.cmd] === "function" ? _base[_name](q, answerHandler(req, resp, true)) : void 0;
} 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() {
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');
@ -98,8 +99,7 @@ WebAPI-ECA Engine
process.on('uncaughtException', function(err) {
switch (err.errno) {
case 'EADDRINUSE':
err.addInfo = 'http-port already in use, shutting down!';
log.error('RS', err);
_this.log.error(err, 'RS | http-port already in use, shutting down!');
return shutDown();
default:
throw err;
@ -114,7 +114,7 @@ WebAPI-ECA Engine
init = function() {
var args, log, logconf;
var args, logconf;
conf(argv.c);
if (!conf.isReady()) {
console.error('FAIL: Config file not ready! Shutting down...');
@ -139,27 +139,30 @@ WebAPI-ECA Engine
try {
fs.unlinkSync(path.resolve(__dirname, '..', 'logs', logconf['file-path']));
} catch (_error) {}
log = logger(logconf);
log.info('RS | STARTING SERVER');
_this.log = logger.getLogger(logconf);
_this.log.info('RS | STARTING SERVER');
args = {
logger: log,
logger: _this.log,
logconf: logconf
};
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);
return db.isConnected(function(err, result) {
var cliArgs, poller;
if (!err) {
log.info('RS | Initialzing engine');
if (err) {
return shutDown();
} else {
_this.log.info('RS | Initialzing engine');
engine(args);
log.info('RS | Initialzing http listener');
_this.log.info('RS | Initialzing http listener');
http(args);
log.info('RS | Passing handlers to engine');
_this.log.info('RS | Passing handlers to engine');
engine.addPersistence(db);
log.info('RS | Passing handlers to http listener');
_this.log.info('RS | Passing handlers to http listener');
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']];
return poller = cp.fork(path.resolve(__dirname, 'event-poller'), cliArgs);
}
@ -174,11 +177,14 @@ WebAPI-ECA Engine
shutDown = function() {
log.warn('RS | Received shut down command!');
_this.log.warn('RS | Received shut down command!');
if (engine != null) {
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;
});
process.on('SIGINT', shutDown);
process.on('SIGTERM', shutDown);
procCmds.die = shutDown;
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-path'
]
test.expect 4 + reqProp.length
test.expect 3 + reqProp.length
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.getDbPort(), 'DB port does not exist!'
logconf = @conf.getLogConf()
test.ok logconf, 'Log config does not exist!'
for prop in reqProp

View file

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