Documentation and private vars update

This commit is contained in:
Dominic Bosch 2013-11-26 23:24:15 +01:00
parent eba1357e9e
commit a778cbcde5
15 changed files with 791 additions and 555 deletions

View file

@ -2,15 +2,16 @@
Config
======
> Loads the configuration file and acts as an interface to it.
Loads the configuration file and acts as an interface to it.
###
'use strict'
path = require 'path'
log = require './logging'
fs = require 'fs'
config = null
path = require 'path'
# Requires:
# - The [Logging](logging.html) module
log = require './logging'
###
##Module call
@ -19,7 +20,7 @@ Calling the module as a function will make it look for the `relPath` property in
args object and then try to load a config file from that relative path.
@param {Object} args
###
exports = module.exports = (args) ->
exports = module.exports = ( args ) ->
args = args ? {}
log args
if typeof args.relPath is 'string'
@ -33,11 +34,11 @@ Reads the config file synchronously from the file system and try to parse it.
@private loadConfigFile
@param {String} relPath
###
loadConfigFile = (relPath) ->
loadConfigFile = ( relPath ) =>
try
config = JSON.parse fs.readFileSync path.resolve __dirname, '..', relPath
if config and config.http_port and config.db_port and
config.crypto_key and config.session_secret
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', relPath
if @config and @config.http_port and @config.db_port and
@config.crypto_key and @config.session_secret
log.print 'CF', 'config file loaded successfully'
else
log.error 'CF', new Error("""Missing property in config file, requires:
@ -57,14 +58,14 @@ Fetch a property from the configuration
@private fetchProp( *prop* )
@param {String} prop
###
fetchProp = (prop) -> config?[prop]
fetchProp = ( prop ) => @config?[prop]
###
Answer true if the config file is ready, else false
@public isReady()
###
exports.isReady = -> config?
exports.isReady = => @config?
###
Returns the HTTP port

View file

@ -2,48 +2,48 @@
DB Interface
============
>Handles the connection to the database and provides functionalities for
>event/action modules, rules and the encrypted storing of authentication tokens.
>General functionality as a wrapper for the module holds initialization,
>encryption/decryption, the retrieval of modules and shut down.
>
>The general structure for linked data is that the key is stored in a set.
>By fetching all set entries we can then fetch all elements, which is
>automated in this function.
>For example modules of the same group, e.g. action modules are registered in an
>unordered set in the database, from where they can be retrieved again. For example
>a new action module has its ID (e.g 'probinder') first registered in the set
>'action_modules' and then stored in the db with the key 'action\_module\_' + ID
>(e.g. action\_module\_probinder).
> Handles the connection to the database and provides functionalities for
> event/action modules, rules and the encrypted storing of authentication tokens.
> General functionality as a wrapper for the module holds initialization,
> encryption/decryption, the retrieval of modules and shut down.
>
> The general structure for linked data is that the key is stored in a set.
> By fetching all set entries we can then fetch all elements, which is
> automated in this function.
> For example modules of the same group, e.g. action modules are registered in an
> unordered set in the database, from where they can be retrieved again. For example
> a new action module has its ID (e.g 'probinder') first registered in the set
> 'action_modules' and then stored in the db with the key 'action\_module\_' + ID
> (e.g. action\_module\_probinder).
>
###
'use strict'
### Grab all required modules ###
redis = require 'redis'
crypto = require 'crypto' # TODO change to Google's "crypto-js""
log = require './logging'
crypto_key = null
db = null
# Requires:
# - The [Logging](logging.html) module
log = require './logging'
###
##Module call
Module call
-----------
Initializes the DB connection. Requires a valid configuration file which contains
a db port and a crypto key.
@param {Object} args
###
exports = module.exports = (args) ->
exports = module.exports = ( args ) =>
args = args ? {}
log args
config = require './config'
config args
crypto_key = config.getCryptoKey()
db = redis.createClient config.getDBPort(), 'localhost', { connect_timeout: 2000 }
db.on "error", (err) ->
@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
@ -55,12 +55,12 @@ ten attempts within five seconds, or nothing on success to the callback(err).
@param {function} cb
###
#}TODO check if timeout works with func in func
exports.isConnected = (cb) ->
if db.connected then cb()
exports.isConnected = ( cb ) =>
if @db.connected then cb()
else
numAttempts = 0
fCheckConnection = ->
if db.connected
fCheckConnection = =>
if @db.connected
log.print 'DB', 'Successfully connected to DB!'
cb()
else if numAttempts++ < 10
@ -78,10 +78,10 @@ Encrypts a string using the crypto key from the config file, based on aes-256-cb
@private encrypt( *plainText* )
@param {String} plainText
###
encrypt = (plainText) ->
encrypt = ( plainText ) =>
if !plainText? then return null
try
enciph = crypto.createCipher 'aes-256-cbc', crypto_key
enciph = crypto.createCipher 'aes-256-cbc', @crypto_key
et = enciph.update plainText, 'utf8', 'base64'
et + enciph.final 'base64'
catch err
@ -95,10 +95,10 @@ Decrypts an encrypted string and hands it back on success or null.
@private decrypt( *crypticText* )
@param {String} crypticText
###
decrypt = (crypticText) ->
decrypt = ( crypticText ) =>
if !crypticText? then return null;
try
deciph = crypto.createDecipher 'aes-256-cbc', crypto_key
deciph = crypto.createDecipher 'aes-256-cbc', @crypto_key
dt = deciph.update crypticText, 'base64', 'utf8'
dt + deciph.final 'utf8'
catch err
@ -112,8 +112,8 @@ Abstracts logging for simple action replies from the DB.
@private replyHandler( *action* )
@param {String} action
###
replyHandler = (action) ->
(err, reply) ->
replyHandler = ( action ) ->
( err, reply ) ->
if err
err.addInfo = 'during "' + action + '"'
log.error 'DB', err
@ -129,9 +129,9 @@ via the provided function and returns the results to the callback(err, obj) func
@param {function} fSingle a function to retrieve a single data element per set entry
@param {function} cb the callback(err, obj) function that receives all the retrieved data or an error
###
getSetRecords = (set, fSingle, cb) ->
getSetRecords = ( set, fSingle, cb ) =>
log.print 'DB', 'Fetching set records: ' + set
db?.smembers set, (err, arrReply) ->
@db.smembers set, ( err, arrReply ) ->
if err
err.addInfo = 'fetching ' + set
log.error 'DB', err
@ -145,8 +145,8 @@ getSetRecords = (set, fSingle, cb) ->
if semaphore > 0
cb new Error('Timeout fetching ' + set)
, 2000
fCallback = (prop) ->
(err, data) ->
fCallback = ( prop ) ->
( err, data ) ->
--semaphore
if err
err.addInfo = 'fetching single element: ' + prop
@ -171,10 +171,10 @@ Store a string representation of an action module in the DB.
@param {String} data
###
# FIXME can the data be an object?
exports.storeActionModule = (id, data) ->
exports.storeActionModule = ( id, data ) =>
log.print 'DB', 'storeActionModule: ' + id
db?.sadd 'action-modules', id, replyHandler 'storing action module key ' + id
db?.set 'action-module:' + id, data, replyHandler 'storing action module ' + id
@db.sadd 'action-modules', id, replyHandler 'storing action module key ' + id
@db.set 'action-module:' + id, data, replyHandler 'storing action module ' + id
###
Query the DB for an action module and pass it to the callback(err, obj) function.
@ -183,9 +183,9 @@ Query the DB for an action module and pass it to the callback(err, obj) function
@param {String} id
@param {function} cb
###
exports.getActionModule = (id, cb) ->
exports.getActionModule = ( id, cb ) =>
log.print 'DB', 'getActionModule: ' + id
db?.get 'action-module:' + id, cb
@db.get 'action-module:' + id, cb
###
Fetch all action modules and hand them to the callback(err, obj) function.
@ -193,7 +193,7 @@ Fetch all action modules and hand them to the callback(err, obj) function.
@public getActionModules( *cb* )
@param {function} cb
###
exports.getActionModules = (cb) ->
exports.getActionModules = ( cb ) ->
getSetRecords 'action-modules', exports.getActionModule, cb
###
@ -204,9 +204,9 @@ Store a string representation of the authentication parameters for an action mod
@param {String} moduleId
@param {String} data
###
exports.storeActionAuth = (userId, moduleId, data) ->
exports.storeActionAuth = ( userId, moduleId, data ) =>
log.print 'DB', 'storeActionAuth: ' + userId + ':' + moduleId
db?.set 'action-auth:' + userId + ':' + moduleId, encrypt(data),
@db.set 'action-auth:' + userId + ':' + moduleId, encrypt(data),
replyHandler 'storing action auth ' + userId + ':' + moduleId
###
@ -218,9 +218,9 @@ and pass it to the callback(err, obj) function.
@param {String} moduleId
@param {function} cb
###
exports.getActionAuth = (userId, moduleId, cb) ->
exports.getActionAuth = ( userId, moduleId, cb ) =>
log.print 'DB', 'getActionAuth: ' + userId + ':' + moduleId
db?.get 'action-auth:' + userId + ':' + moduleId, (err, data) ->
@db.get 'action-auth:' + userId + ':' + moduleId, ( err, data ) ->
cb err, decrypt data
@ -235,10 +235,10 @@ Store a string representation of an event module in the DB.
@param {String} id
@param {String} data
###
exports.storeEventModule = (id, data) ->
exports.storeEventModule = ( id, data ) =>
log.print 'DB', 'storeEventModule: ' + id
db?.sadd 'event-modules', id, replyHandler 'storing event module key ' + id
db?.set 'event-module:' + id, data, replyHandler 'storing event module ' + id
@db.sadd 'event-modules', id, replyHandler 'storing event module key ' + id
@db.set 'event-module:' + id, data, replyHandler 'storing event module ' + id
###
Query the DB for an event module and pass it to the callback(err, obj) function.
@ -247,9 +247,9 @@ Query the DB for an event module and pass it to the callback(err, obj) function.
@param {String} id
@param {function} cb
###
exports.getEventModule = (id, cb) ->
exports.getEventModule = ( id, cb ) =>
log.print 'DB', 'getEventModule: ' + id
db?.get 'event_module:' + id, cb
@db.get 'event_module:' + id, cb
###
Fetch all event modules and pass them to the callback(err, obj) function.
@ -257,31 +257,33 @@ Fetch all event modules and pass them to the callback(err, obj) function.
@public getEventModules( *cb* )
@param {function} cb
###
exports.getEventModules = (cb) ->
exports.getEventModules = ( cb ) ->
getSetRecords 'event_modules', exports.getEventModule, cb
###
Store a string representation of he authentication parameters for an event module.
@public storeEventAuth( *userId, moduleId, data* )
@param {String} id
@param {String} data
@param {String} userId
@param {String} moduleId
@param {Object} data
###
exports.storeEventAuth = (userId, moduleId, data) ->
exports.storeEventAuth = ( userId, moduleId, data ) =>
log.print 'DB', 'storeEventAuth: ' + userId + ':' + moduleId
db?.set 'event-auth:' + userId + ':' + moduleId, encrypt(data),
@db.set 'event-auth:' + userId + ':' + moduleId, encrypt(data),
replyHandler 'storing event auth ' + userId + ':' + moduleId
###
Query the DB for an action module authentication token, associated with a user.
@public getEventAuth( *id, cb* )
@param {String} id
@public getEventAuth( *userId, moduleId, data* )
@param {String} userId
@param {String} moduleId
@param {function} cb
###
exports.getEventAuth = (userId, moduleId, cb) ->
exports.getEventAuth = ( userId, moduleId, cb ) =>
log.print 'DB', 'getEventAuth: ' + userId + ':' + moduleId
db?.get 'event-auth:' + userId + ':' + moduleId, (err, data) ->
@db.get 'event-auth:' + userId + ':' + moduleId, ( err, data ) ->
cb err, decrypt data
@ -296,10 +298,10 @@ Store a string representation of a rule in the DB.
@param {String} id
@param {String} data
###
exports.storeRule = (id, data) ->
exports.storeRule = ( id, data ) =>
log.print 'DB', 'storeRule: ' + id
db?.sadd 'rules', id, replyHandler 'storing rule key ' + id
db?.set 'rule:' + id, data, replyHandler 'storing rule ' + id
@db.sadd 'rules', id, replyHandler 'storing rule key ' + id
@db.set 'rule:' + id, data, replyHandler 'storing rule ' + id
###
Query the DB for a rule and pass it to the callback(err, obj) function.
@ -308,9 +310,9 @@ Query the DB for a rule and pass it to the callback(err, obj) function.
@param {String} id
@param {function} cb
###
exports.getRule = (id, cb) ->
exports.getRule = ( id, cb ) =>
log.print 'DB', 'getRule: ' + id
db?.get 'rule:' + id, cb
@db.get 'rule:' + id, cb
###
Fetch all rules from the database and pass them to the callback function.
@ -318,7 +320,7 @@ Fetch all rules from the database and pass them to the callback function.
@public getRules( *cb* )
@param {function} cb
###
exports.getRules = (cb) ->
exports.getRules = ( cb ) ->
log.print 'DB', 'Fetching all Rules'
getSetRecords 'rules', exports.getRule, cb
@ -328,12 +330,14 @@ Store a user object (needs to be a flat structure).
@public storeUser( *objUser* )
@param {Object} objUser
###
exports.storeUser = (objUser) ->
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.print 'DB', 'storeUser: ' + objUser.username
if objUser and objUser.username and objUser.password
db?.sadd 'users', objUser.username, replyHandler 'storing user key ' + objUser.username
@db.sadd 'users', objUser.username, replyHandler 'storing user key ' + objUser.username
objUser.password = encrypt objUser.password
db?.hmset 'user:' + objUser.username, objUser, replyHandler 'storing user properties ' + objUser.username
@db.hmset 'user:' + objUser.username, objUser, replyHandler 'storing user properties ' + objUser.username
else
log.error 'DB', new Error 'username or password was missing'
@ -344,10 +348,10 @@ Associate a role with a user.
@param {String} username
@param {String} role
###
exports.storeUserRole = (username, role) ->
exports.storeUserRole = ( username, role ) =>
log.print 'DB', 'storeUserRole: ' + username + ':' + role
db?.sadd 'user-roles:' + username, role, replyHandler 'adding role ' + role + ' to user ' + username
db?.sadd 'role-users:' + role, username, replyHandler 'adding user ' + username + ' to role ' + role
@db.sadd 'user-roles:' + username, role, replyHandler 'adding role ' + role + ' to user ' + username
@db.sadd 'role-users:' + role, username, replyHandler 'adding user ' + username + ' to role ' + role
###
Fetch all roles of a user and pass them to the callback(err, obj)
@ -355,9 +359,9 @@ Fetch all roles of a user and pass them to the callback(err, obj)
@public getUserRoles( *username* )
@param {String} username
###
exports.getUserRoles = (username) ->
exports.getUserRoles = ( username ) =>
log.print 'DB', 'getUserRole: ' + username
db?.get 'user-roles:' + username, cb
@db.get 'user-roles:' + username, cb
###
Fetch all users of a role and pass them to the callback(err, obj)
@ -365,9 +369,9 @@ Fetch all users of a role and pass them to the callback(err, obj)
@public getUserRoles( *role* )
@param {String} role
###
exports.getRoleUsers = (role) ->
exports.getRoleUsers = ( role ) =>
log.print 'DB', 'getRoleUsers: ' + role
db?.get 'role-users:' + role, cb
@db.get 'role-users:' + role, cb
###
Checks the credentials and on success returns the user object to the callback(err, obj) function.
@ -378,10 +382,10 @@ Checks the credentials and on success returns the user object to the callback(er
@param {function} cb
###
# TODO verify and test whole function
exports.loginUser = (username, password, cb) ->
exports.loginUser = ( username, password, cb ) =>
log.print 'DB', 'User "' + username + '" tries to log in'
fCheck = (pw) ->
(err, obj) ->
fCheck = ( pw ) ->
( err, obj ) ->
if err
cb err
else if obj and obj.password
@ -392,7 +396,7 @@ exports.loginUser = (username, password, cb) ->
cb new Error 'Wrong credentials!'
else
cb new Error 'Empty arguments!'
db?.hgetall 'user:' + username, fCheck password
@db.hgetall 'user:' + username, fCheck password
# TODO implement functions required for user sessions and the rule activation
@ -401,4 +405,4 @@ Shuts down the db link.
@public shutDown()
###
exports.shutDown = -> db?.quit()
exports.shutDown = => @db.quit()

View file

@ -0,0 +1,85 @@
###
HTTP Listener
=============
> Handles the HTTP requests to the server at the port specified by the
> [config](config.html) file.
###
path = require 'path'
express = require 'express'
app = express()
# } RedisStore = require('connect-redis')(express), # TODO use RedisStore for persistent sessions
qs = require 'querystring'
# Requires:
# - The [Logging](logging.html) module
log = require './logging'
# - The [Config](config.html) module
config = require './config'
# - The [User Handler](user_handler.html) module
userHandler = require './user_handler'
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)'
# The module needs to be called as a function to initialize it.
# After that it fetches the http\_port, db\_port & sess\_sec properties
# from the configuration file.
exports = module.exports = ( args ) ->
args = args ? {}
log args
config args
userHandler args
# TODO check whether this really does what it's supposed to do (fetch wrong sess property)
sess_sec = config.getSessionSecret() || sess_sec
module.exports
exports.addHandlers = ( fEvtHandler, fShutDown ) =>
userHandler.addShutdownHandler fShutDown
@eventHandler = fEvtHandler
# Add cookie support for session handling.
app.use express.cookieParser()
app.use express.session { secret: sess_sec }
log.print 'HL', 'no session backbone'
# Redirect the requests to the appropriate handler.
app.use '/', express.static path.resolve __dirname, '..', 'webpages'
app.get '/rulesforge', userHandler.handleRequest
app.get '/admin', userHandler.handleRequest
app.post '/login', userHandler.handleLogin
app.post '/push_event', onPushEvent
try
http_port = config.getHttpPort()
if http_port
app.listen http_port # inbound event channel
else
log.error 'HL', new Error 'No HTTP port found!? Nothing to listen on!...'
catch e
e.addInfo = 'opening port'
log.error e
#
# If a post request reaches the server, this function handles it and treats the request as a possible event.
#
onPushEvent = ( req, resp ) =>
body = ''
req.on 'data', ( data ) ->
body += data
req.on 'end', =>
obj = qs.parse body
# If required event properties are present we process the event #
if obj and obj.event and obj.eventid
resp.write 'Thank you for the event (' + obj.event + '[' + obj.eventid + '])!'
@eventHandler obj
else
resp.writeHead 400, { "Content-Type": "text/plain" }
resp.write 'Your event was missing important parameters!'
resp.end()
exports.shutDown = () ->
log.print 'HL', 'Shutting down HTTP listener'
process.exit() # This is a bit brute force...

View file

@ -1,6 +1,8 @@
###
Rules Server
============
>This is the main module that is used to run the whole server:
>
> node server [log_type http_port]
@ -14,46 +16,38 @@ Rules Server
>`http_port` can be set to use another port, than defined in the
>[config](config.html) file, to listen to, e.g. used by the test suite.
>
>---
>
###
'use strict'
### Grab all required modules ###
path = require 'path'
# Requires:
# - The [Logging](logging.html) module
log = require './logging'
# - The [Config](config.html) module
conf = require './config'
# - The [DB Interface](db_interface.html) module
db = require './db_interface'
# - The [Engine](engine.html) module
engine = require './engine'
# - The [HTTP Listener](http_listener.html) module
http_listener = require './http_listener'
mm = require './module_manager'
args = {}
procCmds = {}
### Prepare the admin commands that are issued via HTTP requests. ###
adminCmds =
'loadrules': mm.loadRulesFromFS,
'loadaction': mm.loadActionModuleFromFS,
'loadactions': mm.loadActionModulesFromFS,
'loadevent': mm.loadEventModuleFromFS,
'loadevents': mm.loadEventModulesFromFS,
'loadusers': http_listener.loadUsers,
'shutdown': shutDown
###
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
shutDown()
else log.error err
null
else throw err
###
This function is invoked right after the module is loaded and starts the server.
@ -85,9 +79,10 @@ init = ->
if process.argv.length > 3 then args.http_port = parseInt process.argv[3]
else log.print 'RS', 'No HTTP port passed, using standard port from config file'
log.print 'RS', 'Initialzing DB'
db args
### We only proceed with the initialization if the DB is ready ###
db.isConnected (err, result) ->
db.isConnected ( err, result ) ->
if !err
### Initialize all required modules with the args object.###
@ -95,57 +90,23 @@ init = ->
engine args
log.print 'RS', 'Initialzing http listener'
http_listener args
log.print 'RS', 'Initialzing module manager'
mm args
log.print 'RS', 'Initialzing DB'
### Distribute handlers between modules to link the application. ###
log.print 'RS', 'Passing handlers to engine'
engine.addDBLinkAndLoadActionsAndRules db
log.print 'RS', 'Passing handlers to http listener'
http_listener.addHandlers db, fAdminCommands, engine.pushEvent
log.print 'RS', 'Passing handlers to module manager'
mm.addHandlers db, engine.loadActionModule, engine.addRule
###
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
###
fAdminCommands = (args, answHandler) ->
if args and args.cmd
adminCmds[args.cmd]? args, answHandler
else
log.print 'RS', 'No command in request'
###
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
###
fAnsw = (ah) ->
###
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
###
() ->
if not ah.isAnswered()
ah.answerError 'Not handled...'
###
Delayed function call of the anonymous function that checks the answer handler
###
setTimeout fAnsw(answHandler), 2000
# TODO engine pushEvent needs to go into redis queue
http_listener.addHandlers db, engine.pushEvent, shutDown
# log.print 'RS', 'Passing handlers to module manager'
# TODO loadAction and addRule will be removed
# mm.addHandlers db, engine.loadActionModule, engine.addRule
###
Shuts down the server.
@private shutDown( *args, answHandler* )
@param {Object} args
@param {Object} answHandler
@private shutDown()
###
shutDown = (args, answHandler) ->
answHandler?.answerSuccess 'Goodbye!'
shutDown = ->
log.print 'RS', 'Received shut down command!'
engine?.shutDown()
http_listener?.shutDown()
@ -157,7 +118,7 @@ When the server is run as a child process, this function handles messages
from the parent process (e.g. the testing suite)
###
process.on 'message', (cmd) -> procCmds[cmd]?()
process.on 'message', ( cmd ) -> procCmds[cmd]?()
###
The die command redirects to the shutDown function.

View file

@ -1,10 +0,0 @@
efew = require 'fs'
###
root = exports ? this
root.foo = -> 'Hello World'
console.log root.foo()
My comments will show up here
###

138
coffee/user_handler.coffee Normal file
View file

@ -0,0 +1,138 @@
###
User Handler
============
> TODO Add documentation
###
fs = require 'fs'
path = require 'path'
qs = require 'querystring'
# Requires:
# - The [Logging](logging.html) module
log = require './logging'
# - The [DB Interface](db_interface.html) module
db = require './db_interface'
# - The [Module Manager](module_manager.html) module
mm = require './module_manager'
### Prepare the admin command handlers that are issued via HTTP requests. ###
objAdminCmds =
'loadrules': mm.loadRulesFromFS,
'loadaction': mm.loadActionModuleFromFS,
'loadactions': mm.loadActionModulesFromFS,
'loadevent': mm.loadEventModuleFromFS,
'loadevents': mm.loadEventModulesFromFS
exports = module.exports = ( args ) ->
args = args ? {}
log args
db args
mm args
mm.addDBLink db
users = JSON.parse fs.readFileSync path.resolve __dirname, '..', 'config', 'users.json'
db.storeUser user for user in users
module.exports
exports.addShutdownHandler = ( fShutdown ) ->
objAdminCmds.shutdown = fShutdown
exports.handleRequest = ( req, resp ) ->
req.on 'end', -> resp.end()
if req.session and req.session.user
resp.send 'You\'re logged in'
else
resp.sendfile path.resolve __dirname, '..', 'webpages', 'handlers', 'login.html'
req.session.lastPage = req.originalUrl
exports.handleLogin = ( req, resp ) ->
body = ''
req.on 'data', ( data ) -> body += data
req.on 'end', ->
if not req.session or not req.session.user
obj = qs.parse body
db.loginUser obj.username, obj.password, ( err, obj ) ->
if not err
req.session.user = obj
if req.session.user
resp.write 'Welcome ' + req.session.user.name + '!'
else
resp.writeHead 401, { "Content-Type": "text/plain" }
resp.write 'Login failed!'
resp.end()
else
resp.write 'Welcome ' + req.session.user.name + '!'
resp.end()
answerHandler = ( resp ) ->
hasBeenAnswered = false
postAnswer( msg ) ->
if not hasBeenAnswered
resp.write msg
resp.end()
hasBeenAnswered = true
{
answerSuccess: ( msg ) ->
if not hasBeenAnswered
postAnswer msg,
answerError: ( msg ) ->
if not hasBeenAnswered
resp.writeHead 400, { "Content-Type": "text/plain" }
postAnswer msg,
isAnswered: -> hasBeenAnswered
}
# TODO add loadUsers as directive to admin commands
# exports.loadUsers = ->
# var users = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'users.json')));
# for(var name in users) {
# db.storeUser(users[name]);
# }
# };
onAdminCommand = ( req, response ) ->
q = req.query;
log.print 'HL', 'Received admin request: ' + req.originalUrl
if q.cmd
fAdminCommands q, answerHandler response
#answerSuccess(response, 'Thank you, we try our best!');
else answerError response, 'I\'m not sure about what you want from me...'
###
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
###
fAdminCommands = ( args, answHandler ) ->
if args and args.cmd
adminCmds[args.cmd]? args, answHandler
else
log.print 'RS', 'No command in request'
###
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
###
fAnsw = ( ah ) ->
###
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
###
() ->
if not ah.isAnswered()
ah.answerError 'Not handled...'
###
Delayed function call of the anonymous function that checks the answer handler
###
setTimeout fAnsw(answHandler), 2000

View file

@ -3,23 +3,20 @@
Config
======
Loads the configuration file and acts as an interface to it.
> Loads the configuration file and acts as an interface to it.
*/
(function() {
'use strict';
var config, exports, fetchProp, fs, loadConfigFile, log, path;
var exports, fetchProp, fs, loadConfigFile, log, path,
_this = this;
fs = require('fs');
path = require('path');
log = require('./logging');
fs = require('fs');
config = null;
/*
##Module call
@ -50,8 +47,8 @@ Loads the configuration file and acts as an interface to it.
loadConfigFile = function(relPath) {
var e;
try {
config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', relPath)));
if (config && config.http_port && config.db_port && config.crypto_key && config.session_secret) {
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', relPath)));
if (_this.config && _this.config.http_port && _this.config.db_port && _this.config.crypto_key && _this.config.session_secret) {
return log.print('CF', 'config file loaded successfully');
} else {
return log.error('CF', new Error("Missing property in config file, requires:\n- http_port\n- db_port\n- crypto_key\n- session_secret"));
@ -74,7 +71,8 @@ Loads the configuration file and acts as an interface to it.
fetchProp = function(prop) {
return config != null ? config[prop] : void 0;
var _ref;
return (_ref = _this.config) != null ? _ref[prop] : void 0;
};
/*
@ -85,7 +83,7 @@ Loads the configuration file and acts as an interface to it.
exports.isReady = function() {
return config != null;
return _this.config != null;
};
/*

View file

@ -3,28 +3,26 @@
DB Interface
============
>Handles the connection to the database and provides functionalities for
>event/action modules, rules and the encrypted storing of authentication tokens.
>General functionality as a wrapper for the module holds initialization,
>encryption/decryption, the retrieval of modules and shut down.
>
>The general structure for linked data is that the key is stored in a set.
>By fetching all set entries we can then fetch all elements, which is
>automated in this function.
>For example modules of the same group, e.g. action modules are registered in an
>unordered set in the database, from where they can be retrieved again. For example
>a new action module has its ID (e.g 'probinder') first registered in the set
>'action_modules' and then stored in the db with the key 'action\_module\_' + ID
>(e.g. action\_module\_probinder).
> Handles the connection to the database and provides functionalities for
> event/action modules, rules and the encrypted storing of authentication tokens.
> General functionality as a wrapper for the module holds initialization,
> encryption/decryption, the retrieval of modules and shut down.
>
> The general structure for linked data is that the key is stored in a set.
> By fetching all set entries we can then fetch all elements, which is
> automated in this function.
> For example modules of the same group, e.g. action modules are registered in an
> unordered set in the database, from where they can be retrieved again. For example
> a new action module has its ID (e.g 'probinder') first registered in the set
> 'action_modules' and then stored in the db with the key 'action\_module\_' + ID
> (e.g. action\_module\_probinder).
>
*/
(function() {
'use strict';
/* Grab all required modules*/
var crypto, crypto_key, db, decrypt, encrypt, exports, getSetRecords, log, redis, replyHandler;
var crypto, decrypt, encrypt, exports, getSetRecords, log, redis, replyHandler,
_this = this;
redis = require('redis');
@ -32,15 +30,12 @@ DB Interface
log = require('./logging');
crypto_key = null;
db = null;
/*
##Module call
Module call
-----------
Initializes the DB connection. Requires a valid configuration file which contains
a db port and a crypto key.
@param {Object} args
*/
@ -51,11 +46,11 @@ DB Interface
log(args);
config = require('./config');
config(args);
crypto_key = config.getCryptoKey();
db = redis.createClient(config.getDBPort(), 'localhost', {
_this.crypto_key = config.getCryptoKey();
_this.db = redis.createClient(config.getDBPort(), 'localhost', {
connect_timeout: 2000
});
return db.on("error", function(err) {
return _this.db.on("error", function(err) {
err.addInfo = 'message from DB';
return log.error('DB', err);
});
@ -72,13 +67,13 @@ DB Interface
exports.isConnected = function(cb) {
var fCheckConnection, numAttempts;
if (db.connected) {
if (_this.db.connected) {
return cb();
} else {
numAttempts = 0;
fCheckConnection = function() {
var e;
if (db.connected) {
if (_this.db.connected) {
log.print('DB', 'Successfully connected to DB!');
return cb();
} else if (numAttempts++ < 10) {
@ -107,7 +102,7 @@ DB Interface
return null;
}
try {
enciph = crypto.createCipher('aes-256-cbc', crypto_key);
enciph = crypto.createCipher('aes-256-cbc', _this.crypto_key);
et = enciph.update(plainText, 'utf8', 'base64');
return et + enciph.final('base64');
} catch (_error) {
@ -132,7 +127,7 @@ DB Interface
return null;
}
try {
deciph = crypto.createDecipher('aes-256-cbc', crypto_key);
deciph = crypto.createDecipher('aes-256-cbc', _this.crypto_key);
dt = deciph.update(crypticText, 'base64', 'utf8');
return dt + deciph.final('utf8');
} catch (_error) {
@ -175,7 +170,7 @@ DB Interface
getSetRecords = function(set, fSingle, cb) {
log.print('DB', 'Fetching set records: ' + set);
return db != null ? db.smembers(set, function(err, arrReply) {
return _this.db.smembers(set, function(err, arrReply) {
var fCallback, objReplies, reply, semaphore, _i, _len, _results;
if (err) {
err.addInfo = 'fetching ' + set;
@ -213,7 +208,7 @@ DB Interface
}
return _results;
}
}) : void 0;
});
};
/*
@ -232,10 +227,8 @@ DB Interface
exports.storeActionModule = function(id, data) {
log.print('DB', 'storeActionModule: ' + id);
if (db != null) {
db.sadd('action-modules', id, replyHandler('storing action module key ' + id));
}
return db != null ? db.set('action-module:' + id, data, replyHandler('storing action module ' + id)) : void 0;
_this.db.sadd('action-modules', id, replyHandler('storing action module key ' + id));
return _this.db.set('action-module:' + id, data, replyHandler('storing action module ' + id));
};
/*
@ -249,7 +242,7 @@ DB Interface
exports.getActionModule = function(id, cb) {
log.print('DB', 'getActionModule: ' + id);
return db != null ? db.get('action-module:' + id, cb) : void 0;
return _this.db.get('action-module:' + id, cb);
};
/*
@ -276,7 +269,7 @@ DB Interface
exports.storeActionAuth = function(userId, moduleId, data) {
log.print('DB', 'storeActionAuth: ' + userId + ':' + moduleId);
return db != null ? db.set('action-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing action auth ' + userId + ':' + moduleId)) : void 0;
return _this.db.set('action-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing action auth ' + userId + ':' + moduleId));
};
/*
@ -292,9 +285,9 @@ DB Interface
exports.getActionAuth = function(userId, moduleId, cb) {
log.print('DB', 'getActionAuth: ' + userId + ':' + moduleId);
return db != null ? db.get('action-auth:' + userId + ':' + moduleId, function(err, data) {
return _this.db.get('action-auth:' + userId + ':' + moduleId, function(err, data) {
return cb(err, decrypt(data));
}) : void 0;
});
};
/*
@ -313,10 +306,8 @@ DB Interface
exports.storeEventModule = function(id, data) {
log.print('DB', 'storeEventModule: ' + id);
if (db != null) {
db.sadd('event-modules', id, replyHandler('storing event module key ' + id));
}
return db != null ? db.set('event-module:' + id, data, replyHandler('storing event module ' + id)) : void 0;
_this.db.sadd('event-modules', id, replyHandler('storing event module key ' + id));
return _this.db.set('event-module:' + id, data, replyHandler('storing event module ' + id));
};
/*
@ -330,7 +321,7 @@ DB Interface
exports.getEventModule = function(id, cb) {
log.print('DB', 'getEventModule: ' + id);
return db != null ? db.get('event_module:' + id, cb) : void 0;
return _this.db.get('event_module:' + id, cb);
};
/*
@ -349,30 +340,32 @@ DB Interface
Store a string representation of he authentication parameters for an event module.
@public storeEventAuth( *userId, moduleId, data* )
@param {String} id
@param {String} data
@param {String} userId
@param {String} moduleId
@param {Object} data
*/
exports.storeEventAuth = function(userId, moduleId, data) {
log.print('DB', 'storeEventAuth: ' + userId + ':' + moduleId);
return db != null ? db.set('event-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing event auth ' + userId + ':' + moduleId)) : void 0;
return _this.db.set('event-auth:' + userId + ':' + moduleId, encrypt(data), replyHandler('storing event auth ' + userId + ':' + moduleId));
};
/*
Query the DB for an action module authentication token, associated with a user.
@public getEventAuth( *id, cb* )
@param {String} id
@public getEventAuth( *userId, moduleId, data* )
@param {String} userId
@param {String} moduleId
@param {function} cb
*/
exports.getEventAuth = function(userId, moduleId, cb) {
log.print('DB', 'getEventAuth: ' + userId + ':' + moduleId);
return db != null ? db.get('event-auth:' + userId + ':' + moduleId, function(err, data) {
return _this.db.get('event-auth:' + userId + ':' + moduleId, function(err, data) {
return cb(err, decrypt(data));
}) : void 0;
});
};
/*
@ -391,10 +384,8 @@ DB Interface
exports.storeRule = function(id, data) {
log.print('DB', 'storeRule: ' + id);
if (db != null) {
db.sadd('rules', id, replyHandler('storing rule key ' + id));
}
return db != null ? db.set('rule:' + id, data, replyHandler('storing rule ' + id)) : void 0;
_this.db.sadd('rules', id, replyHandler('storing rule key ' + id));
return _this.db.set('rule:' + id, data, replyHandler('storing rule ' + id));
};
/*
@ -408,7 +399,7 @@ DB Interface
exports.getRule = function(id, cb) {
log.print('DB', 'getRule: ' + id);
return db != null ? db.get('rule:' + id, cb) : void 0;
return _this.db.get('rule:' + id, cb);
};
/*
@ -435,11 +426,9 @@ DB Interface
exports.storeUser = function(objUser) {
log.print('DB', 'storeUser: ' + objUser.username);
if (objUser && objUser.username && objUser.password) {
if (db != null) {
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 = encrypt(objUser.password);
return db != null ? db.hmset('user:' + objUser.username, objUser, replyHandler('storing user properties ' + objUser.username)) : void 0;
return _this.db.hmset('user:' + objUser.username, objUser, replyHandler('storing user properties ' + objUser.username));
} else {
return log.error('DB', new Error('username or password was missing'));
}
@ -456,10 +445,8 @@ DB Interface
exports.storeUserRole = function(username, role) {
log.print('DB', 'storeUserRole: ' + username + ':' + role);
if (db != null) {
db.sadd('user-roles:' + username, role, replyHandler('adding role ' + role + ' to user ' + username));
}
return db != null ? db.sadd('role-users:' + role, username, replyHandler('adding user ' + username + ' to role ' + role)) : void 0;
_this.db.sadd('user-roles:' + username, role, replyHandler('adding role ' + role + ' to user ' + username));
return _this.db.sadd('role-users:' + role, username, replyHandler('adding user ' + username + ' to role ' + role));
};
/*
@ -472,7 +459,7 @@ DB Interface
exports.getUserRoles = function(username) {
log.print('DB', 'getUserRole: ' + username);
return db != null ? db.get('user-roles:' + username, cb) : void 0;
return _this.db.get('user-roles:' + username, cb);
};
/*
@ -485,7 +472,7 @@ DB Interface
exports.getRoleUsers = function(role) {
log.print('DB', 'getRoleUsers: ' + role);
return db != null ? db.get('role-users:' + role, cb) : void 0;
return _this.db.get('role-users:' + role, cb);
};
/*
@ -517,7 +504,7 @@ DB Interface
}
};
};
return db != null ? db.hgetall('user:' + username, fCheck(password)) : void 0;
return _this.db.hgetall('user:' + username, fCheck(password));
};
/*
@ -528,7 +515,7 @@ DB Interface
exports.shutDown = function() {
return db != null ? db.quit() : void 0;
return _this.db.quit();
};
}).call(this);

View file

@ -1,116 +1,95 @@
// HTTP Listener
// =============
//
// Handles the HTTP requests to the server at the port specified by the [config](config.html) file.
'use strict';
var path = require('path'),
express = require('express'),
app = express(),
RedisStore = require('connect-redis')(express),
qs = require('querystring'),
log = require('./logging'),
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)',
db_port, http_port, server,
eventHandler, userHandler;
// Generated by CoffeeScript 1.6.3
/*
* The module needs to be called as a function to initialize it.
* After that it fetches the http\_port, db\_port & sess\_sec properties
* from the configuration file.
*/
exports = module.exports = function(args) {
args = args || {};
log(args);
var config = require('./config')(args);
userHandler = require('./user_handler')(args);
db_port = config.getDBPort(),
sess_sec = config.getSessionSecret(),
http_port = config.getHttpPort();
return module.exports;
};
exports.addHandlers = function(funcAdminHandler, funcEvtHandler) {
if(!funcAdminHandler || !funcEvtHandler) {
log.error('HL', 'ERROR: either adminHandler or eventHandler function not defined!');
return;
}
userHandler.addHandler(funcAdminHandler);
eventHandler = funcEvtHandler;
// Add cookie support for session handling.
app.use(express.cookieParser());
app.use(express.session({secret: sess_sec}));
log.print('HL', 'no session backbone');
// ^ TODO figure out why redis backbone doesn't work. eventually the db pass has to be set in the DB?
// } session information seems to be stored in DB but not retrieved correctly
// } if(db_port) {
// } app.use(express.session({
// } store: new RedisStore({
// } host: 'localhost',
// } port: db_port,
// } db: 2
// } ,
// } pass: null
// } }),
// } secret: sess_sec
// } }));
// } log.print('HL', 'Added redis DB as session backbone');
// } } else {
// } app.use(express.session({secret: sess_sec}));
// } log.print('HL', 'no session backbone');
// } }
HTTP Listener
=============
> Handles the HTTP requests to the server at the port specified by the
> [config](config.html) file.
*/
// Redirect the requests to the appropriate handler.
app.use('/', express.static(path.resolve(__dirname, '..', 'webpages')));
// app.use('/doc/', express.static(path.resolve(__dirname, '..', 'webpages', 'doc')));
// app.get('/mobile', userHandler.handleRequest);
app.get('/rulesforge', userHandler.handleRequest);
// app.use('/mobile', express.static(path.resolve(__dirname, '..', 'webpages', 'mobile')));
// } app.use('/rulesforge/', express.static(path.resolve(__dirname, '..', 'webpages', 'rulesforge')));
app.get('/admin', userHandler.handleRequest);
app.post('/login', userHandler.handleLogin);
app.post('/push_event', onPushEvent);
try {
if(http_port) server = app.listen(http_port); // inbound event channel
else log.error('HL', new Error('No HTTP port found!? Nothing to listen on!...'));
} catch(e) {
e.addInfo = 'port unavailable';
log.error(e);
funcAdminHandler({cmd: 'shutdown'});
}
};
/**
* If a post request reaches the server, this function handles it and treats the request as a possible event.
*/
function onPushEvent(req, resp) {
var body = '';
req.on('data', function (data) { body += data; });
req.on('end', function () {
var obj = qs.parse(body);
/* If required event properties are present we process the event */
if(obj && obj.event && obj.eventid){
resp.writeHead(200, { "Content-Type": "text/plain" });
resp.write('Thank you for the event (' + obj.event + '[' + obj.eventid + '])!');
eventHandler(obj);
} else {
resp.writeHead(400, { "Content-Type": "text/plain" });
resp.write('Your event was missing important parameters!');
(function() {
var app, config, exports, express, log, onPushEvent, path, qs, sess_sec, userHandler,
_this = this;
path = require('path');
express = require('express');
app = express();
qs = require('querystring');
log = require('./logging');
config = require('./config');
userHandler = require('./user_handler');
sess_sec = '#C[>;j`@".TXm2TA;A2Tg)';
exports = module.exports = function(args) {
args = args != null ? args : {};
log(args);
config(args);
userHandler(args);
sess_sec = config.getSessionSecret() || sess_sec;
return module.exports;
};
exports.addHandlers = function(fEvtHandler, fShutDown) {
var e, http_port;
userHandler.addShutdownHandler(fShutDown);
_this.eventHandler = fEvtHandler;
app.use(express.cookieParser());
app.use(express.session({
secret: sess_sec
}));
log.print('HL', 'no session backbone');
app.use('/', express["static"](path.resolve(__dirname, '..', 'webpages')));
app.get('/rulesforge', userHandler.handleRequest);
app.get('/admin', userHandler.handleRequest);
app.post('/login', userHandler.handleLogin);
app.post('/push_event', onPushEvent);
try {
http_port = config.getHttpPort();
if (http_port) {
return app.listen(http_port);
} else {
return log.error('HL', new Error('No HTTP port found!? Nothing to listen on!...'));
}
} catch (_error) {
e = _error;
e.addInfo = 'opening port';
return log.error(e);
}
resp.end();
});
}
};
exports.loadUsers = function() {
var users = JSON.parse(require('fs').readFileSync(path.resolve(__dirname, '..', relPath)));
for(var name in users) {
}
};
onPushEvent = function(req, resp) {
var body;
body = '';
req.on('data', function(data) {
return body += data;
});
return req.on('end', function() {
var obj;
obj = qs.parse(body);
if (obj && obj.event && obj.eventid) {
resp.write('Thank you for the event (' + obj.event + '[' + obj.eventid + '])!');
_this.eventHandler(obj);
} else {
resp.writeHead(400, {
"Content-Type": "text/plain"
});
resp.write('Your event was missing important parameters!');
}
return resp.end();
});
};
exports.shutDown = function() {
log.print('HL', 'Shutting down HTTP listener');
process.exit(); // This is a bit brute force...
};
exports.shutDown = function() {
log.print('HL', 'Shutting down HTTP listener');
return process.exit();
};
}).call(this);

View file

@ -21,10 +21,10 @@ exports = module.exports = function(args) {
return module.exports;
};
exports.addHandlers = function(db_link, fLoadAction, fLoadRule) {
exports.addDBLink = function(db_link) {
db = db_link;
funcLoadAction = fLoadAction;
funcLoadRule = fLoadRule;
// funcLoadAction = fLoadAction;
// funcLoadRule = fLoadRule;
};
/*
@ -47,7 +47,7 @@ exports.loadRulesFromFS = function(args, answHandler) {
for(var i = 0; i < arr.length; i++) {
txt += arr[i].id + ', ';
db.storeRule(arr[i].id, JSON.stringify(arr[i]));
funcLoadRule(arr[i]);
// funcLoadRule(arr[i]);
}
answHandler.answerSuccess('Yep, loaded rules: ' + txt);
} catch (e) {
@ -71,7 +71,7 @@ exports.loadRulesFromFS = function(args, answHandler) {
*/
function loadActionCallback(name, data, mod, auth) {
db.storeActionModule(name, data); // store module in db
funcLoadAction(name, mod); // hand back compiled module
// funcLoadAction(name, mod); // hand back compiled module
if(auth) db.storeActionModuleAuth(name, auth);
}

View file

@ -1,7 +1,9 @@
// Generated by CoffeeScript 1.6.3
/*
Rules Server
============
>This is the main module that is used to run the whole server:
>
> node server [log_type http_port]
@ -15,17 +17,12 @@ Rules Server
>`http_port` can be set to use another port, than defined in the
>[config](config.html) file, to listen to, e.g. used by the test suite.
>
>---
>
*/
(function() {
'use strict';
/* Grab all required modules*/
var adminCmds, args, conf, db, engine, fAdminCommands, http_listener, init, log, mm, path, procCmds, shutDown;
path = require('path');
var args, conf, db, engine, http_listener, init, log, procCmds, shutDown;
log = require('./logging');
@ -37,25 +34,10 @@ Rules Server
http_listener = require('./http_listener');
mm = require('./module_manager');
args = {};
procCmds = {};
/* Prepare the admin commands that are issued via HTTP requests.*/
adminCmds = {
'loadrules': mm.loadRulesFromFS,
'loadaction': mm.loadActionModuleFromFS,
'loadactions': mm.loadActionModulesFromFS,
'loadevent': mm.loadEventModuleFromFS,
'loadevents': mm.loadEventModulesFromFS,
'loadusers': http_listener.loadUsers,
'shutdown': shutDown
};
/*
Error handling of the express port listener requires special attention,
thus we have to catch the process error, which is issued if
@ -68,12 +50,10 @@ Rules Server
case 'EADDRINUSE':
err.addInfo = 'http_port already in use, shutting down!';
log.error('RS', err);
shutDown();
break;
return shutDown();
default:
log.error(err);
throw err;
}
return null;
});
/*
@ -119,6 +99,7 @@ Rules Server
} else {
log.print('RS', 'No HTTP port passed, using standard port from config file');
}
log.print('RS', 'Initialzing DB');
db(args);
/* We only proceed with the initialization if the DB is ready*/
@ -130,75 +111,24 @@ Rules Server
engine(args);
log.print('RS', 'Initialzing http listener');
http_listener(args);
log.print('RS', 'Initialzing module manager');
mm(args);
log.print('RS', 'Initialzing DB');
/* Distribute handlers between modules to link the application.*/
log.print('RS', 'Passing handlers to engine');
engine.addDBLinkAndLoadActionsAndRules(db);
log.print('RS', 'Passing handlers to http listener');
http_listener.addHandlers(db, fAdminCommands, engine.pushEvent);
log.print('RS', 'Passing handlers to module manager');
return mm.addHandlers(db, engine.loadActionModule, engine.addRule);
return http_listener.addHandlers(db, engine.pushEvent, shutDown);
}
});
};
/*
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
*/
fAdminCommands = function(args, answHandler) {
var fAnsw, _name;
if (args && args.cmd) {
if (typeof adminCmds[_name = args.cmd] === "function") {
adminCmds[_name](args, answHandler);
}
} else {
log.print('RS', 'No command in request');
}
/*
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
*/
fAnsw = function(ah) {
/*
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
*/
return function() {
if (!ah.isAnswered()) {
return ah.answerError('Not handled...');
}
};
};
/*
Delayed function call of the anonymous function that checks the answer handler
*/
return setTimeout(fAnsw(answHandler), 2000);
};
/*
Shuts down the server.
@private shutDown( *args, answHandler* )
@param {Object} args
@param {Object} answHandler
@private shutDown()
*/
shutDown = function(args, answHandler) {
if (answHandler != null) {
answHandler.answerSuccess('Goodbye!');
}
shutDown = function() {
log.print('RS', 'Received shut down command!');
if (engine != null) {
engine.shutDown();

View file

@ -1,16 +0,0 @@
// Generated by CoffeeScript 1.6.3
(function() {
var efew;
efew = require('fs');
/*
root = exports ? this
root.foo = -> 'Hello World'
console.log root.foo()
My comments will show up here
*/
}).call(this);

View file

@ -1,96 +1,180 @@
var path = require('path'),
qs = require('querystring'),
log = require('./logging'),
db = require('./db_interface'),
adminHandler;
exports = module.exports = function(args) {
args = args || {};
log(args);
db(args);
var users = JSON.parse(require('fs').readFileSync(path.resolve(__dirname, '..', 'config', 'users.json')));
for(var i = 0; i < users.length; i++) {
log.print('UH', 'Found user ' + users[i].username + ' in user file, storing him in the DB');
db.storeUser(users[i]);
}
return module.exports;
};
// Generated by CoffeeScript 1.6.3
/*
exports.addHandler = function(adminHandl) {
adminHandler = adminHandl;
};
User Handler
============
> TODO Add documentation
*/
exports.handleRequest = function(req, resp) {
req.on('end', function () {
resp.end();
});
if(req.session && req.session.user) {
resp.send('You\'re logged in');
} else resp.sendfile(path.resolve(__dirname, '..', 'webpages', 'handlers', 'login.html'));
// resp.end();
log.print('UH', 'last: '+ req.session.lastPage);
req.session.lastPage = req.originalUrl;
log.print('UH', 'last: '+ req.session.lastPage);
log.print('UH', 'retrieved req: '+ req.originalUrl);
// console.log(req);
};
exports.handleLogin = function(req, resp) {
var body = '';
req.on('data', function (data) { body += data; });
req.on('end', function () {
if(!req.session || !req.session.user) {
var obj = qs.parse(body);
db.loginUser(obj.username, obj.password, function(err, obj) {
if(err) {
log.error('UH', err);
resp.writeHead(401, { "Content-Type": "text/plain" });
resp.write('Login failed!');
}
else {
req.session.user = obj;
if(req.session.user) {
(function() {
var answerHandler, db, exports, fAdminCommands, fs, log, mm, objAdminCmds, onAdminCommand, path, qs;
fs = require('fs');
path = require('path');
qs = require('querystring');
log = require('./logging');
db = require('./db_interface');
mm = require('./module_manager');
/* Prepare the admin command handlers that are issued via HTTP requests.*/
objAdminCmds = {
'loadrules': mm.loadRulesFromFS,
'loadaction': mm.loadActionModuleFromFS,
'loadactions': mm.loadActionModulesFromFS,
'loadevent': mm.loadEventModuleFromFS,
'loadevents': mm.loadEventModulesFromFS
};
exports = module.exports = function(args) {
var user, users, _i, _len;
args = args != null ? args : {};
log(args);
db(args);
mm(args);
mm.addDBLink(db);
users = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'config', 'users.json')));
for (_i = 0, _len = users.length; _i < _len; _i++) {
user = users[_i];
db.storeUser(user);
}
return module.exports;
};
exports.addShutdownHandler = function(fShutdown) {
return objAdminCmds.shutdown = fShutdown;
};
exports.handleRequest = function(req, resp) {
req.on('end', function() {
return resp.end();
});
if (req.session && req.session.user) {
resp.send('You\'re logged in');
} else {
resp.sendfile(path.resolve(__dirname, '..', 'webpages', 'handlers', 'login.html'));
}
return req.session.lastPage = req.originalUrl;
};
exports.handleLogin = function(req, resp) {
var body;
body = '';
req.on('data', function(data) {
return body += data;
});
return req.on('end', function() {
var obj;
if (!req.session || !req.session.user) {
obj = qs.parse(body);
return db.loginUser(obj.username, obj.password, function(err, obj) {
if (!err) {
req.session.user = obj;
}
if (req.session.user) {
resp.write('Welcome ' + req.session.user.name + '!');
} else {
resp.writeHead(401, { "Content-Type": "text/plain" });
resp.writeHead(401, {
"Content-Type": "text/plain"
});
resp.write('Login failed!');
}
}
resp.end();
});
}
});
};
function answerHandler(r) {
var response = r, hasBeenAnswered = false;
function postAnswer(msg) {
if(!hasBeenAnswered) {
response.write(msg);
response.end();
hasBeenAnswered = true;
}
}
return {
answerSuccess: function(msg) {
if(!hasBeenAnswered) response.writeHead(200, { "Content-Type": "text/plain" });
postAnswer(msg);
},
answerError: function(msg) {
if(!hasBeenAnswered) response.writeHead(400, { "Content-Type": "text/plain" });
postAnswer(msg);
},
isAnswered: function() { return hasBeenAnswered; }
return resp.end();
});
} else {
resp.write('Welcome ' + req.session.user.name + '!');
return resp.end();
}
});
};
};
function onAdminCommand(request, response) {
var q = request.query;
log.print('HL', 'Received admin request: ' + request.originalUrl);
if(q.cmd) {
adminHandler(q, answerHandler(response));
// answerSuccess(response, 'Thank you, we try our best!');
} else answerError(response, 'I\'m not sure about what you want from me...');
}
answerHandler = function(resp) {
var hasBeenAnswered;
hasBeenAnswered = false;
postAnswer(msg)(function() {
if (!hasBeenAnswered) {
resp.write(msg);
resp.end();
return hasBeenAnswered = true;
}
});
return {
answerSuccess: function(msg) {
if (!hasBeenAnswered) {
return postAnswer(msg);
}
},
answerError: function(msg) {
if (!hasBeenAnswered) {
resp.writeHead(400, {
"Content-Type": "text/plain"
});
}
return postAnswer(msg);
},
isAnswered: function() {
return hasBeenAnswered;
}
};
};
onAdminCommand = function(req, response) {
var q;
q = req.query;
log.print('HL', 'Received admin request: ' + req.originalUrl);
if (q.cmd) {
return fAdminCommands(q, answerHandler(response));
} else {
return answerError(response, 'I\'m not sure about what you want from me...');
}
};
/*
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
*/
fAdminCommands = function(args, answHandler) {
var fAnsw, _name;
if (args && args.cmd) {
if (typeof adminCmds[_name = args.cmd] === "function") {
adminCmds[_name](args, answHandler);
}
} else {
log.print('RS', 'No command in request');
}
/*
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
*/
fAnsw = function(ah) {
/*
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
*/
return function() {
if (!ah.isAnswered()) {
return ah.answerError('Not handled...');
}
};
};
/*
Delayed function call of the anonymous function that checks the answer handler
*/
return setTimeout(fAnsw(answHandler), 2000);
};
}).call(this);

View file

@ -21,10 +21,11 @@ exports = module.exports = function(args) {
return module.exports;
};
exports.addHandlers = function(db_link, fLoadAction, fLoadRule) {
exports.addDBLink = function(db_link) {
db = db_link;
funcLoadAction = fLoadAction;
funcLoadRule = fLoadRule;
//TODO Remove fLoadAction and fLoadRule and replace them with user commands
// funcLoadAction = fLoadAction;
// funcLoadRule = fLoadRule;
};
/*
@ -34,8 +35,8 @@ exports.addHandlers = function(db_link, fLoadAction, fLoadRule) {
exports.loadRulesFromFS = function(args, answHandler) {
if(!args) args = {};
if(!args.name) args.name = 'rules';
if(!funcLoadRule) log.error('ML', 'no rule loader function available');
else {
// if(!funcLoadRule) log.error('ML', 'no rule loader function available');
// else {
fs.readFile(path.resolve(__dirname, '..', 'rules', args.name + '.json'), 'utf8', function (err, data) {
if (err) {
log.error('ML', 'Loading rules file: ' + args.name + '.json');
@ -47,14 +48,14 @@ exports.loadRulesFromFS = function(args, answHandler) {
for(var i = 0; i < arr.length; i++) {
txt += arr[i].id + ', ';
db.storeRule(arr[i].id, JSON.stringify(arr[i]));
funcLoadRule(arr[i]);
// funcLoadRule(arr[i]);
}
answHandler.answerSuccess('Yep, loaded rules: ' + txt);
} catch (e) {
log.error('ML', 'rules file was corrupt! (' + args.name + '.json)');
}
});
}
// }
};
/*
@ -71,7 +72,7 @@ exports.loadRulesFromFS = function(args, answHandler) {
*/
function loadActionCallback(name, data, mod, auth) {
db.storeActionModule(name, data); // store module in db
funcLoadAction(name, mod); // hand back compiled module
// funcLoadAction(name, mod); // hand back compiled module
if(auth) db.storeActionModuleAuth(name, auth);
}

View file

@ -2,22 +2,33 @@ var path = require('path'),
qs = require('querystring'),
log = require('./logging'),
db = require('./db_interface'),
adminHandler;
mm = require('./module_manager'),
// ### Prepare the admin command handlers that are issued via HTTP requests. ###
objAdminCmds = {
'loadrules': mm.loadRulesFromFS,
'loadaction': mm.loadActionModuleFromFS,
'loadactions': mm.loadActionModulesFromFS,
'loadevent': mm.loadEventModuleFromFS,
'loadevents': mm.loadEventModulesFromFS
};
exports = module.exports = function(args) {
args = args || {};
log(args);
db(args);
mm(args);
mm.addDBLink(db);
var users = JSON.parse(require('fs').readFileSync(path.resolve(__dirname, '..', 'config', 'users.json')));
for(var name in users) {
db.storeUser(users[name]);
}
log.print('RS', 'Initialzing module manager');
return module.exports;
};
exports.addHandler = function(adminHandl) {
adminHandler = adminHandl;
exports.addHandler = function(fShutdown) {
objAdminCmds.shutdown = fShutdown;
};
exports.handleRequest = function(req, resp) {
@ -77,12 +88,95 @@ function answerHandler(r) {
};
};
//TODO add loadUsers as directive to admin commands
exports.loadUsers = function () {
var users = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'users.json')));
for(var name in users) {
db.storeUser(users[name]);
}
};
function onAdminCommand(request, response) {
var q = request.query;
log.print('HL', 'Received admin request: ' + request.originalUrl);
if(q.cmd) {
adminHandler(q, answerHandler(response));
fAdminCommands(q, answerHandler(response));
// answerSuccess(response, 'Thank you, we try our best!');
} else answerError(response, 'I\'m not sure about what you want from me...');
}
/*
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
*/
function fAdminCommands(args, answHandler) {
var fAnsw, _name;
if (args && args.cmd) {
if (typeof objAdminCmds[_name = args.cmd] === "function") {
objAdminCmds[_name](args, answHandler);
}
} else {
log.print('RS', 'No command in request');
}
/*
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
*/
fAnsw = function(ah) {
/*
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
*/
return function() {
if (!ah.isAnswered()) {
return ah.answerError('Not handled...');
}
};
};
/*
Delayed function call of the anonymous function that checks the answer handler
*/
return setTimeout(fAnsw(answHandler), 2000);
};
/*
###
admin commands handler receives all command arguments and an answerHandler
object that eases response handling to the HTTP request issuer.
@private fAdminCommands( *args, answHandler* )
###
fAdminCommands = (args, answHandler) ->
if args and args.cmd
adminCmds[args.cmd]? args, answHandler
else
log.print 'RS', 'No command in request'
###
The fAnsw function receives an answerHandler object as an argument when called
and returns an anonymous function
###
fAnsw = (ah) ->
###
The anonymous function checks whether the answerHandler was already used to
issue an answer, if no answer was provided we answer with an error message
###
() ->
if not ah.isAnswered()
ah.answerError 'Not handled...'
###
Delayed function call of the anonymous function that checks the answer handler
###
setTimeout fAnsw(answHandler), 2000
*/