We are dirty again, replaced all indents with tabs, tried to fix all the lil things showing up as we test rule upload

This commit is contained in:
Dominic Bosch 2014-04-16 17:42:56 +02:00
parent f744d8d5f1
commit 18b36b84ac
45 changed files with 3771 additions and 3562 deletions

View file

@ -31,10 +31,10 @@ Initializes the Components Manager and constructs a new Event Emitter.
@param {Object} args
###
exports = module.exports = ( args ) =>
@log = args.logger
db args
dynmod args
module.exports
@log = args.logger
db args
dynmod args
module.exports
###
@ -45,35 +45,35 @@ Add an event handler (eh) that listens for rules.
###
exports.addRuleListener = ( eh ) =>
eventEmitter.addListener 'rule', eh
eventEmitter.addListener 'rule', eh
# Fetch all active rules per user
db.getAllActivatedRuleIdsPerUser ( err, objUsers ) ->
# Fetch all active rules per user
db.getAllActivatedRuleIdsPerUser ( err, objUsers ) ->
# Go through all rules of each user
fGoThroughUsers = ( user, rules ) ->
# Go through all rules of each user
fGoThroughUsers = ( user, rules ) ->
# Fetch the rules object for each rule in each user
fFetchRule = ( userName ) ->
( rule ) ->
db.getRule rule, ( err, strRule ) =>
try
oRule = JSON.parse strRule
db.resetLog userName, oRule.id
db.appendLog userName, oRule.id, "INIT", "Rule '#{ oRule.id }' initialized"
# Fetch the rules object for each rule in each user
fFetchRule = ( userName ) ->
( rule ) ->
db.getRule rule, ( err, strRule ) =>
try
oRule = JSON.parse strRule
db.resetLog userName, oRule.id
db.appendLog userName, oRule.id, "INIT", "Rule '#{ oRule.id }' initialized"
eventEmitter.emit 'rule',
event: 'init'
user: userName
rule: oRule
catch err
@log.warn "CM | There's an invalid rule in the system: #{ strRule }"
eventEmitter.emit 'rule',
event: 'init'
user: userName
rule: oRule
catch err
@log.warn "CM | There's an invalid rule in the system: #{ strRule }"
# Go through all rules for each user
fFetchRule( user ) rule for rule in rules
# Go through each user
fGoThroughUsers user, rules for user, rules of objUsers
# Go through all rules for each user
fFetchRule( user ) rule for rule in rules
# Go through each user
fGoThroughUsers user, rules for user, rules of objUsers
###
Processes a user request coming through the request-handler.
@ -81,30 +81,30 @@ Processes a user request coming through the request-handler.
- `user` is the user object as it comes from the DB.
- `oReq` is the request object that contains:
- `command` as a string
- `payload` an optional stringified JSON object
- `command` as a string
- `payload` an optional stringified JSON object
The callback function `callback( obj )` will receive an object
containing the HTTP response code and a corresponding message.
@public processRequest ( *user, oReq, callback* )
###
exports.processRequest = ( user, oReq, callback ) ->
if not oReq.payload
oReq.payload = '{}'
try
dat = JSON.parse oReq.payload
catch err
return callback
code: 404
message: 'You had a strange payload in your request!'
if commandFunctions[oReq.command]
if not oReq.payload
oReq.payload = '{}'
try
dat = JSON.parse oReq.payload
catch err
return callback
code: 404
message: 'You had a strange payload in your request!'
if commandFunctions[oReq.command]
# If the command function was registered we invoke it
commandFunctions[oReq.command] user, dat, callback
else
callback
code: 404
message: 'What do you want from me?'
# If the command function was registered we invoke it
commandFunctions[oReq.command] user, dat, callback
else
callback
code: 404
message: 'What do you want from me?'
###
Checks whether all required parameters are present in the payload.
@ -114,13 +114,13 @@ Checks whether all required parameters are present in the payload.
@param {Object} oPayload
###
hasRequiredParams = ( arrParams, oPayload ) ->
answ =
code: 400
message: "Your request didn't contain all necessary fields! Requires: #{ arrParams.join() }"
return answ for param in arrParams when not oPayload[param]
answ.code = 200
answ.message = 'All required properties found'
answ
answ =
code: 400
message: "Your request didn't contain all necessary fields! Requires: #{ arrParams.join() }"
return answ for param in arrParams when not oPayload[param]
answ.code = 200
answ.message = 'All required properties found'
answ
###
Fetches all available modules and return them together with the available functions.
@ -132,211 +132,225 @@ Fetches all available modules and return them together with the available functi
@param {function} callback
###
getModules = ( user, oPayload, dbMod, callback ) ->
dbMod.getAvailableModuleIds user.username, ( err, arrNames ) ->
oRes = {}
answReq = () ->
callback
code: 200
message: JSON.stringify oRes
sem = arrNames.length
if sem is 0
answReq()
else
fGetFunctions = ( id ) =>
dbMod.getModule id, ( err, oModule ) =>
if oModule
oRes[id] = JSON.parse oModule.functions
if --sem is 0
answReq()
fGetFunctions id for id in arrNames
dbMod.getAvailableModuleIds user.username, ( err, arrNames ) ->
oRes = {}
answReq = () ->
callback
code: 200
message: JSON.stringify oRes
sem = arrNames.length
if sem is 0
answReq()
else
fGetFunctions = ( id ) =>
dbMod.getModule id, ( err, oModule ) =>
if oModule
oRes[id] = JSON.parse oModule.functions
if --sem is 0
answReq()
fGetFunctions id for id in arrNames
getModuleParams = ( user, oPayload, dbMod, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
dbMod.getModuleParams oPayload.id, ( err, oPayload ) ->
answ.message = oPayload
callback answ
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
dbMod.getModuleParams oPayload.id, ( err, oPayload ) ->
answ.message = oPayload
callback answ
forgeModule = ( user, oPayload, dbMod, callback ) =>
answ = hasRequiredParams [ 'id', 'params', 'lang', 'data' ], oPayload
if answ.code isnt 200
callback answ
else
i = 0
dbMod.getModule oPayload.id, ( err, mod ) =>
if mod
answ.code = 409
answ.message = 'Module name already existing: ' + oPayload.id
callback answ
else
src = oPayload.data
dynmod.compileString src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, ( cm ) =>
answ = cm.answ
if answ.code is 200
funcs = []
funcs.push name for name, id of cm.module
@log.info "CM | Storing new module with functions #{ funcs.join( ', ' ) }"
answ.message =
" Module #{ oPayload.id } successfully stored! Found following function(s): #{ funcs }"
oPayload.functions = JSON.stringify funcs
oPayload.functionParameters = JSON.stringify cm.funcParams
dbMod.storeModule user.username, oPayload
if oPayload.public is 'true'
dbMod.publish oPayload.id
callback answ
answ = hasRequiredParams [ 'id', 'params', 'lang', 'data' ], oPayload
if answ.code isnt 200
callback answ
else
i = 0
dbMod.getModule oPayload.id, ( err, mod ) =>
if mod
answ.code = 409
answ.message = 'Module name already existing: ' + oPayload.id
callback answ
else
src = oPayload.data
dynmod.compileString src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, ( cm ) =>
console.log cm
answ = cm.answ
if answ.code is 200
funcs = []
funcs.push name for name, id of cm.module
@log.info "CM | Storing new module with functions #{ funcs.join( ', ' ) }"
answ.message =
" Module #{ oPayload.id } successfully stored! Found following function(s): #{ funcs }"
oPayload.functions = JSON.stringify funcs
oPayload.functionArgs = JSON.stringify cm.funcParams
dbMod.storeModule user.username, oPayload
if oPayload.public is 'true'
dbMod.publish oPayload.id
callback answ
commandFunctions =
get_public_key: ( user, oPayload, callback ) ->
callback
code: 200
message: dynmod.getPublicKey()
get_public_key: ( user, oPayload, callback ) ->
callback
code: 200
message: dynmod.getPublicKey()
# EVENT POLLERS
# -------------
get_event_pollers: ( user, oPayload, callback ) ->
getModules user, oPayload, db.eventPollers, callback
get_full_event_poller: ( user, oPayload, callback ) ->
db.eventPollers.getModule oPayload.id, ( err, obj ) ->
callback
code: 200
message: JSON.stringify obj
get_event_poller_params: ( user, oPayload, callback ) ->
getModuleParams user, oPayload, db.eventPollers, callback
get_event_pollers: ( user, oPayload, callback ) ->
getModules user, oPayload, db.eventPollers, callback
get_full_event_poller: ( user, oPayload, callback ) ->
db.eventPollers.getModule oPayload.id, ( err, obj ) ->
callback
code: 200
message: JSON.stringify obj
get_event_poller_params: ( user, oPayload, callback ) ->
getModuleParams user, oPayload, db.eventPollers, callback
forge_event_poller: ( user, oPayload, callback ) ->
forgeModule user, oPayload, db.eventPollers, callback
forge_event_poller: ( user, oPayload, callback ) ->
forgeModule user, oPayload, db.eventPollers, callback
delete_event_poller: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.eventPollers.deleteModule oPayload.id
callback
code: 200
message: 'OK!'
delete_event_poller: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.eventPollers.deleteModule oPayload.id
callback
code: 200
message: 'OK!'
# ACTION INVOKERS
# ---------------
get_action_invokers: ( user, oPayload, callback ) ->
getModules user, oPayload, db.actionInvokers, callback
get_full_action_invoker: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.getModule oPayload.id, ( err, obj ) ->
callback
code: 200
message: JSON.stringify obj
get_action_invokers: ( user, oPayload, callback ) ->
getModules user, oPayload, db.actionInvokers, callback
get_full_action_invoker: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.getModule oPayload.id, ( err, obj ) ->
callback
code: 200
message: JSON.stringify obj
get_action_invoker_params: ( user, oPayload, callback ) ->
getModuleParams user, oPayload, db.actionInvokers, callback
get_action_invoker_params: ( user, oPayload, callback ) ->
getModuleParams user, oPayload, db.actionInvokers, callback
get_action_invoker_function_params: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.getModuleField oPayload.id, 'functionParameters', ( err, obj ) ->
callback
code: 200
message: obj
forge_action_invoker: ( user, oPayload, callback ) ->
forgeModule user, oPayload, db.actionInvokers, callback
get_action_invoker_function_params: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.getModuleField oPayload.id, 'functionArgs', ( err, obj ) ->
callback
code: 200
message: obj
forge_action_invoker: ( user, oPayload, callback ) ->
forgeModule user, oPayload, db.actionInvokers, callback
delete_action_invoker: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.deleteModule oPayload.id
callback
code: 200
message: 'OK!'
delete_action_invoker: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.actionInvokers.deleteModule oPayload.id
callback
code: 200
message: 'OK!'
# RULES
# -----
get_rules: ( user, oPayload, callback ) ->
db.getUserLinkedRules user.username, ( err, obj ) ->
callback
code: 200
message: obj
get_rules: ( user, oPayload, callback ) ->
db.getUserLinkedRules user.username, ( err, obj ) ->
callback
code: 200
message: obj
get_rule_log: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.getLog user.username, oPayload.id, ( err, obj ) ->
callback
code: 200
message: obj
get_rule_log: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.getLog user.username, oPayload.id, ( err, obj ) ->
callback
code: 200
message: obj
# A rule needs to be in following format:
# - id
# - event
# - conditions
# - actions
forge_rule: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id', 'event', 'conditions', 'actions' ], oPayload
if answ.code isnt 200
callback answ
else
db.getRule oPayload.id, ( err, oExisting ) ->
if oExisting isnt null
answ =
code: 409
message: 'Rule name already existing!'
else
rule =
id: oPayload.id
event: oPayload.event
conditions: oPayload.conditions
actions: oPayload.actions
strRule = JSON.stringify rule
db.storeRule rule.id, strRule
db.linkRule rule.id, user.username
db.activateRule rule.id, user.username
if oPayload.event_params
epModId = rule.event.split( ' -> ' )[0]
db.eventPollers.storeUserParams epModId, user.username, oPayload.event_params
oParams = oPayload.action_params
db.actionInvokers.storeUserParams id, user.username, JSON.stringify params for id, params of oParams
oParams = oPayload.action_functions
for id, params of oParams
arr = id.split ' -> '
db.actionInvokers.storeUserArguments arr[ 0 ], arr[ 1 ], user.username, JSON.stringify params
db.resetLog user.username, rule.id
db.appendLog user.username, rule.id, "INIT", "Rule '#{ rule.id }' initialized"
eventEmitter.emit 'rule',
event: 'new'
user: user.username
rule: rule
answ =
code: 200
message: "Rule '#{ rule.id }' stored and activated!"
callback answ
# A rule needs to be in following format:
# - id
# - event
# - conditions
# - actions
forge_rule: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id', 'event', 'conditions', 'actions' ], oPayload
if answ.code isnt 200
callback answ
else
db.getRule oPayload.id, ( err, oExisting ) ->
if oExisting isnt null
answ =
code: 409
message: 'Rule name already existing!'
else
# This is how a rule is stored in the database
rule =
id: oPayload.id
event: oPayload.event
event_interval: oPayload.event_interval
conditions: oPayload.conditions
actions: oPayload.actions
strRule = JSON.stringify rule
# store the rule
db.storeRule rule.id, strRule
# link the rule to the user
db.linkRule rule.id, user.username
# activate the rule
db.activateRule rule.id, user.username
# if event module parameters were send, store them
if oPayload.event_params
epModId = rule.event.split( ' -> ' )[0]
db.eventPollers.storeUserParams epModId, user.username, oPayload.event_params
# if action module params were send, store them
oParams = oPayload.action_params
db.actionInvokers.storeUserParams id, user.username, JSON.stringify params for id, params of oParams
oParams = oPayload.action_functions
# if action function arguments were send, store them
for id, params of oParams
arr = id.split ' -> '
db.actionInvokers.storeUserArguments arr[ 0 ], arr[ 1 ], user.username, JSON.stringify params
# Initialize the rule log
db.resetLog user.username, rule.id
db.appendLog user.username, rule.id, "INIT", "Rule '#{ rule.id }' initialized"
# Inform everbody about the new rule
eventEmitter.emit 'rule',
event: 'new'
user: user.username
rule: rule
answ =
code: 200
message: "Rule '#{ rule.id }' stored and activated!"
callback answ
delete_rule: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.deleteRule oPayload.id
eventEmitter.emit 'rule',
event: 'del'
user: user.username
rule: null
ruleId: oPayload.id
callback
code: 200
message: 'OK!'
delete_rule: ( user, oPayload, callback ) ->
answ = hasRequiredParams [ 'id' ], oPayload
if answ.code isnt 200
callback answ
else
db.deleteRule oPayload.id
eventEmitter.emit 'rule',
event: 'del'
user: user.username
rule: null
ruleId: oPayload.id
callback
code: 200
message: 'OK!'

View file

@ -24,14 +24,14 @@ be generated) and configPath for a custom configuration file path.
@param {Object} args
###
exports = module.exports = ( args ) =>
args = args ? {}
if args.nolog
@nolog = true
if args.configPath
loadConfigFile args.configPath
else
loadConfigFile path.join 'config', 'system.json'
module.exports
args = args ? {}
if args.nolog
@nolog = true
if args.configPath
loadConfigFile args.configPath
else
loadConfigFile path.join 'config', 'system.json'
module.exports
###
Tries to load a configuration file from the path relative to this module's parent folder.
@ -41,26 +41,26 @@ Reads the config file synchronously from the file system and try to parse it.
@param {String} configPath
###
loadConfigFile = ( configPath ) =>
@config = null
confProperties = [
'log'
'http-port'
'db-port'
]
try
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', configPath
@isReady = true
for prop in confProperties
if !@config[prop]
@isReady = false
if not @isReady and not @nolog
console.error "Missing property in config file, requires:\n" +
" - #{ confProperties.join "\n - " }"
catch e
@isReady = false
if not @nolog
console.error "Failed loading config file: #{ e.message }"
@config = null
confProperties = [
'log'
'http-port'
'db-port'
]
try
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', configPath
@isReady = true
for prop in confProperties
if !@config[prop]
@isReady = false
if not @isReady and not @nolog
console.error "Missing property in config file, requires:\n" +
" - #{ confProperties.join "\n - " }"
catch e
@isReady = false
if not @nolog
console.error "Failed loading config file: #{ e.message }"
###
Fetch a property from the configuration
@ -68,7 +68,7 @@ Fetch a property from the configuration
@private fetchProp( *prop* )
@param {String} prop
###
fetchProp = ( prop ) => @config?[prop]
exports.fetchProp = ( prop ) => @config?[prop]
###
***Returns*** true if the config file is ready, else false
@ -82,25 +82,25 @@ exports.isReady = => @isReady
@public getHttpPort()
###
exports.getHttpPort = -> fetchProp 'http-port'
exports.getHttpPort = -> exports.fetchProp 'http-port'
###
***Returns*** the DB port*
@public getDBPort()
###
exports.getDbPort = -> fetchProp 'db-port'
exports.getDbPort = -> exports.fetchProp 'db-port'
###
***Returns*** the log conf object
@public getLogConf()
###
exports.getLogConf = -> fetchProp 'log'
exports.getLogConf = -> exports.fetchProp 'log'
###
***Returns*** the crypto key
@public getCryptoKey()
###
exports.getKeygenPassphrase = -> fetchProp 'keygen-passphrase'
exports.getKeygenPassphrase = -> exports.fetchProp 'keygen-passphrase'

View file

@ -18,10 +18,13 @@ needle = require 'needle'
request = require 'request'
# - External Modules: [coffee-script](http://coffeescript.org/),
# [cryptico](https://github.com/wwwtyro/cryptico)
# [cryptico](https://github.com/wwwtyro/cryptico),
# [crypto-js](https://www.npmjs.org/package/crypto-js) and
# [import-io](https://www.npmjs.org/package/import-io)
cs = require 'coffee-script'
cryptico = require 'my-cryptico'
cryptoJS = require 'crypto-js'
importio = require( 'import-io' ).client
@ -33,34 +36,33 @@ Initializes the dynamic module handler.
@param {Object} args
###
exports = module.exports = ( args ) =>
@log = args.logger
# FIXME this can't come through the arguments
if not @strPublicKey and args[ 'keygen' ]
db args
passPhrase = args[ 'keygen' ]
numBits = 1024
@oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
@strPublicKey = cryptico.publicKeyString @oPrivateRSAkey
@log.info "DM | Public Key generated: #{ @strPublicKey }"
@log = args.logger
# FIXME this can't come through the arguments
if not @strPublicKey and args[ 'keygen' ]
db args
passPhrase = args[ 'keygen' ]
numBits = 1024
@oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
@strPublicKey = cryptico.publicKeyString @oPrivateRSAkey
@log.info "DM | Public Key generated: #{ @strPublicKey }"
module.exports
module.exports
exports.getPublicKey = () =>
@strPublicKey
@strPublicKey
logFunction = ( uId, rId, mId ) ->
( msg ) ->
db.appendLog uId, rId, mId, msg
( msg ) ->
db.appendLog uId, rId, mId, msg
regexpComments = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
getFunctionParamNames = ( fName, func, oFuncs ) ->
fnStr = func.toString().replace regexpComments, ''
result = fnStr.slice( fnStr.indexOf( '(' ) + 1, fnStr.indexOf( ')' ) ).match /([^\s,]+)/g
if not result
result = []
oFuncs[fName] = result
fnStr = func.toString().replace regexpComments, ''
result = fnStr.slice( fnStr.indexOf( '(' ) + 1, fnStr.indexOf( ')' ) ).match /([^\s,]+)/g
if not result
result = []
oFuncs[fName] = result
###
Try to run a JS module from a string, together with the
@ -74,86 +76,101 @@ compile it first into JS.
@param {String} lang
###
exports.compileString = ( src, userId, ruleId, modId, lang, dbMod, cb ) =>
answ =
code: 200
message: 'Successfully compiled'
if lang is 'CoffeeScript'
try
@log.info "DM | Compiling module '#{ modId }' for user '#{ userId }'"
src = cs.compile src
catch err
cb
code: 400
message: 'Compilation of CoffeeScript failed at line ' +
err.location.first_line
return
if lang is 'CoffeeScript'
try
src = cs.compile src
catch err
answ.code = 400
answ.message = 'Compilation of CoffeeScript failed at line ' +
err.location.first_line
fTryToLoad = ( params ) =>
if params
try
oDecrypted = cryptico.decrypt params, @oPrivateRSAkey
params = JSON.parse oDecrypted.plaintext
catch err
@log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }"
@log.warn err
params = {}
else
params = {}
@log.info "DM | Trying to fetch user specific module '#{ modId }' paramters for user '#{ userId }'"
# dbMod is only attached if the module really gets loaded and needs to fetch user information from the database
if dbMod
dbMod.getUserParams modId, userId, ( err, obj ) =>
try
oDecrypted = cryptico.decrypt obj, @oPrivateRSAkey
obj = JSON.parse oDecrypted.plaintext
@log.warn "DM | Loaded user defined params for #{ userId }, #{ ruleId }, #{ modId }"
catch err
@log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }"
@log.warn err
fTryToLoadModule userId, ruleId, modId, src, dbMod, obj, cb
else
fTryToLoadModule userId, ruleId, modId, src, dbMod, null, cb
logFunc = logFunction userId, ruleId, modId
sandbox =
id: userId + '.' + modId + '.vm'
params: params
needle: needle
request: request
cryptoJS: cryptoJS
log: logFunc
debug: console.log
exports: {}
fTryToLoadModule = ( userId, ruleId, modId, src, dbMod, params, cb ) =>
if not params
params = {}
#TODO child_process to run module!
#Define max runtime per loop as 10 seconds, after that the child will be killed
#it can still be active after that if there was a timing function or a callback used...
#kill the child each time? how to determine whether there's still a token in the module?
try
vm.runInNewContext src, sandbox, sandbox.id
# TODO We should investigate memory usage and garbage collection (global.gc())?
# Start Node with the flags nouse_idle_notification and expose_gc, and then when you want to run the GC, just call global.gc().
catch err
answ.code = 400
msg = err.message
if not msg
msg = 'Try to run the script locally to track the error! Sadly we cannot provide the line number'
answ.message = 'Loading Module failed: ' + msg
oFuncParams = {}
for fName, func of sandbox.exports
getFunctionParamNames fName, func, oFuncParams
answ =
code: 200
message: 'Successfully compiled'
if dbMod
oFuncArgs = {}
console.log 'oFuncParams'
console.log oFuncParams
@log.info "DM | Running module '#{ modId }' for user '#{ userId }'"
# The function used to provide logging mechanisms on a per rule basis
logFunc = logFunction userId, ruleId, modId
# The sandbox contains the objects that are accessible to the user. Eventually they need to be required from a vm themselves
sandbox =
id: "#{ userId }.#{ ruleId }.#{ modId }.vm"
params: params
needle: needle
importio: importio
request: request
cryptoJS: cryptoJS
log: logFunc
debug: console.log
exports: {}
for func of oFuncParams
console.log 'fetching ' + func
console.log typeof func
dbMod.getUserArguments modId, func, userId, ( err, obj ) =>
console.log err, obj
try
oDecrypted = cryptico.decrypt obj, @oPrivateRSAkey
oFuncArgs[ func ] = JSON.parse oDecrypted.plaintext
catch err
@log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }"
@log.warn err
cb
answ: answ
module: sandbox.exports
funcParams: oFuncParams
funcArgs: oFuncArgs
logger: sandbox.log
#TODO child_process to run module!
#Define max runtime per function call as 10 seconds, after that the child will be killed
#it can still be active after that if there was a timing function or a callback used...
#kill the child each time? how to determine whether there's still a token in the module?
try
# Finally the module is run in a
vm.runInNewContext src, sandbox, sandbox.id
# TODO We should investigate memory usage and garbage collection (global.gc())?
# Start Node with the flags nouse_idle_notification and expose_gc, and then when you want to run the GC, just call global.gc().
catch err
answ.code = 400
msg = err.message
if not msg
msg = 'Try to run the script locally to track the error! Sadly we cannot provide the line number'
answ.message = 'Loading Module failed: ' + msg
if dbMod
dbMod.getUserParams modId, userId, ( err, obj ) ->
fTryToLoad obj
else
fTryToLoad null
@log.info "DM | Module '#{ modId }' ran successfully for user '#{ userId }' in rule '#{ ruleId }'"
oFuncParams = {}
oFuncArgs = {}
for fName, func of sandbox.exports
getFunctionParamNames fName, func, oFuncParams
if dbMod
oFuncArgs = {}
console.log 'oFuncParams'
console.log oFuncParams
for func of oFuncParams
console.log 'fetching ' + func
console.log typeof func
dbMod.getUserArguments modId, func, userId, ( err, obj ) =>
console.log err, obj
try
oDecrypted = cryptico.decrypt obj, @oPrivateRSAkey
oFuncArgs[ func ] = JSON.parse oDecrypted.plaintext
catch err
@log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }"
@log.warn err
console.log 'answering compile request string'
console.log cb
cb
answ: answ
module: sandbox.exports
funcParams: oFuncParams
funcArgs: oFuncArgs
logger: sandbox.log

View file

@ -23,21 +23,21 @@ jsonQuery = require 'js-select'
This is ging to have a structure like:
An object of users with their active rules and the required action modules
"user-1":
"rule-1":
"rule": oRule-1
"actions":
"action-1": oAction-1
"action-2": oAction-2
"rule-2":
"rule": oRule-2
"actions":
"action-1": oAction-1
"user-2":
"rule-3":
"rule": oRule-3
"actions":
"action-3": oAction-3
"user-1":
"rule-1":
"rule": oRule-1
"actions":
"action-1": oAction-1
"action-2": oAction-2
"rule-2":
"rule": oRule-2
"actions":
"action-1": oAction-1
"user-2":
"rule-3":
"rule": oRule-3
"actions":
"action-3": oAction-3
###
#TODO how often do we allow rules to be processed?
@ -55,12 +55,12 @@ Initializes the Engine and starts polling the event queue for new events.
@param {Object} args
###
exports = module.exports = ( args ) =>
if not isRunning
@log = args.logger
db args
dynmod args
setTimeout exports.startEngine, 10 # Very important, this forks a token for the poll task
module.exports
if not isRunning
@log = args.logger
db args
dynmod args
setTimeout exports.startEngine, 10 # Very important, this forks a token for the poll task
module.exports
###
@ -72,13 +72,13 @@ modules are loaded correctly
#TODO we should change this to functions returning true or false rather than returning
#the whole list
exports.getListUserRules = () ->
listUserRules
listUserRules
# We need this so we can shut it down after the module unit tests
exports.startEngine = () ->
if not isRunning
isRunning = true
pollQueue()
if not isRunning
isRunning = true
pollQueue()
###
An event associated to rules happened and is captured here. Such events
@ -88,23 +88,23 @@ are basically CRUD on rules.
@param {Object} evt
###
exports.internalEvent = ( evt ) =>
if not listUserRules[evt.user] and evt.event isnt 'del'
listUserRules[evt.user] = {}
if not listUserRules[evt.user] and evt.event isnt 'del'
listUserRules[evt.user] = {}
oUser = listUserRules[evt.user]
oRule = evt.rule
if evt.event is 'new' or ( evt.event is 'init' and not oUser[oRule.id] )
oUser[oRule.id] =
rule: oRule
actions: {}
updateActionModules oRule.id
oUser = listUserRules[evt.user]
oRule = evt.rule
if evt.event is 'new' or ( evt.event is 'init' and not oUser[oRule.id] )
oUser[oRule.id] =
rule: oRule
actions: {}
updateActionModules oRule.id
if evt.event is 'del' and oUser
delete oUser[evt.ruleId]
if evt.event is 'del' and oUser
delete oUser[evt.ruleId]
# If a user is empty after all the updates above, we remove her from the list
if JSON.stringify( oUser ) is "{}"
delete listUserRules[evt.user]
# If a user is empty after all the updates above, we remove her from the list
if JSON.stringify( oUser ) is "{}"
delete listUserRules[evt.user]
@ -115,65 +115,67 @@ invoker modules are loaded, updated or deleted.
@private updateActionModules ( *updatedRuleId* )
@param {Object} updatedRuleId
###
updateActionModules = ( updatedRuleId ) ->
# Remove all action invoker modules that are not required anymore
fRemoveNotRequired = ( oUser ) ->
updateActionModules = ( updatedRuleId ) =>
# Remove all action invoker modules that are not required anymore
fRemoveNotRequired = ( oUser ) ->
# Check whether the action is still existing in the rule
fRequired = ( actionName ) ->
for action in oUser[updatedRuleId].rule.actions
# Since the event is in the format 'module -> function' we need to split the string
if (action.split ' -> ')[0] is actionName
return true
false
# Check whether the action is still existing in the rule
fRequired = ( actionName ) ->
for action in oUser[updatedRuleId].rule.actions
# Since the event is in the format 'module -> function' we need to split the string
if (action.split ' -> ')[0] is actionName
return true
false
# Go thorugh all loaded action modules and check whether the action is still required
for action of oUser[updatedRuleId].rule.actions
delete oUser[updatedRuleId].actions[action] if not fRequired action
# Go thorugh all loaded action modules and check whether the action is still required
for action of oUser[updatedRuleId].rule.actions
delete oUser[updatedRuleId].actions[action] if not fRequired action
fRemoveNotRequired oUser for name, oUser of listUserRules
fRemoveNotRequired oUser for name, oUser of listUserRules
# Add action invoker modules that are not yet loaded
fAddRequired = ( userName, oUser ) ->
# Add action invoker modules that are not yet loaded
fAddRequired = ( userName, oUser ) =>
# Check whether the action is existing in a rule and load if not
fCheckRules = ( oMyRule ) ->
# Check whether the action is existing in a rule and load if not
fCheckRules = ( oMyRule ) =>
# Load the action invoker module if it was part of the updated rule or if it's new
fAddIfNewOrNotExisting = ( actionName ) ->
moduleName = (actionName.split ' -> ')[0]
if not oMyRule.actions[moduleName] or oMyRule.rule.id is updatedRuleId
db.actionInvokers.getModule moduleName, ( err, obj ) ->
# we compile the module and pass:
dynmod.compileString obj.data, # code
userName, # userId
oMyRule.rule.id, # ruleId
moduleName, # moduleId
obj.lang, # script language
db.actionInvokers, # the DB interface
( result ) ->
if not result.answ is 200
@log.error "EN | Compilation of code failed! #{ userName },
#{ oMyRule.rule.id }, #{ moduleName }"
oMyRule.actions[moduleName] = result.module
# Load the action invoker module if it was part of the updated rule or if it's new
fAddIfNewOrNotExisting = ( actionName ) =>
moduleName = (actionName.split ' -> ')[0]
if not oMyRule.actions[moduleName] or oMyRule.rule.id is updatedRuleId
db.actionInvokers.getModule moduleName, ( err, obj ) =>
if obj
# we compile the module and pass:
dynmod.compileString obj.data, # code
userName, # userId
oMyRule.rule.id, # ruleId
moduleName, # moduleId
obj.lang, # script language
db.actionInvokers, # the DB interface
( result ) =>
if not result.answ is 200
@log.error "EN | Compilation of code failed! #{ userName },
#{ oMyRule.rule.id }, #{ moduleName }"
oMyRule.actions[moduleName] = result.module
else
@log.warn 'EN | #{ moduleName } not found for #{ oMyRule.rule.id }!'
fAddIfNewOrNotExisting action for action in oMyRule.rule.actions
fAddIfNewOrNotExisting action for action in oMyRule.rule.actions
# Go thorugh all rules and check whether the action is still required
fCheckRules oRl for nmRl, oRl of oUser
# Go thorugh all rules and check whether the action is still required
fCheckRules oRl for nmRl, oRl of oUser
# load all required modules for all users
fAddRequired userName, oUser for userName, oUser of listUserRules
# load all required modules for all users
fAddRequired userName, oUser for userName, oUser of listUserRules
semaphore = 0
numExecutingFunctions = 1
pollQueue = () ->
if isRunning
db.popEvent ( err, obj ) ->
if not err and obj
processEvent obj
semaphore--
setTimeout pollQueue, 20 * semaphore #FIXME right wayx to adapt to load?
if isRunning
db.popEvent ( err, obj ) ->
if not err and obj
processEvent obj
setTimeout pollQueue, 20 * numExecutingFunctions #FIXME right way to adapt to load?
###
Checks whether all conditions of the rule are met by the event.
@ -183,13 +185,12 @@ Checks whether all conditions of the rule are met by the event.
@param {Object} rule
###
validConditions = ( evt, rule ) ->
if rule.conditions.length is 0
return true
for prop in rule.conditions
return false if jsonQuery( evt, prop ).nodes().length is 0
return true
if rule.conditions.length is 0
return true
for prop in rule.conditions
return false if jsonQuery( evt, prop ).nodes().length is 0
return true
semaphore = 0
###
Handles retrieved events.
@ -197,30 +198,32 @@ Handles retrieved events.
@param {Object} evt
###
processEvent = ( evt ) =>
fSearchAndInvokeAction = ( node, arrPath, funcName, evt, depth ) ->
if not node
@log.error "EN | Didn't find property in user rule list: " + arrPath.join ', ' + " at depth " + depth
return
if depth is arrPath.length
try
semaphore++
node[funcName] evt.payload
catch err
@log.info "EN | ERROR IN ACTION INVOKER: " + err.message
node.logger err.message
if semaphore-- % 100 is 0
@log.warn "EN | The system is producing too many tokens! Currently: #{ semaphore }"
else
fSearchAndInvokeAction node[arrPath[depth]], arrPath, funcName, evt, depth + 1
fSearchAndInvokeAction = ( node, arrPath, funcName, evt, depth ) =>
if not node
@log.error "EN | Didn't find property in user rule list: " + arrPath.join ', ' + " at depth " + depth
return
if depth is arrPath.length
try
numExecutingFunctions++
@log.info "EN | #{ funcName } executes..."
node[funcName] evt.payload
@log.info "EN | #{ funcName } finished execution"
catch err
@log.info "EN | ERROR IN ACTION INVOKER: " + err.message
node.logger err.message
if numExecutingFunctions-- % 100 is 0
@log.warn "EN | The system is producing too many tokens! Currently: #{ numExecutingFunctions }"
else
fSearchAndInvokeAction node[arrPath[depth]], arrPath, funcName, evt, depth + 1
@log.info 'EN | processing event: ' + evt.event + '(' + evt.eventid + ')'
for userName, oUser of listUserRules
for ruleName, oMyRule of oUser
if evt.event is oMyRule.rule.event and validConditions evt, oMyRule.rule
@log.info 'EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName
for action in oMyRule.rule.actions
arr = action.split ' -> '
fSearchAndInvokeAction listUserRules, [ userName, ruleName, 'actions', arr[0]], arr[1], evt, 0
@log.info 'EN | processing event: ' + evt.event + '(' + evt.eventid + ')'
for userName, oUser of listUserRules
for ruleName, oMyRule of oUser
if evt.event is oMyRule.rule.event and validConditions evt, oMyRule.rule
@log.info 'EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName
for action in oMyRule.rule.actions
arr = action.split ' -> '
fSearchAndInvokeAction listUserRules, [ userName, ruleName, 'actions', arr[0]], arr[1], evt, 0
exports.shutDown = () ->
isRunning = false
isRunning = false

View file

@ -16,13 +16,13 @@ dynmod = require './dynamic-modules'
# If we do not receive all required arguments we shut down immediately
if process.argv.length < 8
console.error 'Not all arguments have been passed!'
process.exit()
console.error 'Not all arguments have been passed!'
process.exit()
# Fetch all the command line arguments to the process to init the logger
logconf =
mode: process.argv[ 2 ]
nolog: process.argv[ 6 ]
mode: process.argv[ 2 ]
nolog: process.argv[ 6 ]
logconf[ 'io-level' ] = process.argv[ 3 ]
logconf[ 'file-level' ] = process.argv[ 4 ]
logconf[ 'file-path' ] = process.argv[ 5 ]
@ -32,8 +32,8 @@ log.info 'EP | Event Poller starts up'
# Initialize required modules (should be in cache already)
db logger: log
dynmod
logger: log
keygen: process.argv[ 7 ]
logger: log
keygen: process.argv[ 7 ]
# Initialize module local variables and
listUserModules = {}
@ -42,102 +42,111 @@ isRunning = true
# Register disconnect action. Since no standalone mode is intended
# the event poller will shut down
process.on 'disconnect', () ->
log.info 'EP | Shutting down Event Poller'
isRunning = false
# very important so the process doesnt linger on when the paren process is killed
process.exit()
log.info 'EP | Shutting down Event Poller'
isRunning = false
# very important so the process doesnt linger on when the paren process is killed
process.exit()
# If the process receives a message it is concerning the rules
process.on 'message', ( msg ) ->
# Let's split the event string to find module and function in an array
# Let's split the event string to find module and function in an array
# A initialization notification or a new rule
if msg.event is 'new' or msg.event is 'init'
fLoadModule msg
# We fetch the module also if the rule was updated
# A initialization notification or a new rule
if msg.event is 'new' or msg.event is 'init'
fLoadModule msg
# We fetch the module also if the rule was updated
# A rule was deleted
if msg.event is 'del'
delete listUserModules[msg.user][msg.ruleId]
if JSON.stringify( listUserModules[msg.user] ) is "{}"
delete listUserModules[msg.user]
# A rule was deleted
if msg.event is 'del'
delete listUserModules[msg.user][msg.ruleId]
if JSON.stringify( listUserModules[msg.user] ) is "{}"
delete listUserModules[msg.user]
# Loads a module if required
fLoadModule = ( msg ) ->
arrName = msg.rule.event.split ' -> '
fAnonymous = () ->
db.eventPollers.getModule arrName[ 0 ], ( err, obj ) ->
if not obj
log.warn "EP | Strange... no module retrieved: #{ arrName[0] }"
else
# we compile the module and pass:
dynmod.compileString obj.data, # code
msg.user, # userId
msg.rule.id, # ruleId
arrName[0], # moduleId
obj.lang, # script language
db.eventPollers, # the DB interface
( result ) ->
if not result.answ is 200
log.error "EP | Compilation of code failed! #{ msg.user },
#{ msg.rule.id }, #{ arrName[0] }"
arrName = msg.rule.event.split ' -> '
fAnonymous = () ->
db.eventPollers.getModule arrName[ 0 ], ( err, obj ) ->
if not obj
log.warn "EP | Strange... no module retrieved: #{ arrName[0] }"
else
# we compile the module and pass:
dynmod.compileString obj.data, # code
msg.user, # userId
msg.rule.id, # ruleId
arrName[0], # moduleId
obj.lang, # script language
db.eventPollers, # the DB interface
( result ) ->
if not result.answ is 200
log.error "EP | Compilation of code failed! #{ msg.user },
#{ msg.rule.id }, #{ arrName[0] }"
# If user is not yet stored, we open a new object
if not listUserModules[msg.user]
listUserModules[msg.user] = {}
# We open up a new object for the rule it
listUserModules[msg.user][msg.rule.id] =
id: msg.rule.event
pollfunc: arrName[1]
module: result.module
logger: result.logger
# If user is not yet stored, we open a new object
if not listUserModules[msg.user]
listUserModules[msg.user] = {}
iv = msg.rule.interval * 60 * 1000
# We open up a new object for the rule it
listUserModules[msg.user][msg.rule.id] =
id: msg.rule.event
pollfunc: arrName[1]
interval: iv
module: result.module
logger: result.logger
log.info "EP | New event module loaded! #{ msg.user },
#{ msg.rule.id }, #{ arrName[0] }"
log.info "EP | New event module '#{ arrName[0] }' loaded for user #{ msg.user },
in rule #{ msg.rule.id }, polling every #{ iv } minutes"
setTimeout fCheckAndRun( msg.user, msg.rule.id ), iv
if msg.event is 'new' or
not listUserModules[msg.user] or
not listUserModules[msg.user][msg.rule.id]
fAnonymous()
if msg.event is 'new' or
not listUserModules[msg.user] or
not listUserModules[msg.user][msg.rule.id]
fAnonymous()
fCheckAndRun = ( userId, ruleId ) ->
() ->
if isRunning and
listUserModules[userId] and
listUserModules[userId][ruleId]
oRule = listUserModules[userId][ruleId]
fCallFunction userId, ruleId, oRule
setTimeout fCheckAndRun( userId, ruleId ), oRule.interval
# We have to register the poll function in belows anonymous function
# because we're fast iterating through the listUserModules and references will
# eventually not be what they are expected to be
fCallFunction = ( userId, ruleId, oRule ) ->
try
oRule.module[oRule.pollfunc] ( obj ) ->
db.pushEvent
event: oRule.id
eventid: "polled #{ oRule.id } #{ userId }_#{ ( new Date ).toISOString() }"
payload: obj
catch err
log.info "EP | ERROR in module when polled: #{ oRule.id } #{ userId }: #{err.message}"
oRule.logger err.message
# ###
# This function will loop infinitely every 10 seconds until isRunning is set to false
# @private pollLoop()
# ###
# pollLoop = () ->
# # We only loop if we're running
# if isRunning
# # Go through all users
# for userName, oRules of listUserModules
# # Go through each of the users modules
# for ruleName, myRule of oRules
# # Call the event poller module function
# fCallFunction myRule, ruleName, userName
# setTimeout pollLoop, 10000
###
This function will loop infinitely every 10 seconds until isRunning is set to false
@private pollLoop()
###
pollLoop = () ->
# We only loop if we're running
if isRunning
# Go through all users
for userName, oRules of listUserModules
# Go through each of the users modules
for ruleName, myRule of oRules
# # This is the to be polled function
# fPoll = myRule.module[myRule.pollfunc]
# We have to register the poll function in belows anonymous function
# because we're fast iterating through the listUserModules and references will
# eventually not be what they are expected to be
fCallFunction = ( oRule, ruleId, userId ) ->
try
oRule.module[oRule.pollfunc] ( obj ) ->
db.pushEvent
event: oRule.id
eventid: "polled #{ oRule.id } #{ userId }_#{ ( new Date ).toISOString() }"
payload: obj
catch err
log.info "EP | ERROR in module when polled: #{ oRule.id } #{ userId }: #{err.message}"
oRule.logger err.message
fCallFunction myRule, ruleName, userName
setTimeout pollLoop, 10000
# Finally if everything initialized we start polling for new events
pollLoop()
# # Finally if everything initialized we start polling for new events
# pollLoop()

View file

@ -33,11 +33,37 @@ Initializes the HTTP listener and its request handler.
@param {Object} args
###
exports = module.exports = ( args ) =>
@log = args.logger
@shutDownSystem = args[ 'shutdown-function' ]
requestHandler args
initRouting args[ 'http-port' ]
module.exports
@log = args.logger
@arrWebhooks = args.webhooks
@shutDownSystem = args[ 'shutdown-function' ]
requestHandler args
initRouting args[ 'http-port' ]
module.exports
indexEvent = ( event, body, resp ) ->
try
obj = JSON.parse body
timestamp = ( new Date ).toISOString()
rand = ( Math.floor Math.random() * 10e9 ).toString( 16 ).toUpperCase()
obj.event = event
obj.eventid = "#{ obj.event }_#{ timestamp }_#{ rand }"
db.pushEvent obj
resp.send 200, "Thank you for the event: #{ obj.eventid }"
catch err
resp.send 400, 'Badly formed event!'
# Activate a webhook. the body will be JSON parsed, the name of the webhook will
# be the event name given to the event object, a timestamp will be added
activateWebHook = ( app, name ) =>
@log.info "HL | Webhook activated for #{ name }"
app.post "/webhooks/#{ name }", ( req, resp ) ->
console.log 'something is coming through'
body = ''
req.on 'data', ( data ) ->
body += data
req.on 'end', ->
indexEvent name, body, resp
###
Initializes the request routing and starts listening on the given port.
@ -46,58 +72,60 @@ Initializes the request routing and starts listening on the given port.
@private initRouting( *fShutDown* )
###
initRouting = ( port ) =>
# Add cookie support for session handling.
app.use express.cookieParser()
#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 }
# Add cookie support for session handling.
app.use express.cookieParser()
#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.info 'HL | no session backbone'
#At the moment there's no redis session backbone (didn't work straight away)
@log.info 'HL | no session backbone'
# **Accepted requests to paths:**
# **Accepted requests to paths:**
# GET Requests
# GET Requests
# - **`GET` to _"/"_:** Static redirect to the _"webpages/public"_ directory
app.use '/', express.static path.resolve __dirname, '..', 'webpages', 'public'
# - **`GET` to _"/admin"_:** Displays the admin console if user is admin
app.get '/admin', requestHandler.handleAdmin
# - **`GET` to _"/forge"_:** Displays different forge pages
app.get '/forge', requestHandler.handleForge
# - **`GET` to _"/"_:** Static redirect to the _"webpages/public"_ directory
app.use '/', express.static path.resolve __dirname, '..', 'webpages', 'public'
# - **`GET` to _"/admin"_:** Displays the admin console if user is admin
app.get '/admin', requestHandler.handleAdmin
# - **`GET` to _"/forge"_:** Displays different forge pages
app.get '/forge', requestHandler.handleForge
# POST Requests
# POST Requests
# - **`POST` to _"/event"_:** Events coming from remote systems are passed to the engine
app.post '/event', requestHandler.handleEvent
# - **`POST` to _"/login"_:** Credentials will be verified
app.post '/login', requestHandler.handleLogin
# - **`POST` to _"/logout"_:** User will be logged out
app.post '/logout', requestHandler.handleLogout
# - **`POST` to _"/usercommand"_:** User requests are possible for all users with an account
app.post '/usercommand', requestHandler.handleUserCommand
# - **`POST` to _"/admincommand"_:** Admin requests are only possible for admins
app.post '/admincommand', requestHandler.handleAdminCommand
# - **`POST` to _"/event"_:** Events coming from remote systems are passed to the engine
app.post '/event', requestHandler.handleEvent
# - **`POST` to _"/login"_:** Credentials will be verified
app.post '/login', requestHandler.handleLogin
# - **`POST` to _"/logout"_:** User will be logged out
app.post '/logout', requestHandler.handleLogout
# - **`POST` to _"/usercommand"_:** User requests are possible for all users with an account
app.post '/usercommand', requestHandler.handleUserCommand
# - **`POST` to _"/admincommand"_:** Admin requests are only possible for admins
app.post '/admincommand', requestHandler.handleAdminCommand
# - **`POST` to _"/webhooks/*"_:** Webhooks can be added in the config file
activateWebHook app, hookName for hookName in @arrWebhooks
server = app.listen parseInt( port ) || 8111 # inbound event channel
server = app.listen parseInt( port ) || 8111 # inbound event channel
server.on 'listening', () =>
addr = server.address()
if addr.port isnt port
@shutDownSystem()
server.on 'error', ( err ) =>
###
Error handling of the express port listener requires special attention,
thus we have to catch the error, which is issued if the port is already in use.
###
switch err.errno
when 'EADDRINUSE'
@log.error err, 'HL | http-port already in use, shutting down!'
when 'EACCES'
@log.error err, 'HL | http-port not accessible, shutting down!'
else
@log.error err, 'HL | Error in server, shutting down!'
@shutDownSystem()
server.on 'listening', () =>
addr = server.address()
if addr.port isnt port
@shutDownSystem()
server.on 'error', ( err ) =>
###
Error handling of the express port listener requires special attention,
thus we have to catch the error, which is issued if the port is already in use.
###
switch err.errno
when 'EADDRINUSE'
@log.error err, 'HL | http-port already in use, shutting down!'
when 'EACCES'
@log.error err, 'HL | http-port not accessible, shutting down!'
else
@log.error err, 'HL | Error in server, shutting down!'
@shutDownSystem()
#

View file

@ -25,61 +25,61 @@ Returns a bunyan logger according to the given arguments.
@param {Object} args
###
exports.getLogger = ( args ) =>
emptylog =
trace: () ->
debug: () ->
info: () ->
warn: () ->
error: () ->
fatal: () ->
# `args` holds the configuration settings for the logging, see either CLI arguments
# in [webapi-eca](webapi-eca.html) or the configuration parameters in [config](config.html).
args = args ? {}
# We need to check for string 'true' also since the cliArgs passed to
# the event-poller will be strings
if args.nolog is true or args.nolog is 'true'
# if the user doesn't want to have a log at all (e.g. during tests), it can be omitted with
# the nolog flag
emptylog
else
try
opt =
name: "webapi-eca"
# if we are in development mode, we also add information about where the call came from
# this should be turned off in productive mode since it slows down the logging.
if args['mode'] is 'development'
opt.src = true
# if there's a custom path defined for the log, we adopt the setting.
if args['file-path']
@logPath = path.resolve args['file-path']
else
@logPath = path.resolve __dirname, '..', 'logs', 'server.log'
emptylog =
trace: () ->
debug: () ->
info: () ->
warn: () ->
error: () ->
fatal: () ->
# `args` holds the configuration settings for the logging, see either CLI arguments
# in [webapi-eca](webapi-eca.html) or the configuration parameters in [config](config.html).
args = args ? {}
# We need to check for string 'true' also since the cliArgs passed to
# the event-poller will be strings
if args.nolog is true or args.nolog is 'true'
# if the user doesn't want to have a log at all (e.g. during tests), it can be omitted with
# the nolog flag
emptylog
else
try
opt =
name: "webapi-eca"
# if we are in development mode, we also add information about where the call came from
# this should be turned off in productive mode since it slows down the logging.
if args['mode'] is 'development'
opt.src = true
# if there's a custom path defined for the log, we adopt the setting.
if args['file-path']
@logPath = path.resolve args['file-path']
else
@logPath = path.resolve __dirname, '..', 'logs', 'server.log'
# We try to write a temp file in the same folder to check if the log can be written
try
fs.writeFileSync @logPath + '.temp', 'temp'
fs.unlinkSync @logPath + '.temp'
catch e
console.error "Log folder '#{ @logPath }' is not writable"
return emptylog
# We try to write a temp file in the same folder to check if the log can be written
try
fs.writeFileSync @logPath + '.temp', 'temp'
fs.unlinkSync @logPath + '.temp'
catch e
console.error "Log folder '#{ @logPath }' is not writable"
return emptylog
# We attach two streams, one for the I/O and one for the log file.
# The log levels are defined per stream according to the CLI args or the configuration.
opt.streams = [
{
level: args['io-level']
stream: process.stdout
},
{
level: args['file-level']
path: @logPath
}
]
# Finally we create the bunyan logger and return it
bunyan.createLogger opt
# We attach two streams, one for the I/O and one for the log file.
# The log levels are defined per stream according to the CLI args or the configuration.
opt.streams = [
{
level: args['io-level']
stream: process.stdout
},
{
level: args['file-level']
path: @logPath
}
]
# Finally we create the bunyan logger and return it
bunyan.createLogger opt
# If something goes wrong we print the error and return an empty logger.
catch e
console.error e
emptylog
# If something goes wrong we print the error and return an empty logger.
catch e
console.error e
emptylog

View file

@ -34,32 +34,34 @@ Initializes the DB connection with the given `db-port` property in the `args` ob
@param {Object} args
###
exports = module.exports = ( args ) =>
if not @db
#TODO we need to have a secure concept here, private keys per user
#FIXME get rid of crpto
if not args[ 'db-port' ]
args[ 'db-port' ] = 6379
@log = args.logger
exports.eventPollers = new IndexedModules 'event-poller', @log
exports.actionInvokers = new IndexedModules 'action-invoker', @log
exports.initPort args[ 'db-port' ]
if not @db
#TODO we need to have a secure concept here, private keys per user
#FIXME get rid of crpto
if not args[ 'db-port' ]
args[ 'db-port' ] = 6379
@log = args.logger
exports.eventPollers = new IndexedModules 'event-poller', @log
exports.actionInvokers = new IndexedModules 'action-invoker', @log
exports.initPort args[ 'db-port' ]
exports.getLogger = () =>
@log
@log
exports.initPort = ( port ) =>
@connRefused = false
@db?.quit()
@db = redis.createClient port,
'localhost', { connect_timeout: 2000 }
# Eventually we try to connect to the wrong port, redis will emit an error that we
# need to catch and take into account when answering the isConnected function call
@db.on 'error', ( err ) =>
if err.message.indexOf( 'ECONNREFUSED' ) > -1
@connRefused = true
@log.error err, 'DB | Wrong port?'
exports.eventPollers.setDB @db
exports.actionInvokers.setDB @db
@connRefused = false
@db?.quit()
@db = redis.createClient port,
'localhost', { connect_timeout: 2000 }
# Eventually we try to connect to the wrong port, redis will emit an error that we
# need to catch and take into account when answering the isConnected function call
@db.on 'error', ( err ) =>
if err.message.indexOf( 'ECONNREFUSED' ) > -1
@connRefused = true
@log.warn 'DB | Wrong port?'
else
@log.error err
exports.eventPollers.setDB @db
exports.actionInvokers.setDB @db
###
Checks whether the db is connected and passes either an error on failure after
@ -69,26 +71,26 @@ ten attempts within five seconds, or nothing on success to the callback(err).
@param {function} cb
###
exports.isConnected = ( cb ) =>
if not @db
cb new Error 'DB | DB initialization did not occur or failed miserably!'
else
if @db.connected
cb()
else
numAttempts = 0
fCheckConnection = =>
if @connRefused
@db?.quit()
cb new Error 'DB | Connection refused! Wrong port?'
else
if @db.connected
@log.info 'DB | Successfully connected to DB!'
cb()
else if numAttempts++ < 10
setTimeout fCheckConnection, 100
else
cb new Error 'DB | Connection to DB failed!'
setTimeout fCheckConnection, 100
if not @db
cb new Error 'DB | DB initialization did not occur or failed miserably!'
else
if @db.connected
cb()
else
numAttempts = 0
fCheckConnection = =>
if @connRefused
@db?.quit()
cb new Error 'DB | Connection refused! Wrong port?'
else
if @db.connected
@log.info 'DB | Successfully connected to DB!'
cb()
else if numAttempts++ < 10
setTimeout fCheckConnection, 100
else
cb new Error 'DB | Connection to DB failed!'
setTimeout fCheckConnection, 100
###
@ -98,11 +100,11 @@ Abstracts logging for simple action replies from the DB.
@param {String} action
###
replyHandler = ( action ) =>
( err, reply ) =>
if err
@log.warn err, "during '#{ action }'"
else
@log.info "DB | #{ action }: #{ reply }"
( err, reply ) =>
if err
@log.warn err, "during '#{ action }'"
else
@log.info "DB | #{ action }: #{ reply }"
###
@ -112,11 +114,11 @@ Push an event into the event queue.
@param {Object} oEvent
###
exports.pushEvent = ( oEvent ) =>
if oEvent
@log.info "DB | Event pushed into the queue: '#{ oEvent.eventid }'"
@db.rpush 'event_queue', JSON.stringify oEvent
else
@log.warn 'DB | Why would you give me an empty event...'
if oEvent
@log.info "DB | Event pushed into the queue: '#{ oEvent.eventid }'"
@db.rpush 'event_queue', JSON.stringify oEvent
else
@log.warn 'DB | Why would you give me an empty event...'
###
@ -126,10 +128,10 @@ Pop an event from the event queue and pass it to cb(err, obj).
@param {function} cb
###
exports.popEvent = ( cb ) =>
makeObj = ( pcb ) ->
( err, obj ) ->
pcb err, JSON.parse obj
@db.lpop 'event_queue', makeObj cb
makeObj = ( pcb ) ->
( err, obj ) ->
pcb err, JSON.parse obj
@db.lpop 'event_queue', makeObj cb
###
@ -138,7 +140,7 @@ Purge the event queue.
@public purgeEventQueue()
###
exports.purgeEventQueue = () =>
@db.del 'event_queue', replyHandler 'purging event queue'
@db.del 'event_queue', replyHandler 'purging event queue'
###
@ -148,202 +150,202 @@ data objects via the provided function and returns the results to cb(err, obj).
@private getSetRecords( *set, fSingle, cb* )
@param {String} set the set name how it is stored in the DB
@param {function} fSingle a function to retrieve a single data element
per set entry
per set entry
@param {function} cb the callback(err, obj) function that receives all
the retrieved data or an error
the retrieved data or an error
###
getSetRecords = ( set, fSingle, cb ) =>
@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
@log.warn err, "DB | fetching '#{ set }'"
cb err
else if arrReply.length == 0
# If the set was empty we return null to the callback
cb()
else
# We need to fetch all the entries from the set and use a semaphore
# since the fetching from the DB will happen asynchronously
semaphore = arrReply.length
objReplies = {}
setTimeout ->
# We use a timeout function to cancel the operation
# in case the DB does not respond
if semaphore > 0
cb new Error "Timeout fetching '#{ set }'"
, 2000
fCallback = ( prop ) =>
# The callback function is required to preprocess the result before
# handing it to the callback. This especially includes decrementing
# the semaphore
( err, data ) =>
--semaphore
if err
@log.warn err, "DB | fetching single element: '#{ prop }'"
else if not data
# There was no data behind the key
@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
if semaphore == 0
# If all fetch calls returned we finally pass the result
# to the callback
cb null, objReplies
# Since we retrieved an array of keys, we now execute the fSingle function
# on each of them, to retrieve the ata behind the key. Our fCallback function
# is used to preprocess the answer to determine correct execution
fSingle reply, fCallback reply for reply in arrReply
@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
@log.warn err, "DB | fetching '#{ set }'"
cb err
else if arrReply.length == 0
# If the set was empty we return null to the callback
cb()
else
# We need to fetch all the entries from the set and use a semaphore
# since the fetching from the DB will happen asynchronously
semaphore = arrReply.length
objReplies = {}
setTimeout ->
# We use a timeout function to cancel the operation
# in case the DB does not respond
if semaphore > 0
cb new Error "Timeout fetching '#{ set }'"
, 2000
fCallback = ( prop ) =>
# The callback function is required to preprocess the result before
# handing it to the callback. This especially includes decrementing
# the semaphore
( err, data ) =>
--semaphore
if err
@log.warn err, "DB | fetching single element: '#{ prop }'"
else if not data
# There was no data behind the key
@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
if semaphore == 0
# If all fetch calls returned we finally pass the result
# to the callback
cb null, objReplies
# Since we retrieved an array of keys, we now execute the fSingle function
# on each of them, to retrieve the ata behind the key. Our fCallback function
# is used to preprocess the answer to determine correct execution
fSingle reply, fCallback reply for reply in arrReply
class IndexedModules
constructor: ( @setname, @log ) ->
@log.info "DB | (IdxedMods) Instantiated indexed modules for '#{ @setname }'"
constructor: ( @setname, @log ) ->
@log.info "DB | (IdxedMods) Instantiated indexed modules for '#{ @setname }'"
setDB: ( @db ) ->
@log.info "DB | (IdxedMods) Registered new DB connection for '#{ @setname }'"
setDB: ( @db ) ->
@log.info "DB | (IdxedMods) Registered new DB connection for '#{ @setname }'"
###
Stores a module and links it to the user.
@private storeModule( *userId, oModule* )
@param {String} userId
@param {object} oModule
###
storeModule: ( userId, oModule ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeModule( #{ userId }, oModule )"
@db.sadd "#{ @setname }s", oModule.id,
replyHandler "sadd '#{ oModule.id }' to '#{ @setname }'"
@db.hmset "#{ @setname }:#{ oModule.id }", oModule,
replyHandler "hmset properties in hash '#{ @setname }:#{ oModule.id }'"
@linkModule oModule.id, userId
###
Stores a module and links it to the user.
@private storeModule( *userId, oModule* )
@param {String} userId
@param {object} oModule
###
storeModule: ( userId, oModule ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeModule( #{ userId }, oModule )"
@db.sadd "#{ @setname }s", oModule.id,
replyHandler "sadd '#{ oModule.id }' to '#{ @setname }'"
@db.hmset "#{ @setname }:#{ oModule.id }", oModule,
replyHandler "hmset properties in hash '#{ @setname }:#{ oModule.id }'"
@linkModule oModule.id, userId
#TODO add testing
linkModule: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.linkModule( #{ mId }, #{ userId } )"
@db.sadd "#{ @setname }:#{ mId }:users", userId,
replyHandler "sadd #{ userId } to '#{ @setname }:#{ mId }:users'"
@db.sadd "user:#{ userId }:#{ @setname }s", mId,
replyHandler "sadd #{ mId } to 'user:#{ userId }:#{ @setname }s'"
#TODO add testing
linkModule: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.linkModule( #{ mId }, #{ userId } )"
@db.sadd "#{ @setname }:#{ mId }:users", userId,
replyHandler "sadd #{ userId } to '#{ @setname }:#{ mId }:users'"
@db.sadd "user:#{ userId }:#{ @setname }s", mId,
replyHandler "sadd #{ mId } to 'user:#{ userId }:#{ @setname }s'"
#TODO add testing
unlinkModule: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.unlinkModule( #{ mId }, #{ userId } )"
@db.srem "#{ @setname }:#{ mId }:users", userId,
replyHandler "srem #{ userId } from '#{ @setname }:#{ mId }:users'"
@db.srem "user:#{ userId }:#{ @setname }s", mId,
replyHandler "srem #{ mId } from 'user:#{ userId }:#{ @setname }s'"
#TODO add testing
unlinkModule: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.unlinkModule( #{ mId }, #{ userId } )"
@db.srem "#{ @setname }:#{ mId }:users", userId,
replyHandler "srem #{ userId } from '#{ @setname }:#{ mId }:users'"
@db.srem "user:#{ userId }:#{ @setname }s", mId,
replyHandler "srem #{ mId } from 'user:#{ userId }:#{ @setname }s'"
#TODO add testing
publish: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.publish( #{ mId } )"
@db.sadd "public-#{ @setname }s", mId,
replyHandler "sadd '#{ mId }' to 'public-#{ @setname }s'"
#TODO add testing
publish: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.publish( #{ mId } )"
@db.sadd "public-#{ @setname }s", mId,
replyHandler "sadd '#{ mId }' to 'public-#{ @setname }s'"
#TODO add testing
unpublish: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.unpublish( #{ mId } )"
@db.srem "public-#{ @setname }s", mId,
replyHandler "srem '#{ mId }' from 'public-#{ @setname }s'"
#TODO add testing
unpublish: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.unpublish( #{ mId } )"
@db.srem "public-#{ @setname }s", mId,
replyHandler "srem '#{ mId }' from 'public-#{ @setname }s'"
getModule: ( mId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ mId } )"
@db.hgetall "#{ @setname }:#{ mId }", cb
getModule: ( mId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ mId } )"
@db.hgetall "#{ @setname }:#{ mId }", cb
getModuleField: ( mId, field, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ mId } )"
@db.hget "#{ @setname }:#{ mId }", field, cb
getModuleField: ( mId, field, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ mId } )"
@db.hget "#{ @setname }:#{ mId }", field, cb
#TODO add testing
getModuleParams: ( mId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModuleParams( #{ mId } )"
@db.hget "#{ @setname }:#{ mId }", "params", cb
#TODO add testing
getModuleParams: ( mId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModuleParams( #{ mId } )"
@db.hget "#{ @setname }:#{ mId }", "params", cb
#TODO add testing
getAvailableModuleIds: ( userId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getPublicModuleIds( #{ userId } )"
@db.sunion "public-#{ @setname }s", "user:#{ userId }:#{ @setname }s", cb
#TODO add testing
getAvailableModuleIds: ( userId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getPublicModuleIds( #{ userId } )"
@db.sunion "public-#{ @setname }s", "user:#{ userId }:#{ @setname }s", cb
getModuleIds: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModuleIds()"
@db.smembers "#{ @setname }s", cb
getModuleIds: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModuleIds()"
@db.smembers "#{ @setname }s", cb
getModules: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModules()"
getSetRecords "#{ @setname }s", @getModule, cb
getModules: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getModules()"
getSetRecords "#{ @setname }s", @getModule, cb
deleteModule: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteModule( #{ mId } )"
@db.srem "#{ @setname }s", mId,
replyHandler "srem '#{ mId }' from #{ @setname }s"
@db.del "#{ @setname }:#{ mId }",
replyHandler "del of '#{ @setname }:#{ mId }'"
@unpublish mId
@db.smembers "#{ @setname }:#{ mId }:users", ( err, obj ) =>
@unlinkModule mId, userId for userId in obj
@deleteUserParams mId, userId for userId in obj
@deleteUserArguments mId, userId for userId in obj
deleteModule: ( mId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteModule( #{ mId } )"
@db.srem "#{ @setname }s", mId,
replyHandler "srem '#{ mId }' from #{ @setname }s"
@db.del "#{ @setname }:#{ mId }",
replyHandler "del of '#{ @setname }:#{ mId }'"
@unpublish mId
@db.smembers "#{ @setname }:#{ mId }:users", ( err, obj ) =>
@unlinkModule mId, userId for userId in obj
@deleteUserParams mId, userId for userId in obj
@deleteUserArguments mId, userId for userId in obj
###
Stores user params for a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserParams( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
###
storeUserParams: ( mId, userId, encData ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeUserParams( #{ mId }, #{ userId }, encData )"
@db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "sadd '#{ mId }:#{ userId }' to '#{ @setname }-params'"
@db.set "#{ @setname }-params:#{ mId }:#{ userId }", encData,
replyHandler "set user params in '#{ @setname }-params:#{ mId }:#{ userId }'"
###
Stores user params for a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserParams( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
###
storeUserParams: ( mId, userId, encData ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeUserParams( #{ mId }, #{ userId }, encData )"
@db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "sadd '#{ mId }:#{ userId }' to '#{ @setname }-params'"
@db.set "#{ @setname }-params:#{ mId }:#{ userId }", encData,
replyHandler "set user params in '#{ @setname }-params:#{ mId }:#{ userId }'"
getUserParams: ( mId, userId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getUserParams( #{ mId }, #{ userId } )"
@db.get "#{ @setname }-params:#{ mId }:#{ userId }", cb
getUserParams: ( mId, userId, cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getUserParams( #{ mId }, #{ userId } )"
@db.get "#{ @setname }-params:#{ mId }:#{ userId }", cb
getUserParamsIds: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getUserParamsIds()"
@db.smembers "#{ @setname }-params", cb
getUserParamsIds: ( cb ) =>
@log.info "DB | (IdxedMods) #{ @setname }.getUserParamsIds()"
@db.smembers "#{ @setname }-params", cb
deleteUserParams: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteUserParams(#{ mId }, #{ userId } )"
@db.srem "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "srem '#{ mId }:#{ userId }' from '#{ @setname }-params'"
@db.del "#{ @setname }-params:#{ mId }:#{ userId }",
replyHandler "del '#{ @setname }-params:#{ mId }:#{ userId }'"
deleteUserParams: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteUserParams(#{ mId }, #{ userId } )"
@db.srem "#{ @setname }-params", "#{ mId }:#{ userId }",
replyHandler "srem '#{ mId }:#{ userId }' from '#{ @setname }-params'"
@db.del "#{ @setname }-params:#{ mId }:#{ userId }",
replyHandler "del '#{ @setname }-params:#{ mId }:#{ userId }'"
###
Stores user arguments for a function within a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserArguments( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
###
storeUserArguments: ( mId, funcId, userId, encData ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeUserArguments( #{ mId }, #{ funcId }, #{ userId }, encData )"
@db.sadd "#{ @setname }:#{ mId }:#{ userId }:functions", funcId,
replyHandler "sadd '#{ funcId }' to '#{ @setname }:#{ mId }:#{ userId }:functions'"
@db.set "#{ @setname }:#{ mId }:#{ userId }:function:#{ funcId }", encData,
replyHandler "set user params in '#{ @setname }:#{ mId }:#{ userId }:function:#{ func }'"
###
Stores user arguments for a function within a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserArguments( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
###
storeUserArguments: ( mId, funcId, userId, encData ) =>
@log.info "DB | (IdxedMods) #{ @setname }.storeUserArguments( #{ mId }, #{ funcId }, #{ userId }, encData )"
@db.sadd "#{ @setname }:#{ mId }:#{ userId }:functions", funcId,
replyHandler "sadd '#{ funcId }' to '#{ @setname }:#{ mId }:#{ userId }:functions'"
@db.set "#{ @setname }:#{ mId }:#{ userId }:function:#{ funcId }", encData,
replyHandler "set user params in '#{ @setname }:#{ mId }:#{ userId }:function:#{ func }'"
getUserArguments: ( mId, funcId, userId, cb ) =>
console.log 'calling ffunct'
@log.info "DB | (IdxedMods) #{ @setname }.getUserArguments( #{ mId }, #{ funcId }, #{ userId } )"
@db.get "#{ @setname }:#{ mId }:#{ userId }:function:#{ funcId }", cb
getUserArguments: ( mId, funcId, userId, cb ) =>
console.log 'calling ffunct'
@log.info "DB | (IdxedMods) #{ @setname }.getUserArguments( #{ mId }, #{ funcId }, #{ userId } )"
@db.get "#{ @setname }:#{ mId }:#{ userId }:function:#{ funcId }", cb
deleteUserArguments: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteUserArguments(#{ mId }, #{ userId } )"
@db.smembers "#{ @setname }:#{ mId }:#{ userId }:functions", ( err, obj ) =>
for func in obj
@db.del "#{ @setname }:#{ mId }:#{ userId }:function:#{ func }",
replyHandler "del '#{ @setname }:#{ mId }:#{ userId }:function:#{ func }'"
deleteUserArguments: ( mId, userId ) =>
@log.info "DB | (IdxedMods) #{ @setname }.deleteUserArguments(#{ mId }, #{ userId } )"
@db.smembers "#{ @setname }:#{ mId }:#{ userId }:functions", ( err, obj ) =>
for func in obj
@db.del "#{ @setname }:#{ mId }:#{ userId }:function:#{ func }",
replyHandler "del '#{ @setname }:#{ mId }:#{ userId }:function:#{ func }'"
###
@ -360,8 +362,8 @@ Appends a log entry.
@param {String} message
###
exports.appendLog = ( userId, ruleId, moduleId, message ) =>
@db.append "#{ userId }:#{ ruleId }:log",
"[#{ ( new Date ).toISOString() }] {#{ moduleId }} #{ message }\n"
@db.append "#{ userId }:#{ ruleId }:log",
"[#{ ( new Date ).toISOString() }] {#{ moduleId }} #{ message }\n"
###
Retrieves a log entry.
@ -372,7 +374,7 @@ Retrieves a log entry.
@param {function} cb
###
exports.getLog = ( userId, ruleId, cb ) =>
@db.get "#{ userId }:#{ ruleId }:log", cb
@db.get "#{ userId }:#{ ruleId }:log", cb
###
Resets a log entry.
@ -382,8 +384,8 @@ Resets a log entry.
@param {String} ruleId
###
exports.resetLog = ( userId, ruleId ) =>
@db.del "#{ userId }:#{ ruleId }:log",
replyHandler "del '#{ userId }:#{ ruleId }:log'"
@db.del "#{ userId }:#{ ruleId }:log",
replyHandler "del '#{ userId }:#{ ruleId }:log'"
###
Query the DB for a rule and pass it to cb(err, obj).
@ -393,8 +395,8 @@ Query the DB for a rule and pass it to cb(err, obj).
@param {function} cb
###
exports.getRule = ( ruleId, cb ) =>
@log.info "DB | get: 'rule:#{ ruleId }'"
@db.get "rule:#{ ruleId }", cb
@log.info "DB | get: 'rule:#{ ruleId }'"
@db.get "rule:#{ ruleId }", cb
###
Fetch all rules and pass them to cb(err, obj).
@ -403,8 +405,8 @@ Fetch all rules and pass them to cb(err, obj).
@param {function} cb
###
exports.getRules = ( cb ) =>
@log.info "DB | Fetching all Rules: getSetRecords 'rules'"
getSetRecords 'rules', exports.getRule, cb
@log.info "DB | Fetching all Rules: getSetRecords 'rules'"
getSetRecords 'rules', exports.getRule, cb
###
Fetch all rule IDs and hand it to cb(err, obj).
@ -413,8 +415,8 @@ Fetch all rule IDs and hand it to cb(err, obj).
@param {function} cb
###
exports.getRuleIds = ( cb ) =>
@log.info "DB | Fetching all Rule IDs: 'rules'"
@db.smembers 'rules', cb
@log.info "DB | Fetching all Rule IDs: 'rules'"
@db.smembers 'rules', cb
###
Store a string representation of a rule in the DB.
@ -424,11 +426,11 @@ Store a string representation of a rule in the DB.
@param {String} data
###
exports.storeRule = ( ruleId, data ) =>
@log.info "DB | storeRule: '#{ ruleId }'"
@db.sadd 'rules', "#{ ruleId }",
replyHandler "sadd rules: '#{ ruleId }'"
@db.set "rule:#{ ruleId }", data,
replyHandler "set 'rule:#{ ruleId }': data"
@log.info "DB | storeRule: '#{ ruleId }'"
@db.sadd 'rules', "#{ ruleId }",
replyHandler "sadd rules: '#{ ruleId }'"
@db.set "rule:#{ ruleId }", data,
replyHandler "set 'rule:#{ ruleId }': data"
###
Delete a string representation of a rule.
@ -438,26 +440,26 @@ Delete a string representation of a rule.
@param {String} userId
###
exports.deleteRule = ( ruleId ) =>
@log.info "DB | deleteRule: '#{ ruleId }'"
@db.srem "rules", ruleId, replyHandler "srem 'rules': '#{ ruleId }'"
@db.del "rule:#{ ruleId }", replyHandler "del: 'rule:#{ ruleId }'"
@log.info "DB | deleteRule: '#{ ruleId }'"
@db.srem "rules", ruleId, replyHandler "srem 'rules': '#{ ruleId }'"
@db.del "rule:#{ ruleId }", replyHandler "del: 'rule:#{ ruleId }'"
# We also need to delete all references in linked and active users
@db.smembers "rule:#{ ruleId }:users", ( err, obj ) =>
delLinkedUserRule = ( userId ) =>
exports.resetLog userId, ruleId
@db.srem "user:#{ userId }:rules", ruleId,
replyHandler "srem 'user:#{ userId }:rules': '#{ ruleId }'"
delLinkedUserRule id for id in obj
@db.del "rule:#{ ruleId }:users", replyHandler "del 'rule:#{ ruleId }:users'"
# We also need to delete all references in linked and active users
@db.smembers "rule:#{ ruleId }:users", ( err, obj ) =>
delLinkedUserRule = ( userId ) =>
exports.resetLog userId, ruleId
@db.srem "user:#{ userId }:rules", ruleId,
replyHandler "srem 'user:#{ userId }:rules': '#{ ruleId }'"
delLinkedUserRule id for id in obj
@db.del "rule:#{ ruleId }:users", replyHandler "del 'rule:#{ ruleId }:users'"
@db.smembers "rule:#{ ruleId }:active-users", ( err, obj ) =>
delActiveUserRule = ( userId ) =>
@db.srem "user:#{ userId }:active-rules", ruleId,
replyHandler "srem 'user:#{ userId }:active-rules': '#{ ruleId }'"
delActiveUserRule id for id in obj
@db.del "rule:#{ ruleId }:active-users",
replyHandler "del 'rule:#{ ruleId }:active-users'"
@db.smembers "rule:#{ ruleId }:active-users", ( err, obj ) =>
delActiveUserRule = ( userId ) =>
@db.srem "user:#{ userId }:active-rules", ruleId,
replyHandler "srem 'user:#{ userId }:active-rules': '#{ ruleId }'"
delActiveUserRule id for id in obj
@db.del "rule:#{ ruleId }:active-users",
replyHandler "del 'rule:#{ ruleId }:active-users'"
###
Associate a rule to a user.
@ -467,11 +469,11 @@ Associate a rule to a user.
@param {String} userId
###
exports.linkRule = ( ruleId, userId ) =>
@log.info "DB | linkRule: '#{ ruleId }' to user '#{ userId }'"
@db.sadd "rule:#{ ruleId }:users", userId,
replyHandler "sadd 'rule:#{ ruleId }:users': '#{ userId }'"
@db.sadd "user:#{ userId }:rules", ruleId,
replyHandler "sadd 'user:#{ userId }:rules': '#{ ruleId }'"
@log.info "DB | linkRule: '#{ ruleId }' to user '#{ userId }'"
@db.sadd "rule:#{ ruleId }:users", userId,
replyHandler "sadd 'rule:#{ ruleId }:users': '#{ userId }'"
@db.sadd "user:#{ userId }:rules", ruleId,
replyHandler "sadd 'user:#{ userId }:rules': '#{ ruleId }'"
###
Get rules linked to a user and hand it to cb(err, obj).
@ -481,8 +483,8 @@ Get rules linked to a user and hand it to cb(err, obj).
@param {function} cb
###
exports.getUserLinkedRules = ( userId, cb ) =>
@log.info "DB | getUserLinkedRules: 'user:#{ userId }:rules'"
@db.smembers "user:#{ userId }:rules", cb
@log.info "DB | getUserLinkedRules: 'user:#{ userId }:rules'"
@db.smembers "user:#{ userId }:rules", cb
###
Get users linked to a rule and hand it to cb(err, obj).
@ -492,8 +494,8 @@ Get users linked to a rule and hand it to cb(err, obj).
@param {function} cb
###
exports.getRuleLinkedUsers = ( ruleId, cb ) =>
@log.info "DB | getRuleLinkedUsers: 'rule:#{ ruleId }:users'"
@db.smembers "rule:#{ ruleId }:users", cb
@log.info "DB | getRuleLinkedUsers: 'rule:#{ ruleId }:users'"
@db.smembers "rule:#{ ruleId }:users", cb
###
Delete an association of a rule to a user.
@ -503,11 +505,11 @@ Delete an association of a rule to a user.
@param {String} userId
###
exports.unlinkRule = ( ruleId, userId ) =>
@log.info "DB | unlinkRule: '#{ ruleId }:#{ userId }'"
@db.srem "rule:#{ ruleId }:users", userId,
replyHandler "srem 'rule:#{ ruleId }:users': '#{ userId }'"
@db.srem "user:#{ userId }:rules", ruleId,
replyHandler "srem 'user:#{ userId }:rules': '#{ ruleId }'"
@log.info "DB | unlinkRule: '#{ ruleId }:#{ userId }'"
@db.srem "rule:#{ ruleId }:users", userId,
replyHandler "srem 'rule:#{ ruleId }:users': '#{ userId }'"
@db.srem "user:#{ userId }:rules", ruleId,
replyHandler "srem 'user:#{ userId }:rules': '#{ ruleId }'"
###
Activate a rule.
@ -517,11 +519,11 @@ Activate a rule.
@param {String} userId
###
exports.activateRule = ( ruleId, userId ) =>
@log.info "DB | activateRule: '#{ ruleId }' for '#{ userId }'"
@db.sadd "rule:#{ ruleId }:active-users", userId,
replyHandler "sadd 'rule:#{ ruleId }:active-users': '#{ userId }'"
@db.sadd "user:#{ userId }:active-rules", ruleId,
replyHandler "sadd 'user:#{ userId }:active-rules': '#{ ruleId }'"
@log.info "DB | activateRule: '#{ ruleId }' for '#{ userId }'"
@db.sadd "rule:#{ ruleId }:active-users", userId,
replyHandler "sadd 'rule:#{ ruleId }:active-users': '#{ userId }'"
@db.sadd "user:#{ userId }:active-rules", ruleId,
replyHandler "sadd 'user:#{ userId }:active-rules': '#{ ruleId }'"
###
Get rules activated for a user and hand it to cb(err, obj).
@ -531,8 +533,8 @@ Get rules activated for a user and hand it to cb(err, obj).
@param {function} cb
###
exports.getUserActivatedRules = ( userId, cb ) =>
@log.info "DB | getUserActivatedRules: smembers 'user:#{ userId }:active-rules'"
@db.smembers "user:#{ userId }:active-rules", cb
@log.info "DB | getUserActivatedRules: smembers 'user:#{ userId }:active-rules'"
@db.smembers "user:#{ userId }:active-rules", cb
###
Get users activated for a rule and hand it to cb(err, obj).
@ -542,8 +544,8 @@ Get users activated for a rule and hand it to cb(err, obj).
@param {function} cb
###
exports.getRuleActivatedUsers = ( ruleId, cb ) =>
@log.info "DB | getRuleActivatedUsers: smembers 'rule:#{ ruleId }:active-users'"
@db.smembers "rule:#{ ruleId }:active-users", cb
@log.info "DB | getRuleActivatedUsers: smembers 'rule:#{ ruleId }:active-users'"
@db.smembers "rule:#{ ruleId }:active-users", cb
###
Deactivate a rule.
@ -553,11 +555,11 @@ Deactivate a rule.
@param {String} userId
###
exports.deactivateRule = ( ruleId, userId ) =>
@log.info "DB | deactivateRule: '#{ ruleId }' for '#{ userId }'"
@db.srem "rule:#{ ruleId }:active-users", userId,
replyHandler "srem 'rule:#{ ruleId }:active-users': '#{ userId }'"
@db.srem "user:#{ userId }:active-rules", ruleId,
replyHandler "srem 'user:#{ userId }:active-rules' '#{ ruleId }'"
@log.info "DB | deactivateRule: '#{ ruleId }' for '#{ userId }'"
@db.srem "rule:#{ ruleId }:active-users", userId,
replyHandler "srem 'rule:#{ ruleId }:active-users': '#{ userId }'"
@db.srem "user:#{ userId }:active-rules", ruleId,
replyHandler "srem 'user:#{ userId }:active-rules' '#{ ruleId }'"
###
Fetch all active ruleIds and pass them to cb(err, obj).
@ -566,20 +568,20 @@ Fetch all active ruleIds and pass them to cb(err, obj).
@param {function} cb
###
exports.getAllActivatedRuleIdsPerUser = ( cb ) =>
@log.info "DB | Fetching all active rules"
@db.smembers 'users', ( err, obj ) =>
result = {}
if obj.length is 0
cb null, result
else
semaphore = obj.length
fFetchActiveUserRules = ( userId ) =>
@db.smembers "user:#{ user }:active-rules", ( err, obj ) =>
if obj.length > 0
result[userId] = obj
if --semaphore is 0
cb null, result
fFetchActiveUserRules user for user in obj
@log.info "DB | Fetching all active rules"
@db.smembers 'users', ( err, obj ) =>
result = {}
if obj.length is 0
cb null, result
else
semaphore = obj.length
fFetchActiveUserRules = ( userId ) =>
@db.smembers "user:#{ user }:active-rules", ( err, obj ) =>
if obj.length > 0
result[userId] = obj
if --semaphore is 0
cb null, result
fFetchActiveUserRules user for user in obj
###
@ -594,15 +596,15 @@ The password should be hashed before it is passed to this function.
@param {Object} objUser
###
exports.storeUser = ( objUser ) =>
@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 }'"
objUser.password = objUser.password
@db.hmset "user:#{ objUser.username }", objUser,
replyHandler "storing user properties '#{ objUser.username }'"
else
@log.warn new Error 'DB | username or password was missing'
@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 }'"
objUser.password = objUser.password
@db.hmset "user:#{ objUser.username }", objUser,
replyHandler "storing user properties '#{ objUser.username }'"
else
@log.warn new Error 'DB | username or password was missing'
###
Fetch all user IDs and pass them to cb(err, obj).
@ -611,9 +613,9 @@ Fetch all user IDs and pass them to cb(err, obj).
@param {function} cb
###
exports.getUserIds = ( cb ) =>
@log.info "DB | getUserIds"
@db.smembers "users", cb
@log.info "DB | getUserIds"
@db.smembers "users", cb
###
Fetch a user by id and pass it to cb(err, obj).
@ -622,9 +624,9 @@ Fetch a user by id and pass it to cb(err, obj).
@param {function} cb
###
exports.getUser = ( userId, cb ) =>
@log.info "DB | getUser: '#{ userId }'"
@db.hgetall "user:#{ userId }", cb
@log.info "DB | getUser: '#{ userId }'"
@db.hgetall "user:#{ userId }", cb
###
Deletes a user and all his associated linked and active rules.
@ -632,36 +634,36 @@ Deletes a user and all his associated linked and active rules.
@param {String} userId
###
exports.deleteUser = ( userId ) =>
@log.info "DB | deleteUser: '#{ userId }'"
@db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'"
@db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'"
@log.info "DB | deleteUser: '#{ userId }'"
@db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'"
@db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'"
# We also need to delete all linked rules
@db.smembers "user:#{ userId }:rules", ( err, obj ) =>
delLinkedRuleUser = ( ruleId ) =>
@db.srem "rule:#{ ruleId }:users", userId,
replyHandler "Deleting user key '#{ userId }' in linked rule '#{ ruleId }'"
delLinkedRuleUser id for id in obj
@db.del "user:#{ userId }:rules",
replyHandler "Deleting user '#{ userId }' rules"
# We also need to delete all linked rules
@db.smembers "user:#{ userId }:rules", ( err, obj ) =>
delLinkedRuleUser = ( ruleId ) =>
@db.srem "rule:#{ ruleId }:users", userId,
replyHandler "Deleting user key '#{ userId }' in linked rule '#{ ruleId }'"
delLinkedRuleUser id for id in obj
@db.del "user:#{ userId }:rules",
replyHandler "Deleting user '#{ userId }' rules"
# We also need to delete all active rules
@db.smembers "user:#{ userId }:active-rules", ( err, obj ) =>
delActivatedRuleUser = ( ruleId ) =>
@db.srem "rule:#{ ruleId }:active-users", userId,
replyHandler "Deleting user key '#{ userId }' in active rule '#{ ruleId }'"
delActivatedRuleUser id for id in obj
@db.del "user:#{ userId }:active-rules",
replyHandler "Deleting user '#{ userId }' rules"
# We also need to delete all active rules
@db.smembers "user:#{ userId }:active-rules", ( err, obj ) =>
delActivatedRuleUser = ( ruleId ) =>
@db.srem "rule:#{ ruleId }:active-users", userId,
replyHandler "Deleting user key '#{ userId }' in active rule '#{ ruleId }'"
delActivatedRuleUser id for id in obj
@db.del "user:#{ userId }:active-rules",
replyHandler "Deleting user '#{ userId }' rules"
# We also need to delete all associated roles
@db.smembers "user:#{ userId }:roles", ( err, obj ) =>
delRoleUser = ( roleId ) =>
@db.srem "role:#{ roleId }:users", userId,
replyHandler "Deleting user key '#{ userId }' in role '#{ roleId }'"
delRoleUser id for id in obj
@db.del "user:#{ userId }:roles",
replyHandler "Deleting user '#{ userId }' roles"
# We also need to delete all associated roles
@db.smembers "user:#{ userId }:roles", ( err, obj ) =>
delRoleUser = ( roleId ) =>
@db.srem "role:#{ roleId }:users", userId,
replyHandler "Deleting user key '#{ userId }' in role '#{ roleId }'"
delRoleUser id for id in obj
@db.del "user:#{ userId }:roles",
replyHandler "Deleting user '#{ userId }' roles"
###
Checks the credentials and on success returns the user object to the
@ -675,20 +677,20 @@ because we only store hashes of passwords for security6 reasons.
@param {function} cb
###
exports.loginUser = ( userId, password, cb ) =>
@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 is obj.password
@log.info "DB | User '#{ obj.username }' logged in!"
cb null, obj
else
cb (new Error 'Wrong credentials!'), null
else
cb (new Error 'User not found!'), null
@db.hgetall "user:#{ userId }", fCheck password
@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 is obj.password
@log.info "DB | User '#{ obj.username }' logged in!"
cb null, obj
else
cb (new Error 'Wrong credentials!'), null
else
cb (new Error 'User not found!'), null
@db.hgetall "user:#{ userId }", fCheck password
#TODO implement functions required for user sessions?
@ -705,12 +707,12 @@ Associate a role with a user.
@param {String} role
###
exports.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 }'"
@db.sadd "role:#{ role }:users", userId,
replyHandler "adding user '#{ userId }' to role '#{ 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 }'"
@db.sadd "role:#{ role }:users", userId,
replyHandler "adding user '#{ userId }' to role '#{ role }'"
###
Fetch all roles of a user and pass them to cb(err, obj).
@ -720,9 +722,9 @@ 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 }'"
@db.smembers "user:#{ userId }:roles", cb
@log.info "DB | getUserRoles: '#{ userId }'"
@db.smembers "user:#{ userId }:roles", cb
###
Fetch all users of a role and pass them to cb(err, obj).
@ -731,8 +733,8 @@ 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 }'"
@db.smembers "role:#{ role }:users", cb
@log.info "DB | getRoleUsers: '#{ role }'"
@db.smembers "role:#{ role }:users", cb
###
Remove a role from a user.
@ -742,11 +744,11 @@ Remove a role from a user.
@param {String} userId
###
exports.removeUserRole = ( userId, role ) =>
@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,
replyHandler "Removing user '#{ userId }' from role '#{ role }'"
@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,
replyHandler "Removing user '#{ userId }' from role '#{ role }'"
###
@ -755,5 +757,5 @@ Shuts down the db link.
@public shutDown()
###
exports.shutDown = () =>
@db?.quit()
# @db?.end()
@db?.quit()
# @db?.end()

View file

@ -25,32 +25,32 @@ qs = require 'querystring'
# [crypto-js](https://github.com/evanvosberg/crypto-js)
mustache = require 'mustache'
crypto = require 'crypto-js'
# Prepare the user command handlers which are invoked via HTTP requests.
dirHandlers = path.resolve __dirname, '..', 'webpages', 'handlers'
exports = module.exports = ( args ) =>
@log = args.logger
@log = args.logger
# Register the request service
@userRequestHandler = args[ 'request-service' ]
# Register the request service
@userRequestHandler = args[ 'request-service' ]
# Register the shutdown handler to the admin command.
@objAdminCmds =
shutdown: ( obj, cb ) ->
data =
code: 200
message: 'Shutting down... BYE!'
setTimeout args[ 'shutdown-function' ], 500
cb null, data
db args
# Register the shutdown handler to the admin command.
@objAdminCmds =
shutdown: ( obj, cb ) ->
data =
code: 200
message: 'Shutting down... BYE!'
setTimeout args[ 'shutdown-function' ], 500
cb null, data
db args
# Load the standard users from the user config file
users = JSON.parse fs.readFileSync path.resolve __dirname, '..', 'config', 'users.json'
fStoreUser = ( username, oUser ) ->
oUser.username = username
db.storeUser oUser
fStoreUser user, oUser for user, oUser of users
module.exports
# Load the standard users from the user config file
users = JSON.parse fs.readFileSync path.resolve __dirname, '..', 'config', 'users.json'
fStoreUser = ( username, oUser ) ->
oUser.username = username
db.storeUser oUser
fStoreUser user, oUser for user, oUser of users
module.exports
###
@ -65,32 +65,32 @@ objects.*
@public handleEvent( *req, resp* )
###
exports.handleEvent = ( req, resp ) ->
body = ''
req.on 'data', ( data ) ->
body += data
body = ''
req.on 'data', ( data ) ->
body += data
req.on 'end', ->
#if req.session and req.session.user
try
obj = JSON.parse body
console.log 'got foreign event!'
console.log obj
catch err
resp.send 400, 'Badly formed event!'
# If required event properties are present we process the event #
if obj and obj.event and not err
timestamp = ( new Date ).toISOString()
rand = ( Math.floor Math.random() * 10e9 ).toString( 16 ).toUpperCase()
obj.eventid = "#{ obj.event }_#{ timestamp }_#{ rand }"
answ =
code: 200
message: "Thank you for the event: #{ obj.eventid }"
resp.send answ.code, answ
db.pushEvent obj
else
resp.send 400, 'Your event was missing important parameters!'
# else
# resp.send 401, 'Please login!'
req.on 'end', ->
#if req.session and req.session.user
try
obj = JSON.parse body
console.log 'got foreign event!'
console.log obj
catch err
resp.send 400, 'Badly formed event!'
# If required event properties are present we process the event #
if obj and obj.event and not err
timestamp = ( new Date ).toISOString()
rand = ( Math.floor Math.random() * 10e9 ).toString( 16 ).toUpperCase()
obj.eventid = "#{ obj.event }_#{ timestamp }_#{ rand }"
answ =
code: 200
message: "Thank you for the event: #{ obj.eventid }"
resp.send answ.code, answ
db.pushEvent obj
else
resp.send 400, 'Your event was missing important parameters!'
# else
# resp.send 401, 'Please login!'
@ -105,21 +105,21 @@ objects.*
@public handleLogin( *req, resp* )
###
exports.handleLogin = ( req, resp ) =>
body = ''
req.on 'data', ( data ) -> body += data
req.on 'end', =>
obj = JSON.parse body
db.loginUser obj.username, obj.password, ( err, usr ) =>
if err
# Tapping on fingers, at least in log...
@log.warn "RH | AUTH-UH-OH ( #{ obj.username } ): #{ err.message }"
else
# no error, so we can associate the user object from the DB to the session
req.session.user = usr
if req.session.user
resp.send 'OK!'
else
resp.send 401, 'NO!'
body = ''
req.on 'data', ( data ) -> body += data
req.on 'end', =>
obj = JSON.parse body
db.loginUser obj.username, obj.password, ( err, usr ) =>
if err
# Tapping on fingers, at least in log...
@log.warn "RH | AUTH-UH-OH ( #{ obj.username } ): #{ err.message }"
else
# no error, so we can associate the user object from the DB to the session
req.session.user = usr
if req.session.user
resp.send 'OK!'
else
resp.send 401, 'NO!'
###
A post request retrieved on this handler causes the user object to be
@ -133,9 +133,9 @@ objects.*
@public handleLogout( *req, resp* )
###
exports.handleLogout = ( req, resp ) ->
if req.session
req.session.user = null
resp.send 'Bye!'
if req.session
req.session.user = null
resp.send 'Bye!'
###
@ -145,7 +145,7 @@ Resolves the path to a handler webpage.
@param {String} name
###
getHandlerPath = ( name ) ->
path.join dirHandlers, name + '.html'
path.join dirHandlers, name + '.html'
###
Fetches a template.
@ -154,9 +154,9 @@ Fetches a template.
@param {String} name
###
getTemplate = ( name ) ->
pth = path.join dirHandlers, 'templates', name + '.html'
fs.readFileSync pth, 'utf8'
pth = path.join dirHandlers, 'templates', name + '.html'
fs.readFileSync pth, 'utf8'
###
Fetches a script.
@ -164,9 +164,9 @@ Fetches a script.
@param {String} name
###
getScript = ( name ) ->
pth = path.join dirHandlers, 'js', name + '.js'
fs.readFileSync pth, 'utf8'
pth = path.join dirHandlers, 'js', name + '.js'
fs.readFileSync pth, 'utf8'
###
Fetches remote scripts snippets.
@ -174,9 +174,9 @@ Fetches remote scripts snippets.
@param {String} name
###
getRemoteScripts = ( name ) ->
pth = path.join dirHandlers, 'remote-scripts', name + '.html'
fs.readFileSync pth, 'utf8'
pth = path.join dirHandlers, 'remote-scripts', name + '.html'
fs.readFileSync pth, 'utf8'
###
Renders a page, with helps of mustache, depending on the user session and returns it.
@ -186,46 +186,46 @@ Renders a page, with helps of mustache, depending on the user session and return
@param {Object} msg
###
renderPage = ( name, req, resp, msg ) ->
# Grab the skeleton
pathSkel = path.join dirHandlers, 'skeleton.html'
skeleton = fs.readFileSync pathSkel, 'utf8'
code = 200
data =
message: msg
user: req.session.user
# Grab the skeleton
pathSkel = path.join dirHandlers, 'skeleton.html'
skeleton = fs.readFileSync pathSkel, 'utf8'
code = 200
data =
message: msg
user: req.session.user
# Try to grab the script belonging to this page. But don't bother if it's not existing
try
script = getScript name
# Try to grab the remote scripts belonging to this page. But don't bother if it's not existing
try
remote_scripts = getRemoteScripts name
# Try to grab the script belonging to this page. But don't bother if it's not existing
try
script = getScript name
# Try to grab the remote scripts belonging to this page. But don't bother if it's not existing
try
remote_scripts = getRemoteScripts name
# Now try to find the page the user requested.
try
content = getTemplate name
catch err
# If the page doesn't exist we return the error page, load the error script into it
# and render the error page with some additional data
content = getTemplate 'error'
script = getScript 'error'
code = 404
data.message = 'Invalid Page!'
# Now try to find the page the user requested.
try
content = getTemplate name
catch err
# If the page doesn't exist we return the error page, load the error script into it
# and render the error page with some additional data
content = getTemplate 'error'
script = getScript 'error'
code = 404
data.message = 'Invalid Page!'
if req.session.user
menubar = getTemplate 'menubar'
if req.session.user
menubar = getTemplate 'menubar'
pageElements =
content: content
script: script
remote_scripts: remote_scripts
menubar: menubar
pageElements =
content: content
script: script
remote_scripts: remote_scripts
menubar: menubar
# First we render the page by including all page elements into the skeleton
page = mustache.render skeleton, pageElements
# First we render the page by including all page elements into the skeleton
page = mustache.render skeleton, pageElements
# Then we complete the rendering by adding the data, and send the result to the user
resp.send code, mustache.render page, data
# Then we complete the rendering by adding the data, and send the result to the user
resp.send code, mustache.render page, data
###
Present the desired forge page to the user.
@ -238,10 +238,10 @@ objects.*
@public handleForge( *req, resp* )
###
exports.handleForge = ( req, resp ) ->
page = req.query.page
if not req.session.user
page = 'login'
renderPage page, req, resp
page = req.query.page
if not req.session.user
page = 'login'
renderPage page, req, resp
###
Handles the user command requests.
@ -254,18 +254,18 @@ objects.*
@public handleUser( *req, resp* )
###
exports.handleUserCommand = ( req, resp ) =>
if req.session and req.session.user
body = ''
#Append data to body while receiving fragments
req.on 'data', ( data ) ->
body += data
req.on 'end', =>
obj = qs.parse body
# Let the user request handler service answer the request
@userRequestHandler req.session.user, obj, ( obj ) ->
resp.send obj.code, obj
else
resp.send 401, 'Login first!'
if req.session and req.session.user
body = ''
#Append data to body while receiving fragments
req.on 'data', ( data ) ->
body += data
req.on 'end', =>
obj = qs.parse body
# Let the user request handler service answer the request
@userRequestHandler req.session.user, obj, ( obj ) ->
resp.send obj.code, obj
else
resp.send 401, 'Login first!'
###
@ -279,15 +279,15 @@ objects.*
@public handleForge( *req, resp* )
###
exports.handleAdmin = ( req, resp ) ->
if not req.session.user
page = 'login'
#TODO isAdmin should come from the db role
else if req.session.user.isAdmin isnt "true"
page = 'login'
msg = 'You need to be admin!'
else
page = 'admin'
renderPage page, req, resp, msg
if not req.session.user
page = 'login'
#TODO isAdmin should come from the db role
else if req.session.user.isAdmin isnt "true"
page = 'login'
msg = 'You need to be admin!'
else
page = 'admin'
renderPage page, req, resp, msg
###
Handles the admin command requests.
@ -300,20 +300,20 @@ objects.*
@public handleAdminCommand( *req, resp* )
###
exports.handleAdminCommand = ( req, resp ) =>
if req.session and
req.session.user and
req.session.user.isAdmin is "true"
body = ''
req.on 'data', ( data ) ->
body += data
req.on 'end', =>
obj = qs.parse body
@log.info 'RH | Received admin request: ' + obj.command
if obj.command and @objAdminCmds[obj.command]
@objAdminCmds[obj.command] obj, ( err, obj ) ->
resp.send obj.code, obj
else
resp.send 404, 'Command unknown!'
else
resp.send 401, 'You need to be logged in as admin!'
if req.session and
req.session.user and
req.session.user.isAdmin is "true"
body = ''
req.on 'data', ( data ) ->
body += data
req.on 'end', =>
obj = qs.parse body
@log.info 'RH | Received admin request: ' + obj.command
if obj.command and @objAdminCmds[obj.command]
@objAdminCmds[obj.command] obj, ( err, obj ) ->
resp.send obj.code, obj
else
resp.send 404, 'Command unknown!'
else
resp.send 401, 'You need to be logged in as admin!'

View file

@ -51,69 +51,69 @@ Let's prepare the optimist CLI optional arguments `[opt]`:
usage = 'This runs your webapi-based ECA engine'
opt =
# `-h`, `--help`: Display the help
'h':
alias : 'help',
describe: 'Display this'
'h':
alias : 'help',
describe: 'Display this'
# `-c`, `--config-path`: Specify a path to a custom configuration file, other than "config/config.json"
'c':
alias : 'config-path',
describe: 'Specify a path to a custom configuration file, other than "config/config.json"'
'c':
alias : 'config-path',
describe: 'Specify a path to a custom configuration file, other than "config/config.json"'
# `-w`, `--http-port`: Specify a HTTP port for the web server
'w':
alias : 'http-port',
describe: 'Specify a HTTP port for the web server'
'w':
alias : 'http-port',
describe: 'Specify a HTTP port for the web server'
# `-d`, `--db-port`: Specify a port for the redis DB
'd':
alias : 'db-port',
describe: 'Specify a port for the redis DB'
'd':
alias : 'db-port',
describe: 'Specify a port for the redis DB'
# `-m`, `--log-mode`: Specify a log mode: [development|productive]
'm':
alias : 'log-mode',
describe: 'Specify a log mode: [development|productive]'
'm':
alias : 'log-mode',
describe: 'Specify a log mode: [development|productive]'
# `-i`, `--log-io-level`: Specify the log level for the I/O. in development expensive origin
# lookups are made and added to the log entries
'i':
alias : 'log-io-level',
describe: 'Specify the log level for the I/O'
'i':
alias : 'log-io-level',
describe: 'Specify the log level for the I/O'
# `-f`, `--log-file-level`: Specify the log level for the log file
'f':
alias : 'log-file-level',
describe: 'Specify the log level for the log file'
'f':
alias : 'log-file-level',
describe: 'Specify the log level for the log file'
# `-p`, `--log-file-path`: Specify the path to the log file within the "logs" folder
'p':
alias : 'log-file-path',
describe: 'Specify the path to the log file within the "logs" folder'
'p':
alias : 'log-file-path',
describe: 'Specify the path to the log file within the "logs" folder'
# `-n`, `--nolog`: Set this true if no output shall be generated
'n':
alias : 'nolog',
describe: 'Set this if no output shall be generated'
'n':
alias : 'nolog',
describe: 'Set this if no output shall be generated'
# now fetch the CLI arguments and exit if the help has been called.
argv = optimist.usage( usage ).options( opt ).argv
if argv.help
console.log optimist.help()
process.exit()
console.log optimist.help()
process.exit()
conf argv.c
# > Check whether the config file is ready, which is required to start the server.
if !conf.isReady()
console.error 'FAIL: Config file not ready! Shutting down...'
process.exit()
console.error 'FAIL: Config file not ready! Shutting down...'
process.exit()
logconf = conf.getLogConf()
if argv.m
logconf[ 'mode' ] = argv.m
logconf[ 'mode' ] = argv.m
if argv.i
logconf[ 'io-level' ] = argv.i
logconf[ 'io-level' ] = argv.i
if argv.f
logconf[ 'file-level' ] = argv.f
logconf[ 'file-level' ] = argv.f
if argv.p
logconf[ 'file-path' ] = argv.p
logconf[ 'file-path' ] = argv.p
if argv.n
logconf[ 'nolog' ] = true
logconf[ 'nolog' ] = true
try
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
@log = logger.getLogger logconf
@log.info 'RS | STARTING SERVER'
@ -124,80 +124,81 @@ This function is invoked right after the module is loaded and starts the server.
###
init = =>
args =
logger: @log
logconf: logconf
# > Fetch the `http-port` argument
args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort()
args[ 'db-port' ] = parseInt argv.d || conf.getDbPort()
args =
logger: @log
logconf: logconf
# > Fetch the `http-port` argument
args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort()
args[ 'db-port' ] = parseInt argv.d || conf.getDbPort()
#FIXME this has to come from user input for security reasons:
args[ 'keygen' ] = conf.getKeygenPassphrase()
@log.info 'RS | Initialzing DB'
db args
# > We only proceed with the initialization if the DB is ready
#TODO eventually we shouldn't let each module load its own persistence
#module, but hand this one through them via the args...
db.isConnected ( err ) =>
if err
@log.error 'RS | No DB connection, shutting down system!'
shutDown()
#FIXME this has to come from user input for security reasons:
args[ 'keygen' ] = conf.getKeygenPassphrase()
args[ 'webhooks' ] = conf.fetchProp 'webhooks'
@log.info 'RS | Initialzing DB'
db args
# > We only proceed with the initialization if the DB is ready
#TODO eventually we shouldn't let each module load its own persistence
#module, but hand this one through them via the args...
db.isConnected ( err ) =>
if err
@log.error 'RS | No DB connection, shutting down system!'
shutDown()
else
# > Initialize all required modules with the args object.
@log.info 'RS | Initialzing engine'
#TODO We could in the future make the engine a child process as well
engine args
# Start the event poller. The module manager will emit events for it
@log.info 'RS | Forking a child process for the event poller'
# Grab all required log config fields
cliArgs = [
# - the log mode: [development|productive], in development expensive origin
# lookups are made and added to the log entries
args.logconf[ 'mode' ]
# - the I/O log level, refer to logging.coffee for the different levels
args.logconf[ 'io-level' ]
# - the file log level, refer to logging.coffee for the different levels
args.logconf[ 'file-level' ]
# - the optional path to the log file
args.logconf[ 'file-path' ]
# - whether a log file shall be written at all [true|false]
args.logconf[ 'nolog' ]
# - The keygen phrase, this has to be handled differently in the future!
args[ 'keygen' ]
]
poller = cp.fork path.resolve( __dirname, nameEP ), cliArgs
else
# > Initialize all required modules with the args object.
@log.info 'RS | Initialzing engine'
#TODO We could in the future make the engine a child process as well
engine args
# Start the event poller. The module manager will emit events for it
@log.info 'RS | Forking a child process for the event poller'
# Grab all required log config fields
cliArgs = [
# - the log mode: [development|productive], in development expensive origin
# lookups are made and added to the log entries
args.logconf[ 'mode' ]
# - the I/O log level, refer to logging.coffee for the different levels
args.logconf[ 'io-level' ]
# - the file log level, refer to logging.coffee for the different levels
args.logconf[ 'file-level' ]
# - the optional path to the log file
args.logconf[ 'file-path' ]
# - whether a log file shall be written at all [true|false]
args.logconf[ 'nolog' ]
# - The keygen phrase, this has to be handled differently in the future!
args[ 'keygen' ]
]
poller = cp.fork path.resolve( __dirname, nameEP ), cliArgs
# after the engine and the event poller have been initialized we can
# initialize the module manager and register event listener functions
# from engine and event poller
@log.info 'RS | Initialzing module manager'
cm args
cm.addRuleListener engine.internalEvent
cm.addRuleListener ( evt ) -> poller.send evt
# after the engine and the event poller have been initialized we can
# initialize the module manager and register event listener functions
# from engine and event poller
@log.info 'RS | Initialzing module manager'
cm args
cm.addRuleListener engine.internalEvent
cm.addRuleListener ( evt ) -> poller.send evt
@log.info 'RS | Initialzing http listener'
# The request handler passes certain requests to the module manager
args[ 'request-service' ] = cm.processRequest
# We give the HTTP listener the ability to shutdown the whole system
args[ 'shutdown-function' ] = shutDown
http args
@log.info 'RS | Initialzing http listener'
# The request handler passes certain requests to the module manager
args[ 'request-service' ] = cm.processRequest
# We give the HTTP listener the ability to shutdown the whole system
args[ 'shutdown-function' ] = shutDown
http args
###
Shuts down the server.
@private shutDown()
###
shutDown = () =>
@log.warn 'RS | Received shut down command!'
db?.shutDown()
engine.shutDown()
# We need to call process.exit() since the express server in the http-listener
# can't be stopped gracefully. Why would you stop this system anyways!??
process.exit()
@log.warn 'RS | Received shut down command!'
db?.shutDown()
engine.shutDown()
# We need to call process.exit() since the express server in the http-listener
# can't be stopped gracefully. Why would you stop this system anyways!??
process.exit()
###
## Process Commands

View file

@ -8,5 +8,8 @@
"file-level": "info",
"file-path": "logs/server.log"
},
"webhooks": [
"github"
],
"keygen-passphrase": "[TODO this has to come from prompt when server is started!]"
}

View file

@ -1,3 +1,5 @@
###
ProBinder ACTION INVOKER
------------------------
@ -6,8 +8,6 @@ Global variables
This module requires user-specific parameters:
- username
- password
- companyId: company where to post the binder entries
- contextId: context where to post the binder entries
###
urlService = 'https://probinder.com/service/'
credentials =
@ -44,50 +44,45 @@ callService = ( args ) ->
if not args.callback
args.callback = standardCallback 'call'
url = urlService + args.service + '/' + args.method
needlereq 'post', url, args.data, credentials, args.callback
needle.request 'post', url, args.data, credentials, args.callback
###
Does everything to post something in a binder
@param {Object} args the object containing the content
@param {String} args.content the content to be posted
@param {String} companyId the comany associated to the binder
@param {String} contextId the binder id
@param {String} content the content to be posted
###
exports.newContent = ( args ) ->
if not args.callback
args.callback = standardCallback 'newContent'
exports.newContent = ( companyId, contextId, content ) ->
if arguments[ 4 ]
callback = arguments[ 4 ]
else
callback = standardCallback 'newContent'
callService
service: '27'
method: 'save'
data:
companyId: params.companyId
context: params.contextId
text: args.content
callback: args.callback
companyId: companyId
context: contextId
text: content
callback: callback
###
Does everything to post a file info in a binder tabe
Does everything to post a file info in a binder tab
@param {Object} args the object containing the content
@param {String} args.service the content service
@param {String} args.id the content id
@param {String} fromService the content service which grabs the content
@param {String} fromId the content id from which the information is grabbed
###
exports.makeFileEntry = ( args ) ->
if not args.callback
args.callback = standardCallback 'makeFileEntry'
exports.makeFileEntry = ( fromService, fromId, toCompany, toContext ) ->
getContent
serviceid: args.service
contentid: args.id
serviceid: fromService
contentid: fromId
callback: ( err, resp, body ) ->
callService
service: '27'
method: 'save'
data:
companyId: params.companyId
context: params.contextId
text: "New file (#{ body.title }) in tab \"#{ body.context[0].name }\",
find it <a href=\"https://probinder.com/file/#{ body.fileIds[0] }\">here</a>!'"
callback: args.callback
content = "New file (#{ body.title }) in tab \"#{ body.context[0].name }\",
find it here!'"
exports.newContent toCompanyId, toContextId, content, standardCallback 'makeFileEntry'
###
Calls the content get service with the content id and the service id provided.
@ -112,15 +107,12 @@ getContent = ( args ) ->
###
Sets the content as read.
@param {Object} args the object containing the content
@param {String} args.content the content to be posted
@param {Object} id the content id to be set to read.
###
exports.setRead = ( args ) ->
if not args.callback
args.callback = standardCallback 'setRead'
exports.setRead = ( id ) ->
callService
service: '2'
method: 'setread'
data:
id: args.id
callback: args.callback
id: id
callback: standardCallback 'setRead'

View file

@ -18,26 +18,7 @@ cs = require 'coffee-script'
needle = require 'needle'
crypto = require 'crypto-js'
request = require 'request'
issueApiCall = ( method, url, data, options, cb ) ->
try
needle.request method, url, data, options, ( err, resp, body ) =>
try
cb err, resp, body
catch err
console.log 'Error during needle request! ' + err.message
catch err
console.log 'Error before needle request! ' + err.message
issueRequest = ( options, cb ) ->
try
request options, ( err, resp, body ) =>
try
cb err, resp, body
catch err
console.log 'Error during request! ' + err.message
catch err
console.log 'Error before request! ' + err.message
importio = require( 'import-io' ).client
params = JSON.parse fs.readFileSync 'params.json', 'utf8'
code = fs.readFileSync process.argv[ 2 ], 'utf8'
@ -46,9 +27,10 @@ src = cs.compile code
sandbox =
id: 'test.vm'
params: params.userparams
needlereq: issueApiCall
request: issueRequest
needle: needle
request: request
cryptoJS: crypto
importio: importio
log: console.log
debug: console.log
exports: {}

View file

@ -9,7 +9,7 @@ compilation and running of module code
*/
(function() {
var code, crypto, cs, fs, issueApiCall, issueRequest, needle, params, request, sandbox, src, vm;
var code, crypto, cs, fs, importio, needle, params, request, sandbox, src, vm;
if (!process.argv[2]) {
console.log('Please provide a path to a coffee file');
@ -28,43 +28,7 @@ compilation and running of module code
request = require('request');
issueApiCall = function(method, url, data, options, cb) {
var err;
try {
return needle.request(method, url, data, options, (function(_this) {
return function(err, resp, body) {
try {
return cb(err, resp, body);
} catch (_error) {
err = _error;
return console.log('Error during needle request! ' + err.message);
}
};
})(this));
} catch (_error) {
err = _error;
return console.log('Error before needle request! ' + err.message);
}
};
issueRequest = function(options, cb) {
var err;
try {
return request(options, (function(_this) {
return function(err, resp, body) {
try {
return cb(err, resp, body);
} catch (_error) {
err = _error;
return console.log('Error during request! ' + err.message);
}
};
})(this));
} catch (_error) {
err = _error;
return console.log('Error before request! ' + err.message);
}
};
importio = require('import-io').client;
params = JSON.parse(fs.readFileSync('params.json', 'utf8'));
@ -75,9 +39,10 @@ compilation and running of module code
sandbox = {
id: 'test.vm',
params: params.userparams,
needlereq: issueApiCall,
request: issueRequest,
needle: needle,
request: request,
cryptoJS: crypto,
importio: importio,
log: console.log,
debug: console.log,
exports: {}

View file

@ -103,8 +103,8 @@ Components Manager
- `user` is the user object as it comes from the DB.
- `oReq` is the request object that contains:
- `command` as a string
- `payload` an optional stringified JSON object
- `command` as a string
- `payload` an optional stringified JSON object
The callback function `callback( obj )` will receive an object
containing the HTTP response code and a corresponding message.
@ -239,6 +239,7 @@ Components Manager
src = oPayload.data;
return dynmod.compileString(src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, function(cm) {
var funcs, id, name, _ref;
console.log(cm);
answ = cm.answ;
if (answ.code === 200) {
funcs = [];
@ -250,7 +251,7 @@ Components Manager
_this.log.info("CM | Storing new module with functions " + (funcs.join(', ')));
answ.message = " Module " + oPayload.id + " successfully stored! Found following function(s): " + funcs;
oPayload.functions = JSON.stringify(funcs);
oPayload.functionParameters = JSON.stringify(cm.funcParams);
oPayload.functionArgs = JSON.stringify(cm.funcParams);
dbMod.storeModule(user.username, oPayload);
if (oPayload["public"] === 'true') {
dbMod.publish(oPayload.id);
@ -327,7 +328,7 @@ Components Manager
if (answ.code !== 200) {
return callback(answ);
} else {
return db.actionInvokers.getModuleField(oPayload.id, 'functionParameters', function(err, obj) {
return db.actionInvokers.getModuleField(oPayload.id, 'functionArgs', function(err, obj) {
return callback({
code: 200,
message: obj
@ -390,6 +391,7 @@ Components Manager
rule = {
id: oPayload.id,
event: oPayload.event,
event_interval: oPayload.event_interval,
conditions: oPayload.conditions,
actions: oPayload.actions
};

View file

@ -8,7 +8,7 @@ Configuration
*/
(function() {
var exports, fetchProp, fs, loadConfigFile, path;
var exports, fs, loadConfigFile, path;
fs = require('fs');
@ -85,7 +85,7 @@ Configuration
@param {String} prop
*/
fetchProp = (function(_this) {
exports.fetchProp = (function(_this) {
return function(prop) {
var _ref;
return (_ref = _this.config) != null ? _ref[prop] : void 0;
@ -113,7 +113,7 @@ Configuration
*/
exports.getHttpPort = function() {
return fetchProp('http-port');
return exports.fetchProp('http-port');
};
@ -124,7 +124,7 @@ Configuration
*/
exports.getDbPort = function() {
return fetchProp('db-port');
return exports.fetchProp('db-port');
};
@ -135,7 +135,7 @@ Configuration
*/
exports.getLogConf = function() {
return fetchProp('log');
return exports.fetchProp('log');
};
@ -146,7 +146,7 @@ Configuration
*/
exports.getKeygenPassphrase = function() {
return fetchProp('keygen-passphrase');
return exports.fetchProp('keygen-passphrase');
};
}).call(this);

View file

@ -9,7 +9,7 @@ Dynamic Modules
*/
(function() {
var cryptico, cryptoJS, cs, db, exports, getFunctionParamNames, logFunction, needle, regexpComments, request, vm;
var cryptico, cryptoJS, cs, db, exports, fTryToLoadModule, getFunctionParamNames, importio, logFunction, needle, regexpComments, request, vm;
db = require('./persistence');
@ -25,6 +25,8 @@ Dynamic Modules
cryptoJS = require('crypto-js');
importio = require('import-io').client;
/*
Module call
@ -89,99 +91,114 @@ Dynamic Modules
exports.compileString = (function(_this) {
return function(src, userId, ruleId, modId, lang, dbMod, cb) {
var answ, err, fTryToLoad;
answ = {
code: 200,
message: 'Successfully compiled'
};
var err;
if (lang === 'CoffeeScript') {
try {
_this.log.info("DM | Compiling module '" + modId + "' for user '" + userId + "'");
src = cs.compile(src);
} catch (_error) {
err = _error;
answ.code = 400;
answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line;
cb({
code: 400,
message: 'Compilation of CoffeeScript failed at line ' + err.location.first_line
});
return;
}
}
fTryToLoad = function(params) {
var fName, func, logFunc, msg, oDecrypted, oFuncArgs, oFuncParams, sandbox, _ref;
if (params) {
_this.log.info("DM | Trying to fetch user specific module '" + modId + "' paramters for user '" + userId + "'");
if (dbMod) {
return dbMod.getUserParams(modId, userId, function(err, obj) {
var oDecrypted;
try {
oDecrypted = cryptico.decrypt(params, _this.oPrivateRSAkey);
params = JSON.parse(oDecrypted.plaintext);
oDecrypted = cryptico.decrypt(obj, _this.oPrivateRSAkey);
obj = JSON.parse(oDecrypted.plaintext);
_this.log.warn("DM | Loaded user defined params for " + userId + ", " + ruleId + ", " + modId);
} catch (_error) {
err = _error;
_this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId);
_this.log.warn(err);
params = {};
}
} else {
params = {};
}
logFunc = logFunction(userId, ruleId, modId);
sandbox = {
id: userId + '.' + modId + '.vm',
params: params,
needle: needle,
request: request,
cryptoJS: cryptoJS,
log: logFunc,
debug: console.log,
exports: {}
};
try {
vm.runInNewContext(src, sandbox, sandbox.id);
} catch (_error) {
err = _error;
answ.code = 400;
msg = err.message;
if (!msg) {
msg = 'Try to run the script locally to track the error! Sadly we cannot provide the line number';
}
answ.message = 'Loading Module failed: ' + msg;
}
oFuncParams = {};
_ref = sandbox.exports;
for (fName in _ref) {
func = _ref[fName];
getFunctionParamNames(fName, func, oFuncParams);
}
if (dbMod) {
oFuncArgs = {};
console.log('oFuncParams');
console.log(oFuncParams);
for (func in oFuncParams) {
console.log('fetching ' + func);
console.log(typeof func);
dbMod.getUserArguments(modId, func, userId, function(err, obj) {
console.log(err, obj);
try {
oDecrypted = cryptico.decrypt(obj, _this.oPrivateRSAkey);
return oFuncArgs[func] = JSON.parse(oDecrypted.plaintext);
} catch (_error) {
err = _error;
_this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId);
return _this.log.warn(err);
}
});
}
}
return cb({
answ: answ,
module: sandbox.exports,
funcParams: oFuncParams,
funcArgs: oFuncArgs,
logger: sandbox.log
});
};
if (dbMod) {
return dbMod.getUserParams(modId, userId, function(err, obj) {
return fTryToLoad(obj);
return fTryToLoadModule(userId, ruleId, modId, src, dbMod, obj, cb);
});
} else {
return fTryToLoad(null);
return fTryToLoadModule(userId, ruleId, modId, src, dbMod, null, cb);
}
};
})(this);
fTryToLoadModule = (function(_this) {
return function(userId, ruleId, modId, src, dbMod, params, cb) {
var answ, err, fName, func, logFunc, msg, oFuncArgs, oFuncParams, sandbox, _ref;
if (!params) {
params = {};
answ = {
code: 200,
message: 'Successfully compiled'
};
}
_this.log.info("DM | Running module '" + modId + "' for user '" + userId + "'");
logFunc = logFunction(userId, ruleId, modId);
sandbox = {
id: "" + userId + "." + ruleId + "." + modId + ".vm",
params: params,
needle: needle,
importio: importio,
request: request,
cryptoJS: cryptoJS,
log: logFunc,
debug: console.log,
exports: {}
};
try {
vm.runInNewContext(src, sandbox, sandbox.id);
} catch (_error) {
err = _error;
answ.code = 400;
msg = err.message;
if (!msg) {
msg = 'Try to run the script locally to track the error! Sadly we cannot provide the line number';
}
answ.message = 'Loading Module failed: ' + msg;
}
_this.log.info("DM | Module '" + modId + "' ran successfully for user '" + userId + "' in rule '" + ruleId + "'");
oFuncParams = {};
oFuncArgs = {};
_ref = sandbox.exports;
for (fName in _ref) {
func = _ref[fName];
getFunctionParamNames(fName, func, oFuncParams);
}
if (dbMod) {
oFuncArgs = {};
console.log('oFuncParams');
console.log(oFuncParams);
for (func in oFuncParams) {
console.log('fetching ' + func);
console.log(typeof func);
dbMod.getUserArguments(modId, func, userId, function(err, obj) {
var oDecrypted;
console.log(err, obj);
try {
oDecrypted = cryptico.decrypt(obj, _this.oPrivateRSAkey);
return oFuncArgs[func] = JSON.parse(oDecrypted.plaintext);
} catch (_error) {
err = _error;
_this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId);
return _this.log.warn(err);
}
});
}
}
console.log('answering compile request string');
console.log(cb);
return cb({
answ: answ,
module: sandbox.exports,
funcParams: oFuncParams,
funcArgs: oFuncArgs,
logger: sandbox.log
});
};
})(this);
}).call(this);

View file

@ -10,7 +10,7 @@ Engine
*/
(function() {
var db, dynmod, exports, isRunning, jsonQuery, listUserRules, pollQueue, processEvent, semaphore, updateActionModules, validConditions;
var db, dynmod, exports, isRunning, jsonQuery, listUserRules, numExecutingFunctions, pollQueue, processEvent, updateActionModules, validConditions;
db = require('./persistence');
@ -23,21 +23,21 @@ Engine
This is ging to have a structure like:
An object of users with their active rules and the required action modules
"user-1":
"rule-1":
"rule": oRule-1
"actions":
"action-1": oAction-1
"action-2": oAction-2
"rule-2":
"rule": oRule-2
"actions":
"action-1": oAction-1
"user-2":
"rule-3":
"rule": oRule-3
"actions":
"action-3": oAction-3
"user-1":
"rule-1":
"rule": oRule-1
"actions":
"action-1": oAction-1
"action-2": oAction-2
"rule-2":
"rule": oRule-2
"actions":
"action-1": oAction-1
"user-2":
"rule-3":
"rule": oRule-3
"actions":
"action-3": oAction-3
*/
listUserRules = {};
@ -126,87 +126,92 @@ Engine
@param {Object} updatedRuleId
*/
updateActionModules = function(updatedRuleId) {
var fAddRequired, fRemoveNotRequired, name, oUser, userName, _results;
fRemoveNotRequired = function(oUser) {
var action, fRequired, _results;
fRequired = function(actionName) {
var action, _i, _len, _ref;
_ref = oUser[updatedRuleId].rule.actions;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
if ((action.split(' -> '))[0] === actionName) {
return true;
}
}
return false;
};
_results = [];
for (action in oUser[updatedRuleId].rule.actions) {
if (!fRequired(action)) {
_results.push(delete oUser[updatedRuleId].actions[action]);
} else {
_results.push(void 0);
}
}
return _results;
};
for (name in listUserRules) {
oUser = listUserRules[name];
fRemoveNotRequired(oUser);
}
fAddRequired = function(userName, oUser) {
var fCheckRules, nmRl, oRl, _results;
fCheckRules = function(oMyRule) {
var action, fAddIfNewOrNotExisting, _i, _len, _ref, _results;
fAddIfNewOrNotExisting = function(actionName) {
var moduleName;
moduleName = (actionName.split(' -> '))[0];
if (!oMyRule.actions[moduleName] || oMyRule.rule.id === updatedRuleId) {
return db.actionInvokers.getModule(moduleName, function(err, obj) {
return dynmod.compileString(obj.data, userName, oMyRule.rule.id, moduleName, obj.lang, db.actionInvokers, function(result) {
if (!result.answ === 200) {
this.log.error("EN | Compilation of code failed! " + userName + ", " + oMyRule.rule.id + ", " + moduleName);
}
return oMyRule.actions[moduleName] = result.module;
});
});
updateActionModules = (function(_this) {
return function(updatedRuleId) {
var fAddRequired, fRemoveNotRequired, name, oUser, userName, _results;
fRemoveNotRequired = function(oUser) {
var action, fRequired, _results;
fRequired = function(actionName) {
var action, _i, _len, _ref;
_ref = oUser[updatedRuleId].rule.actions;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
if ((action.split(' -> '))[0] === actionName) {
return true;
}
}
return false;
};
_ref = oMyRule.rule.actions;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
_results.push(fAddIfNewOrNotExisting(action));
for (action in oUser[updatedRuleId].rule.actions) {
if (!fRequired(action)) {
_results.push(delete oUser[updatedRuleId].actions[action]);
} else {
_results.push(void 0);
}
}
return _results;
};
for (name in listUserRules) {
oUser = listUserRules[name];
fRemoveNotRequired(oUser);
}
fAddRequired = function(userName, oUser) {
var fCheckRules, nmRl, oRl, _results;
fCheckRules = function(oMyRule) {
var action, fAddIfNewOrNotExisting, _i, _len, _ref, _results;
fAddIfNewOrNotExisting = function(actionName) {
var moduleName;
moduleName = (actionName.split(' -> '))[0];
if (!oMyRule.actions[moduleName] || oMyRule.rule.id === updatedRuleId) {
return db.actionInvokers.getModule(moduleName, function(err, obj) {
if (obj) {
return dynmod.compileString(obj.data, userName, oMyRule.rule.id, moduleName, obj.lang, db.actionInvokers, function(result) {
if (!result.answ === 200) {
_this.log.error("EN | Compilation of code failed! " + userName + ", " + oMyRule.rule.id + ", " + moduleName);
}
return oMyRule.actions[moduleName] = result.module;
});
} else {
return _this.log.warn('EN | #{ moduleName } not found for #{ oMyRule.rule.id }!');
}
});
}
};
_ref = oMyRule.rule.actions;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
_results.push(fAddIfNewOrNotExisting(action));
}
return _results;
};
_results = [];
for (nmRl in oUser) {
oRl = oUser[nmRl];
_results.push(fCheckRules(oRl));
}
return _results;
};
_results = [];
for (nmRl in oUser) {
oRl = oUser[nmRl];
_results.push(fCheckRules(oRl));
for (userName in listUserRules) {
oUser = listUserRules[userName];
_results.push(fAddRequired(userName, oUser));
}
return _results;
};
_results = [];
for (userName in listUserRules) {
oUser = listUserRules[userName];
_results.push(fAddRequired(userName, oUser));
}
return _results;
};
})(this);
semaphore = 0;
numExecutingFunctions = 1;
pollQueue = function() {
if (isRunning) {
db.popEvent(function(err, obj) {
if (!err && obj) {
processEvent(obj);
return processEvent(obj);
}
return semaphore--;
});
return setTimeout(pollQueue, 20 * semaphore);
return setTimeout(pollQueue, 20 * numExecutingFunctions);
}
};
@ -234,8 +239,6 @@ Engine
return true;
};
semaphore = 0;
/*
Handles retrieved events.
@ -250,20 +253,22 @@ Engine
fSearchAndInvokeAction = function(node, arrPath, funcName, evt, depth) {
var err;
if (!node) {
this.log.error("EN | Didn't find property in user rule list: " + arrPath.join(', ' + " at depth " + depth));
_this.log.error("EN | Didn't find property in user rule list: " + arrPath.join(', ' + " at depth " + depth));
return;
}
if (depth === arrPath.length) {
try {
semaphore++;
numExecutingFunctions++;
_this.log.info("EN | " + funcName + " executes...");
node[funcName](evt.payload);
_this.log.info("EN | " + funcName + " finished execution");
} catch (_error) {
err = _error;
this.log.info("EN | ERROR IN ACTION INVOKER: " + err.message);
_this.log.info("EN | ERROR IN ACTION INVOKER: " + err.message);
node.logger(err.message);
}
if (semaphore-- % 100 === 0) {
return this.log.warn("EN | The system is producing too many tokens! Currently: " + semaphore);
if (numExecutingFunctions-- % 100 === 0) {
return _this.log.warn("EN | The system is producing too many tokens! Currently: " + numExecutingFunctions);
}
} else {
return fSearchAndInvokeAction(node[arrPath[depth]], arrPath, funcName, evt, depth + 1);

View file

@ -9,7 +9,7 @@ Dynamic Modules
*/
(function() {
var db, dynmod, fLoadModule, isRunning, listUserModules, log, logconf, logger, pollLoop;
var db, dynmod, fCallFunction, fCheckAndRun, fLoadModule, isRunning, listUserModules, log, logconf, logger;
logger = require('./logging');
@ -77,19 +77,23 @@ Dynamic Modules
return log.warn("EP | Strange... no module retrieved: " + arrName[0]);
} else {
return dynmod.compileString(obj.data, msg.user, msg.rule.id, arrName[0], obj.lang, db.eventPollers, function(result) {
var iv;
if (!result.answ === 200) {
log.error("EP | Compilation of code failed! " + msg.user + ", " + msg.rule.id + ", " + arrName[0]);
}
if (!listUserModules[msg.user]) {
listUserModules[msg.user] = {};
}
iv = msg.rule.interval * 60 * 1000;
listUserModules[msg.user][msg.rule.id] = {
id: msg.rule.event,
pollfunc: arrName[1],
interval: iv,
module: result.module,
logger: result.logger
};
return log.info("EP | New event module loaded! " + msg.user + ", " + msg.rule.id + ", " + arrName[0]);
log.info("EP | New event module '" + arrName[0] + "' loaded for user " + msg.user + ", in rule " + msg.rule.id + ", polling every " + iv + " minutes");
return setTimeout(fCheckAndRun(msg.user, msg.rule.id), iv);
});
}
});
@ -99,43 +103,32 @@ Dynamic Modules
}
};
/*
This function will loop infinitely every 10 seconds until isRunning is set to false
@private pollLoop()
*/
pollLoop = function() {
var fCallFunction, myRule, oRules, ruleName, userName;
if (isRunning) {
for (userName in listUserModules) {
oRules = listUserModules[userName];
for (ruleName in oRules) {
myRule = oRules[ruleName];
fCallFunction = function(oRule, ruleId, userId) {
var err;
try {
return oRule.module[oRule.pollfunc](function(obj) {
return db.pushEvent({
event: oRule.id,
eventid: "polled " + oRule.id + " " + userId + "_" + ((new Date).toISOString()),
payload: obj
});
});
} catch (_error) {
err = _error;
log.info("EP | ERROR in module when polled: " + oRule.id + " " + userId + ": " + err.message);
return oRule.logger(err.message);
}
};
fCallFunction(myRule, ruleName, userName);
}
fCheckAndRun = function(userId, ruleId) {
return function() {
var oRule;
if (isRunning && listUserModules[userId] && listUserModules[userId][ruleId]) {
oRule = listUserModules[userId][ruleId];
fCallFunction(userId, ruleId, oRule);
return setTimeout(fCheckAndRun(userId, ruleId), oRule.interval);
}
return setTimeout(pollLoop, 10000);
};
};
fCallFunction = function(userId, ruleId, oRule) {
var err;
try {
return oRule.module[oRule.pollfunc](function(obj) {
return db.pushEvent({
event: oRule.id,
eventid: "polled " + oRule.id + " " + userId + "_" + ((new Date).toISOString()),
payload: obj
});
});
} catch (_error) {
err = _error;
log.info("EP | ERROR in module when polled: " + oRule.id + " " + userId + ": " + err.message);
return oRule.logger(err.message);
}
};
pollLoop();
}).call(this);

View file

@ -10,7 +10,7 @@ HTTP Listener
*/
(function() {
var app, exports, express, initRouting, path, qs, requestHandler;
var activateWebHook, app, exports, express, indexEvent, initRouting, path, qs, requestHandler;
requestHandler = require('./request-handler');
@ -34,6 +34,7 @@ HTTP Listener
exports = module.exports = (function(_this) {
return function(args) {
_this.log = args.logger;
_this.arrWebhooks = args.webhooks;
_this.shutDownSystem = args['shutdown-function'];
requestHandler(args);
initRouting(args['http-port']);
@ -41,6 +42,39 @@ HTTP Listener
};
})(this);
indexEvent = function(event, body, resp) {
var err, obj, rand, timestamp;
try {
obj = JSON.parse(body);
timestamp = (new Date).toISOString();
rand = (Math.floor(Math.random() * 10e9)).toString(16).toUpperCase();
obj.event = event;
obj.eventid = "" + obj.event + "_" + timestamp + "_" + rand;
db.pushEvent(obj);
return resp.send(200, "Thank you for the event: " + obj.eventid);
} catch (_error) {
err = _error;
return resp.send(400, 'Badly formed event!');
}
};
activateWebHook = (function(_this) {
return function(app, name) {
_this.log.info("HL | Webhook activated for " + name);
return app.post("/webhooks/" + name, function(req, resp) {
var body;
console.log('something is coming through');
body = '';
req.on('data', function(data) {
return body += data;
});
return req.on('end', function() {
return indexEvent(name, body, resp);
});
});
};
})(this);
/*
Initializes the request routing and starts listening on the given port.
@ -51,7 +85,7 @@ HTTP Listener
initRouting = (function(_this) {
return function(port) {
var server, sess_sec;
var hookName, server, sess_sec, _i, _len, _ref;
app.use(express.cookieParser());
sess_sec = "149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw";
app.use(express.session({
@ -66,6 +100,11 @@ HTTP Listener
app.post('/logout', requestHandler.handleLogout);
app.post('/usercommand', requestHandler.handleUserCommand);
app.post('/admincommand', requestHandler.handleAdminCommand);
_ref = _this.arrWebhooks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
hookName = _ref[_i];
activateWebHook(app, hookName);
}
server = app.listen(parseInt(port) || 8111);
server.on('listening', function() {
var addr;
@ -77,8 +116,8 @@ HTTP Listener
return server.on('error', function(err) {
/*
Error handling of the express port listener requires special attention,
thus we have to catch the error, which is issued if the port is already in use.
Error handling of the express port listener requires special attention,
thus we have to catch the error, which is issued if the port is already in use.
*/
switch (err.errno) {
case 'EADDRINUSE':

View file

@ -69,7 +69,9 @@ Persistence
_this.db.on('error', function(err) {
if (err.message.indexOf('ECONNREFUSED') > -1) {
_this.connRefused = true;
return _this.log.error(err, 'DB | Wrong port?');
return _this.log.warn('DB | Wrong port?');
} else {
return _this.log.error(err);
}
});
exports.eventPollers.setDB(_this.db);
@ -200,9 +202,9 @@ Persistence
@private getSetRecords( *set, fSingle, cb* )
@param {String} set the set name how it is stored in the DB
@param {function} fSingle a function to retrieve a single data element
per set entry
per set entry
@param {function} cb the callback(err, obj) function that receives all
the retrieved data or an error
the retrieved data or an error
*/
getSetRecords = (function(_this) {
@ -282,11 +284,11 @@ Persistence
/*
Stores a module and links it to the user.
@private storeModule( *userId, oModule* )
@param {String} userId
@param {object} oModule
Stores a module and links it to the user.
@private storeModule( *userId, oModule* )
@param {String} userId
@param {object} oModule
*/
IndexedModules.prototype.storeModule = function(userId, oModule) {
@ -376,13 +378,13 @@ Persistence
/*
Stores user params for a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserParams( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
Stores user params for a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserParams( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
*/
IndexedModules.prototype.storeUserParams = function(mId, userId, encData) {
@ -409,13 +411,13 @@ Persistence
/*
Stores user arguments for a function within a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserArguments( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
Stores user arguments for a function within a module. They are expected to be RSA encrypted with helps of
the provided cryptico JS library and will only be decrypted right before the module is loaded!
@private storeUserArguments( *mId, userId, encData* )
@param {String} mId
@param {String} userId
@param {object} encData
*/
IndexedModules.prototype.storeUserArguments = function(mId, funcId, userId, encData) {

View file

@ -78,28 +78,26 @@ Request Handler
});
return req.on('end', function() {
var answ, err, obj, rand, timestamp;
if (req.session && req.session.user) {
try {
obj = JSON.parse(body);
} catch (_error) {
err = _error;
resp.send(400, 'Badly formed event!');
}
if (obj && obj.event && !err) {
timestamp = (new Date).toISOString();
rand = (Math.floor(Math.random() * 10e9)).toString(16).toUpperCase();
obj.eventid = "" + obj.event + "_" + timestamp + "_" + rand;
answ = {
code: 200,
message: "Thank you for the event: " + obj.eventid
};
resp.send(answ.code, answ);
return db.pushEvent(obj);
} else {
return resp.send(400, 'Your event was missing important parameters!');
}
try {
obj = JSON.parse(body);
console.log('got foreign event!');
console.log(obj);
} catch (_error) {
err = _error;
resp.send(400, 'Badly formed event!');
}
if (obj && obj.event && !err) {
timestamp = (new Date).toISOString();
rand = (Math.floor(Math.random() * 10e9)).toString(16).toUpperCase();
obj.eventid = "" + obj.event + "_" + timestamp + "_" + rand;
answ = {
code: 200,
message: "Thank you for the event: " + obj.eventid
};
resp.send(answ.code, answ);
return db.pushEvent(obj);
} else {
return resp.send(401, 'Please login!');
return resp.send(400, 'Your event was missing important parameters!');
}
});
};

42
js/sandbox.js Normal file
View file

@ -0,0 +1,42 @@
// Generated by CoffeeScript 1.7.1
(function() {
var app, express, fHandleEvent, fHandleEventGet;
express = require('express');
app = express();
app.post('/event', fHandleEvent);
app.get('/event', fHandleEventGet);
app.listen(8111);
fHandleEvent = function(req, resp) {
var body;
console.log('received something with POST!');
body = '';
req.on('data', function(data) {
return body += data;
});
req.on('end', function() {
var err, obj;
console.log('got foreign event!');
console.log(body);
try {
obj = JSON.parse(body);
return console.log('successfully parsed');
} catch (_error) {
err = _error;
return console.log(err);
}
});
return resp.send(200, 'Cheers!');
};
fHandleEventGet = function(req, resp) {
console.log('received something with GET!');
return resp.send(200, 'Cheers!');
};
}).call(this);

View file

@ -146,6 +146,7 @@ WebAPI-ECA Engine
args['http-port'] = parseInt(argv.w || conf.getHttpPort());
args['db-port'] = parseInt(argv.d || conf.getDbPort());
args['keygen'] = conf.getKeygenPassphrase();
args['webhooks'] = conf.fetchProp('webhooks');
_this.log.info('RS | Initialzing DB');
db(args);
return db.isConnected(function(err) {

View file

@ -14,6 +14,7 @@
"crypto-js": "3.1.2",
"express": "3.4.8",
"groc": "0.6.1",
"import-io": "1.0.x",
"js-select": "0.6.0",
"mustache": "0.8.1",
"needle": "0.6.3",

View file

@ -35,15 +35,17 @@
"data":"# Send a mail through emailyak\nexports.otherEvent = ( evt ) ->\n\turl = 'https://api.emailyak.com/v1/' + params.apikey + '/json/send/email/'\n\tpayload =\n\t FromAddress : \"testsender@mscliveweb.simpleyak.com\",\n\t ToAddress: \"dominic.bosch@gmail.com\",\n\t Subject: \"TestMAIL\",\n\t TextBody: \"Hello\"\n\t\n\tneedle.post url, payload, ( err, resp, body ) ->\n\t\tif err\n\t\t\tlog err\n\t\tif resp.statusCode isnt 200\n\t\t\tlog 'Request not successful:'\n\t\t\tlog body\n",
"public":"false",
"params":"[\"apikey\",\"andmore\"]",
"functions":"[\"otherEvent\"]"
"functions":"[\"otherEvent\"]",
"functionArgs":"{\"otherEvent\":[\"evt\"]}"
},
"aiThree": {
"id":"aiThree",
"lang":"CoffeeScript",
"data":"exports.printUserParamToLog = ( evt ) ->\n\tlog params.password",
"data":"exports.printUserParamToLog = ( evt ) ->\n\tdebug 'wow'n\tlog 'wow'\n\tlog params.password",
"public":"false",
"params":"[\"password\"]",
"functions":"[\"printUserParamToLog\"]"
"functions":"[\"printUserParamToLog\"]",
"functionArgs":"{\"printUserParamToLog\":[\"evt\"]}"
}
},
"userparams": {
@ -76,36 +78,18 @@
},
"rules": {
"ruleOne": {
"id": "ruleOne_id",
"event": "custom-test-1",
"conditions": [],
"actions": []
},
"ruleTwo": {
"id": "ruleTwo_id",
"event": "custom-test-2",
"conditions": [],
"actions": []
},
"ruleThree": {
"id": "ruleThree_id",
"event": "custom-test-3",
"conditions": [],
"actions": []
},
"ruleReal": {
"id": "ruleReal",
"event": "epOne -> newMail",
"event": "test_1",
"conditions": [".more:val(\"really nested\")"],
"actions": ["aiOne -> printToLog"]
},
"ruleRealTwo": {
"ruleTwo": {
"id": "ruleRealTwo",
"event": "epOne -> newMail",
"event": "test_2",
"conditions": [],
"actions": ["aiTwo -> otherEvent"]
},
"ruleRealThree": {
"ruleThree": {
"id": "ruleRealThree",
"event": "epOne -> newMail",
"conditions": [],

View file

@ -1,24 +1,36 @@
fs = require 'fs'
path = require 'path'
cryptico = require 'my-cryptico'
passPhrase = 'UNIT TESTING PASSWORD'
numBits = 1024
oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
strPublicKey = cryptico.publicKeyString oPrivateRSAkey
try
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
catch err
console.log 'Error fetching standard objects file: ' + err.message
console.log 'Error fetching standard objects file: ' + err.message
logger = require path.join '..', 'js', 'logging'
log = logger.getLogger
nolog: true
log = logger.getLogger()
# nolog: true
opts =
logger: log
logger: log
engine = require path.join '..', 'js', 'engine'
engine opts
cm = require path.join '..', 'js', 'components-manager'
cm opts
cm.addRuleListener engine.internalEvent
db = require path.join '..', 'js', 'persistence'
db opts
@ -29,139 +41,182 @@ oRuleThree = objects.rules.ruleThree
oEpOne = objects.eps.epOne
oEpTwo = objects.eps.epTwo
oAiTwo = objects.ais.aiTwo
oAiThree = objects.ais.aiThree
exports.tearDown = ( cb ) ->
db.deleteRule oRuleOne.id
db.deleteRule oRuleTwo.id
db.deleteRule oRuleThree.id
setTimeout cb, 100
db.deleteRule oRuleOne.id
db.deleteRule oRuleTwo.id
db.deleteRule oRuleThree.id
setTimeout cb, 100
exports.requestProcessing =
testEmptyPayload: ( test ) =>
test.expect 1
testEmptyPayload: ( test ) =>
test.expect 1
request =
command: 'get_event_pollers'
request =
command: 'get_event_pollers'
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'Empty payload did not return 200'
test.done()
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'Empty payload did not return 200'
test.done()
testCorruptPayload: ( test ) =>
test.expect 1
testCorruptPayload: ( test ) =>
test.expect 1
request =
command: 'get_event_pollers'
payload: 'no-json'
request =
command: 'get_event_pollers'
payload: 'no-json'
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 404, answ.code, 'Corrupt payload did not return 404'
test.done()
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 404, answ.code, 'Corrupt payload did not return 404'
test.done()
exports.testListener = ( test ) =>
test.expect 3
test.expect 3
strRuleOne = JSON.stringify oRuleOne
strRuleTwo = JSON.stringify oRuleTwo
strRuleThree = JSON.stringify oRuleThree
strRuleOne = JSON.stringify oRuleOne
strRuleTwo = JSON.stringify oRuleTwo
strRuleThree = JSON.stringify oRuleThree
db.storeUser oUser
db.storeRule oRuleOne.id, strRuleOne
db.linkRule oRuleOne.id, oUser.username
db.activateRule oRuleOne.id, oUser.username
db.storeRule oRuleTwo.id, strRuleTwo
db.linkRule oRuleTwo.id, oUser.username
db.activateRule oRuleTwo.id, oUser.username
db.storeUser oUser
db.storeRule oRuleOne.id, strRuleOne
db.linkRule oRuleOne.id, oUser.username
db.activateRule oRuleOne.id, oUser.username
db.storeRule oRuleTwo.id, strRuleTwo
db.linkRule oRuleTwo.id, oUser.username
db.activateRule oRuleTwo.id, oUser.username
request =
command: 'forge_rule'
payload: strRuleThree
request =
command: 'forge_rule'
payload: strRuleThree
cm.addRuleListener ( evt ) =>
strEvt = JSON.stringify evt.rule
if evt.event is 'init'
if strEvt is strRuleOne or strEvt is strRuleTwo
test.ok true, 'Dummy true to fill expected tests!'
cm.addRuleListener ( evt ) =>
strEvt = JSON.stringify evt.rule
if evt.event is 'init'
if strEvt is strRuleOne or strEvt is strRuleTwo
test.ok true, 'Dummy true to fill expected tests!'
if strEvt is strRuleThree
test.ok false, 'Init Rule found test rule number two??'
if strEvt is strRuleThree
test.ok false, 'Init Rule found test rule number two??'
if evt.event is 'new'
if strEvt is strRuleOne or strEvt is strRuleTwo
test.ok false, 'New Rule got test rule number one??'
if evt.event is 'new'
if strEvt is strRuleOne or strEvt is strRuleTwo
test.ok false, 'New Rule got test rule number one??'
if strEvt is strRuleThree
test.ok true, 'Dummy true to fill expected tests!'
if strEvt is strRuleThree
test.ok true, 'Dummy true to fill expected tests!'
fWaitForInit = ->
cm.processRequest oUser, request, ( answ ) =>
if answ.code isnt 200
test.ok false, 'testListener failed: ' + answ.message
test.done()
setTimeout test.done, 500
fWaitForInit = ->
cm.processRequest oUser, request, ( answ ) =>
if answ.code isnt 200
test.ok false, 'testListener failed: ' + answ.message
test.done()
setTimeout test.done, 500
setTimeout fWaitForInit, 200
setTimeout fWaitForInit, 200
exports.moduleHandling =
tearDown: ( cb ) ->
db.eventPollers.deleteModule oEpOne.id
db.eventPollers.deleteModule oEpTwo.id
db.actionInvokers.deleteModule oAiTwo.id
setTimeout cb, 100
tearDown: ( cb ) ->
db.eventPollers.deleteModule oEpOne.id
db.eventPollers.deleteModule oEpTwo.id
db.actionInvokers.deleteModule oAiTwo.id
setTimeout cb, 100
testGetModules: ( test ) ->
test.expect 2
testGetModules: ( test ) ->
test.expect 2
db.eventPollers.storeModule oUser.username, oEpOne
db.eventPollers.storeModule oUser.username, oEpTwo
request =
command: 'get_event_pollers'
db.eventPollers.storeModule oUser.username, oEpOne
db.eventPollers.storeModule oUser.username, oEpTwo
request =
command: 'get_event_pollers'
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'GetModules failed...'
oExpected = {}
oExpected[oEpOne.id] = JSON.parse oEpOne.functions
oExpected[oEpTwo.id] = JSON.parse oEpTwo.functions
test.deepEqual oExpected, JSON.parse(answ.message),
'GetModules retrieved modules is not what we expected'
test.done()
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'GetModules failed...'
oExpected = {}
oExpected[oEpOne.id] = JSON.parse oEpOne.functions
oExpected[oEpTwo.id] = JSON.parse oEpTwo.functions
test.deepEqual oExpected, JSON.parse(answ.message),
'GetModules retrieved modules is not what we expected'
test.done()
testGetModuleParams: ( test ) ->
test.expect 2
testGetModuleParams: ( test ) ->
test.expect 2
db.eventPollers.storeModule oUser.username, oEpOne
db.eventPollers.storeModule oUser.username, oEpOne
request =
command: 'get_event_poller_params'
payload:
id: oEpOne.id
request.payload = JSON.stringify request.payload
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code,
'Required Module Parameters did not return 200'
test.strictEqual oEpOne.params, answ.message,
'Required Module Parameters did not match'
test.done()
request =
command: 'get_event_poller_params'
payload:
id: oEpOne.id
request.payload = JSON.stringify request.payload
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code,
'Required Module Parameters did not return 200'
test.strictEqual oEpOne.params, answ.message,
'Required Module Parameters did not match'
test.done()
testForgeModule: ( test ) ->
test.expect 2
testForgeModule: ( test ) ->
test.expect 2
oTmp = {}
for key, val of oAiTwo
oTmp[key] = val if key isnt 'functions' and key isnt 'functionParameters'
oTmp = {}
for key, val of oAiTwo
oTmp[key] = val if key isnt 'functions' and key isnt 'functionParameters'
request =
command: 'forge_action_invoker'
payload: JSON.stringify oTmp
request =
command: 'forge_action_invoker'
payload: JSON.stringify oTmp
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'Forging Module did not return 200'
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, 'Forging Module did not return 200'
db.actionInvokers.getModule oAiTwo.id, ( err, obj ) ->
test.deepEqual obj, oAiTwo, 'Forged Module is not what we expected'
test.done()
exports.testForgeRule = ( test ) ->
test.expect 1
db.storeUser oUser
db.actionInvokers.storeModule oUser.username, oAiThree
pw = 'This password should come out cleartext'
userparams = JSON.stringify password: pw
oEncrypted = cryptico.encrypt userparams, strPublicKey
db.actionInvokers.storeUserParams oAiThree.id, oUser.username, oEncrypted.cipher
request =
command: 'forge_rule'
payload: JSON.stringify oRuleThree
cm.processRequest oUser, request, ( answ ) =>
test.strictEqual 200, answ.code, "Forging Rule returned #{ answ.code }: #{ answ.message }"
fWaitForPersistence = () ->
evt = objects.events.eventReal
evt.eventid = 'event_testid'
db.pushEvent evt
console.log 'pushed'
fWaitAgain = () ->
console.log 'waited'
db.getLog oUser.username, oRuleThree.id, ( err, data ) ->
console.log data
try
logged = data.split( '] ' )[1]
logged = logged.split( "\n" )[0]
test.strictEqual logged, "{#{ oAiThree.id }} " + pw, 'Did not log the right thing'
catch e
test.ok false, 'Parsing log failed'
setTimeout test.done, 200
setTimeout fWaitAgain, 200
setTimeout fWaitForPersistence, 200
db.actionInvokers.getModule oAiTwo.id, ( err, obj ) ->
console.log obj
console.log oAiTwo
test.deepEqual obj, oAiTwo, 'Forged Module is not what we expected'
test.done()

View file

@ -1,43 +1,43 @@
path = require 'path'
logger = require path.join '..', 'js', 'logging'
log = logger.getLogger
nolog: true
nolog: true
conf = require path.join '..', 'js', 'config'
conf
logger: log
logger: log
exports.testRequire = ( test ) ->
test.expect 1
test.ok conf.isReady(), 'File does not exist!'
test.done()
test.expect 1
test.ok conf.isReady(), 'File does not exist!'
test.done()
exports.testParameters = ( test ) ->
reqProp = [
'mode'
'io-level'
'file-level'
]
test.expect 3 + reqProp.length
test.ok conf.getHttpPort(), 'HTTP port 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
test.ok logconf[prop], "Log conf property #{ prop } does not exist!"
test.done()
reqProp = [
'mode'
'io-level'
'file-level'
]
test.expect 3 + reqProp.length
test.ok conf.getHttpPort(), 'HTTP port 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
test.ok logconf[prop], "Log conf property #{ prop } does not exist!"
test.done()
exports.testDifferentConfigFile = ( test ) ->
test.expect 1
conf
# nolog: true
configPath: path.join 'testing', 'files', 'jsonTestConfig.json'
test.ok conf.isReady(), 'Different path not loaded!'
test.done()
test.expect 1
conf
# nolog: true
configPath: path.join 'testing', 'files', 'jsonTestConfig.json'
test.ok conf.isReady(), 'Different path not loaded!'
test.done()
exports.testNoConfigFile = ( test ) ->
test.expect 1
conf
nolog: true
configPath: 'wrongpath.file'
test.strictEqual conf.isReady(), false, 'Wrong path still loaded!'
test.done()
test.expect 1
conf
nolog: true
configPath: 'wrongpath.file'
test.strictEqual conf.isReady(), false, 'Wrong path still loaded!'
test.done()

View file

@ -8,20 +8,20 @@ oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
strPublicKey = cryptico.publicKeyString oPrivateRSAkey
try
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
catch err
console.log 'Error fetching standard objects file: ' + err.message
console.log 'Error fetching standard objects file: ' + err.message
logger = require path.join '..', 'js', 'logging'
log = logger.getLogger
nolog: true
nolog: true
opts =
logger: log
keygen: passPhrase
logger: log
keygen: passPhrase
db = require path.join '..', 'js', 'persistence'
db opts
@ -33,78 +33,30 @@ dm = require path.join '..', 'js', 'dynamic-modules'
dm opts
oUser = objects.users.userOne
oRuleReal = objects.rules.ruleRealThree
oRule = objects.rules.ruleThree
oAi = objects.ais.aiThree
exports.tearDown = ( cb ) ->
db.storeUser oUser
db.deleteRule oRuleReal.id
db.actionInvokers.deleteModule oAi.id
setTimeout cb, 200
db.storeUser oUser
db.deleteRule oRule.id
db.actionInvokers.deleteModule oAi.id
setTimeout cb, 200
exports.testCompile = ( test ) ->
test.expect 5
test.expect 5
paramOne = 'First Test'
code = "exports.testFunc = () ->\n\t'#{ paramOne }'"
dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) ->
test.strictEqual 200, result.answ.code
moduleOne = result.module
test.strictEqual paramOne, moduleOne.testFunc(), "Other result expected"
paramTwo = 'Second Test'
code = "exports.testFunc = () ->\n\t'#{ paramTwo }'"
dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) ->
test.strictEqual 200, result.answ.code
moduleTwo = result.module
test.strictEqual paramTwo, moduleTwo.testFunc(), "Other result expected"
test.notStrictEqual paramOne, moduleTwo.testFunc(), "Other result expected"
setTimeout test.done, 200
exports.testCorrectUserParams = ( test ) ->
test.expect 1
db.storeUser oUser
db.storeRule oRuleReal.id, JSON.stringify oRuleReal
db.linkRule oRuleReal.id, oUser.username
db.activateRule oRuleReal.id, oUser.username
db.actionInvokers.storeModule oUser.username, oAi
pw = 'This password should come out cleartext'
userparams = JSON.stringify password: pw
oEncrypted = cryptico.encrypt userparams, strPublicKey
db.actionInvokers.storeUserParams oAi.id, oUser.username, oEncrypted.cipher
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleReal
fWaitForPersistence = () ->
evt = objects.events.eventReal
evt.eventid = 'event_testid'
db.pushEvent evt
fWaitAgain = () ->
db.getLog oUser.username, oRuleReal.id, ( err, data ) ->
try
logged = data.split( '] ' )[1]
logged = logged.split( "\n" )[0]
test.strictEqual logged, "{#{ oAi.id }} " + pw, 'Did not log the right thing'
catch e
test.ok false, 'Parsing log failed'
engine.internalEvent
event: 'del'
user: oUser.username
rule: null
ruleId: oRuleReal.id
engine.shutDown()
setTimeout test.done, 200
setTimeout fWaitAgain, 200
setTimeout fWaitForPersistence, 200
paramOne = 'First Test'
code = "exports.testFunc = () ->\n\t'#{ paramOne }'"
dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) ->
test.strictEqual 200, result.answ.code
moduleOne = result.module
test.strictEqual paramOne, moduleOne.testFunc(), "Other result expected"
paramTwo = 'Second Test'
code = "exports.testFunc = () ->\n\t'#{ paramTwo }'"
dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) ->
test.strictEqual 200, result.answ.code
moduleTwo = result.module
test.strictEqual paramTwo, moduleTwo.testFunc(), "Other result expected"
test.notStrictEqual paramOne, moduleTwo.testFunc(), "Other result expected"
setTimeout test.done, 200

View file

@ -2,19 +2,19 @@ fs = require 'fs'
path = require 'path'
try
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
catch err
console.log 'Error fetching standard objects file: ' + err.message
console.log 'Error fetching standard objects file: ' + err.message
logger = require path.join '..', 'js', 'logging'
log = logger.getLogger
nolog: true
nolog: true
opts =
logger: log
logger: log
engine = require path.join '..', 'js', 'engine'
engine opts
@ -25,93 +25,93 @@ db opts
listRules = engine.getListUserRules()
oUser = objects.users.userOne
oRuleReal = objects.rules.ruleReal
oRuleRealTwo = objects.rules.ruleRealTwo
oRuleOne = objects.rules.ruleOne
oRuleTwo = objects.rules.ruleTwo
oAiOne = objects.ais.aiOne
oAiTwo = objects.ais.aiTwo
exports.setUp = ( cb ) ->
engine.startEngine()
cb()
engine.startEngine()
cb()
exports.tearDown = ( cb ) ->
db.deleteRule oRuleReal.id
db.actionInvokers.deleteModule oAiOne.id
db.actionInvokers.deleteModule oAiTwo.id
# TODO if user is deleted all his modules should be unlinked and deleted
db.deleteUser oUser.username
db.deleteRule oRuleOne.id
db.actionInvokers.deleteModule oAiOne.id
db.actionInvokers.deleteModule oAiTwo.id
# TODO if user is deleted all his modules should be unlinked and deleted
db.deleteUser oUser.username
engine.internalEvent
event: 'del'
user: oUser.username
rule: oRuleReal
engine.internalEvent
event: 'del'
user: oUser.username
rule: oRuleOne
engine.internalEvent
event: 'del'
user: oUser.username
rule: oRuleRealTwo
engine.shutDown()
engine.internalEvent
event: 'del'
user: oUser.username
rule: oRuleTwo
engine.shutDown()
setTimeout cb, 200
setTimeout cb, 200
exports.ruleEvents =
testInitAddDeleteMultiple: ( test ) ->
test.expect 2 + 2 * oRuleReal.actions.length + oRuleRealTwo.actions.length
testInitAddDeleteMultiple: ( test ) ->
test.expect 2 + 2 * oRuleOne.actions.length + oRuleTwo.actions.length
db.storeUser oUser
db.storeRule oRuleReal.id, JSON.stringify oRuleReal
db.linkRule oRuleReal.id, oUser.username
db.activateRule oRuleReal.id, oUser.username
db.actionInvokers.storeModule oUser.username, oAiOne
db.actionInvokers.storeModule oUser.username, oAiTwo
db.storeUser oUser
db.storeRule oRuleOne.id, JSON.stringify oRuleOne
db.linkRule oRuleOne.id, oUser.username
db.activateRule oRuleOne.id, oUser.username
db.actionInvokers.storeModule oUser.username, oAiOne
db.actionInvokers.storeModule oUser.username, oAiTwo
test.strictEqual listRules[oUser.username], undefined, 'Initial user object exists!?'
test.strictEqual listRules[oUser.username], undefined, 'Initial user object exists!?'
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleReal
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleOne
fWaitForPersistence = () ->
fWaitForPersistence = () ->
for act in oRuleReal.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleReal.id].actions[mod], 'Missing action!'
for act in oRuleOne.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleOne.id].actions[mod], 'Missing action!'
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleRealTwo
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleTwo
fWaitAgainForPersistence = () ->
fWaitAgainForPersistence = () ->
for act in oRuleRealTwo.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleRealTwo.id].actions[mod], 'Missing action!'
engine.internalEvent
event: 'del'
user: oUser.username
rule: null
ruleId: oRuleRealTwo.id
for act in oRuleTwo.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleTwo.id].actions[mod], 'Missing action!'
engine.internalEvent
event: 'del'
user: oUser.username
rule: null
ruleId: oRuleTwo.id
for act in oRuleReal.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleReal.id].actions[mod], 'Missing action!'
engine.internalEvent
event: 'del'
user: oUser.username
rule: null
ruleId: oRuleReal.id
for act in oRuleOne.actions
mod = ( act.split ' -> ' )[0]
test.ok listRules[oUser.username][oRuleOne.id].actions[mod], 'Missing action!'
engine.internalEvent
event: 'del'
user: oUser.username
rule: null
ruleId: oRuleOne.id
test.strictEqual listRules[oUser.username], undefined, 'Final user object exists!?'
test.done()
test.strictEqual listRules[oUser.username], undefined, 'Final user object exists!?'
test.done()
setTimeout fWaitAgainForPersistence, 200
setTimeout fWaitAgainForPersistence, 200
setTimeout fWaitForPersistence, 200
setTimeout fWaitForPersistence, 200
# #TODO
# testUpdate: ( test ) ->
@ -120,9 +120,9 @@ exports.ruleEvents =
# test.done()
# db.storeUser oUser
# db.storeRule oRuleReal.id, JSON.stringify oRuleReal
# db.linkRule oRuleReal.id, oUser.username
# db.activateRule oRuleReal.id, oUser.username
# db.storeRule oRuleOne.id, JSON.stringify oRuleOne
# db.linkRule oRuleOne.id, oUser.username
# db.activateRule oRuleOne.id, oUser.username
# db.actionInvokers.storeModule oUser.username, oAiOne
@ -133,7 +133,7 @@ exports.ruleEvents =
# engine.internalEvent
# event: 'init'
# user: oUser.username
# rule: oRuleReal
# rule: oRuleOne
# fCheckRules = () ->
# db.getAllActivatedRuleIdsPerUser ( err, obj ) ->
@ -143,35 +143,35 @@ exports.ruleEvents =
# setTimeout fCheckRules, 500
exports.engine =
testMatchingEvent: ( test ) ->
test.expect 1
db.storeUser oUser
db.storeRule oRuleReal.id, JSON.stringify oRuleReal
db.linkRule oRuleReal.id, oUser.username
db.activateRule oRuleReal.id, oUser.username
db.actionInvokers.storeModule oUser.username, oAiOne
testMatchingEvent: ( test ) ->
test.expect 1
db.storeUser oUser
db.storeRule oRuleOne.id, JSON.stringify oRuleOne
db.linkRule oRuleOne.id, oUser.username
db.activateRule oRuleOne.id, oUser.username
db.actionInvokers.storeModule oUser.username, oAiOne
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleReal
engine.internalEvent
event: 'new'
user: oUser.username
rule: oRuleOne
fWaitForPersistence = () ->
evt = objects.events.eventReal
evt.eventid = 'event_testid'
db.pushEvent evt
fWaitForPersistence = () ->
evt = objects.events.eventReal
evt.eventid = 'event_testid'
db.pushEvent evt
fWaitAgain = () ->
db.getLog oUser.username, oRuleReal.id, ( err, data ) ->
try
fWaitAgain = () ->
db.getLog oUser.username, oRuleOne.id, ( err, data ) ->
try
logged = data.split( '] ' )[1]
logged = logged.split( "\n" )[0]
test.strictEqual logged, "{#{ oAiOne.id }} " + evt.payload.property, 'Did not log the right thing'
catch e
test.ok false, 'Parsing log failed'
test.done()
logged = data.split( '] ' )[1]
logged = logged.split( "\n" )[0]
test.strictEqual logged, "{#{ oAiOne.id }} " + evt.payload.property, 'Did not log the right thing'
catch e
test.ok false, 'Parsing log failed'
test.done()
setTimeout fWaitAgain, 200
setTimeout fWaitAgain, 200
setTimeout fWaitForPersistence, 200
setTimeout fWaitForPersistence, 200

View file

@ -4,97 +4,97 @@ stdPath = path.resolve __dirname, '..', 'logs', 'server.log'
logger = require path.join '..', 'js', 'logging'
getLog = ( strPath, cb ) ->
fWait = ->
# cb fs.readFileSync path, 'utf-8'
str = fs.readFileSync path.resolve( strPath ), 'utf-8'
arrStr = str.split "\n"
fConvertRow = ( row ) ->
try
JSON.parse row
arrStr[i] = fConvertRow row for row, i in arrStr
cb arrStr.slice 0, arrStr.length - 1
setTimeout fWait, 100
fWait = ->
# cb fs.readFileSync path, 'utf-8'
str = fs.readFileSync path.resolve( strPath ), 'utf-8'
arrStr = str.split "\n"
fConvertRow = ( row ) ->
try
JSON.parse row
arrStr[i] = fConvertRow row for row, i in arrStr
cb arrStr.slice 0, arrStr.length - 1
setTimeout fWait, 100
exports.setUp = ( cb ) ->
try
fs.unlinkSync stdPath
cb()
try
fs.unlinkSync stdPath
cb()
exports.testCreate = ( test ) ->
test.expect 2
arrLogs = [
'TL | testInitIO - info'
'TL | testInitIO - warn'
'TL | testInitIO - error'
]
args = {}
args[ 'io-level' ] = 'error'
log = logger.getLogger args
log.info arrLogs[0]
log.warn arrLogs[1]
log.error arrLogs[2]
test.ok fs.existsSync( stdPath ), 'Log file does not exist!'
getLog stdPath, ( arr ) ->
allCorrect = true
for o,i in arr
if o.msg is not arrLogs[i]
allCorrect = false
test.ok allCorrect, 'Log file does not contain the correct entries!'
test.done()
test.expect 2
arrLogs = [
'TL | testInitIO - info'
'TL | testInitIO - warn'
'TL | testInitIO - error'
]
args = {}
args[ 'io-level' ] = 'error'
log = logger.getLogger args
log.info arrLogs[0]
log.warn arrLogs[1]
log.error arrLogs[2]
test.ok fs.existsSync( stdPath ), 'Log file does not exist!'
getLog stdPath, ( arr ) ->
allCorrect = true
for o,i in arr
if o.msg is not arrLogs[i]
allCorrect = false
test.ok allCorrect, 'Log file does not contain the correct entries!'
test.done()
exports.testNoLog = ( test ) ->
test.expect 1
test.expect 1
log = logger.getLogger
nolog: true
log.info 'TL | test 1'
log = logger.getLogger
nolog: true
log.info 'TL | test 1'
fWait = () ->
test.ok !fs.existsSync( stdPath ), 'Log file does still exist!'
test.done()
fWait = () ->
test.ok !fs.existsSync( stdPath ), 'Log file does still exist!'
test.done()
setTimeout fWait, 100
setTimeout fWait, 100
exports.testCustomPath = ( test ) ->
test.expect 2
test.expect 2
strInfo = 'TL | custom path test 1'
strPath = 'testing/files/test.log'
args = {}
args[ 'file-path' ] = strPath
args[ 'io-level' ] = 'error'
strInfo = 'TL | custom path test 1'
strPath = 'testing/files/test.log'
args = {}
args[ 'file-path' ] = strPath
args[ 'io-level' ] = 'error'
log = logger.getLogger args
log.info strInfo
log = logger.getLogger args
log.info strInfo
fWait = () ->
test.ok fs.existsSync( strPath ), 'Custom log file does not exist!'
getLog strPath, ( arr ) ->
test.ok arr[0].msg is strInfo, 'Custom log file not correct!'
try
fs.unlinkSync strPath
test.done()
fWait = () ->
test.ok fs.existsSync( strPath ), 'Custom log file does not exist!'
getLog strPath, ( arr ) ->
test.ok arr[0].msg is strInfo, 'Custom log file not correct!'
try
fs.unlinkSync strPath
test.done()
setTimeout fWait, 100
setTimeout fWait, 100
exports.testWrongPath = ( test ) ->
empty = [
'trace'
'debug'
'info'
'warn'
'error'
'fatal'
]
test.expect empty.length
empty = [
'trace'
'debug'
'info'
'warn'
'error'
'fatal'
]
test.expect empty.length
strInfo = 'TL | custom path test 1'
strPath = 'strange/path/to/test.log'
args = {}
args[ 'file-path' ] = strPath
args[ 'io-level' ] = 'error'
log = logger.getLogger args
test.ok prop in empty, "#{ prop } shouldn't be here" for prop of log
test.done()
strInfo = 'TL | custom path test 1'
strPath = 'strange/path/to/test.log'
args = {}
args[ 'file-path' ] = strPath
args[ 'io-level' ] = 'error'
log = logger.getLogger args
test.ok prop in empty, "#{ prop } shouldn't be here" for prop of log
test.done()

File diff suppressed because it is too large Load diff

View file

@ -6,241 +6,241 @@ cp = require 'child_process'
try
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8'
try
objects = JSON.parse data
catch err
console.log 'Error parsing standard objects file: ' + err.message
catch err
console.log 'Error fetching standard objects file: ' + err.message
console.log 'Error fetching standard objects file: ' + err.message
logger = require path.join '..', 'js', 'logging'
log = logger.getLogger
nolog: true
nolog: true
opts =
logger: log
logger: log
opts[ 'db-port' ] = 6379
db = require path.join '..', 'js', 'persistence'
db opts
rh = require path.join '..', 'js', 'request-handler'
opts[ 'request-service' ] = ( usr, obj, cb ) ->
test.ok false, 'testEvent should not cause a service request call'
test.ok false, 'testEvent should not cause a service request call'
opts[ 'shutdown-function' ] = () ->
test.ok false, 'testEvent should not cause a system shutdown'
test.ok false, 'testEvent should not cause a system shutdown'
rh opts
createRequest = ( query, origUrl ) ->
req = new events.EventEmitter()
req.query = query
req.originalUrl = origUrl
req.session = {}
req
req = new events.EventEmitter()
req.query = query
req.originalUrl = origUrl
req.session = {}
req
createLoggedInRequest = ( query, origUrl ) ->
req = createRequest query, origUrl
req.session =
user: objects.users.userOne
req
req = createRequest query, origUrl
req.session =
user: objects.users.userOne
req
createAdminRequest = ( query, origUrl ) ->
req = createRequest()
req.session =
user: objects.users.userAdmin
req
req = createRequest()
req.session =
user: objects.users.userAdmin
req
postRequestData = ( req, data ) ->
req.emit 'data', data
req.emit 'end'
req.emit 'data', data
req.emit 'end'
# cb want's to get a response like { code, msg }
createResponse = ( cb ) ->
resp =
send: ( code, msg ) ->
if msg
code = parseInt code
else
msg = code
code = 200
cb code, msg
resp =
send: ( code, msg ) ->
if msg
code = parseInt code
else
msg = code
code = 200
cb code, msg
exports.session =
setUp: ( cb ) =>
@oUsr = objects.users.userOne
db.storeUser @oUsr
cb()
setUp: ( cb ) =>
@oUsr = objects.users.userOne
db.storeUser @oUsr
cb()
tearDown: ( cb ) =>
db.deleteUser @oUsr.username
cb()
tearDown: ( cb ) =>
db.deleteUser @oUsr.username
cb()
testLoginAndOut: ( test ) =>
test.expect 6
testLoginAndOut: ( test ) =>
test.expect 6
req = createRequest()
resp = createResponse ( code, msg ) =>
req = createRequest()
resp = createResponse ( code, msg ) =>
# Check Login
test.strictEqual code, 200, 'Login failed'
test.deepEqual req.session.user, @oUsr, 'Session user not what we expected'
req = createLoggedInRequest()
resp = createResponse ( code, msg ) =>
# Check Login
test.strictEqual code, 200, 'Login failed'
test.deepEqual req.session.user, @oUsr, 'Session user not what we expected'
req = createLoggedInRequest()
resp = createResponse ( code, msg ) =>
# Check Login again
test.strictEqual code, 200, 'Login again did nothing different'
test.deepEqual req.session.user, @oUsr, 'Session user not what we expected after relogin'
req = createRequest()
resp = createResponse ( code, msg ) ->
# Check Login again
test.strictEqual code, 200, 'Login again did nothing different'
test.deepEqual req.session.user, @oUsr, 'Session user not what we expected after relogin'
req = createRequest()
resp = createResponse ( code, msg ) ->
# Check logout
test.strictEqual code, 200, 'Logout failed'
test.strictEqual req.session.user, null, 'User not removed from session'
test.done()
rh.handleLogout req, resp # set the handler to listening
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify @oUsr # emit the data post event
# Check logout
test.strictEqual code, 200, 'Logout failed'
test.strictEqual req.session.user, null, 'User not removed from session'
test.done()
rh.handleLogout req, resp # set the handler to listening
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify @oUsr # emit the data post event
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify @oUsr # emit the data post event
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify @oUsr # emit the data post event
testWrongLogin: ( test ) =>
test.expect 2
testWrongLogin: ( test ) =>
test.expect 2
req = createRequest()
resp = createResponse ( code, msg ) =>
test.strictEqual code, 401, 'Login did not fail?'
test.strictEqual req.session.user, undefined, 'User in session?'
test.done()
req = createRequest()
resp = createResponse ( code, msg ) =>
test.strictEqual code, 401, 'Login did not fail?'
test.strictEqual req.session.user, undefined, 'User in session?'
test.done()
usr =
username: @oUsr.username
password: 'wrongpassword'
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify usr # emit the data post event
usr =
username: @oUsr.username
password: 'wrongpassword'
rh.handleLogin req, resp # set the handler to listening
postRequestData req, JSON.stringify usr # emit the data post event
exports.events =
setUp: ( cb ) ->
db.purgeEventQueue()
cb()
setUp: ( cb ) ->
db.purgeEventQueue()
cb()
# This test seems to hang sometimes... maybe it's also happening somewhere else...
testCorrectEvent: ( test ) ->
test.expect 2
testCorrectEvent: ( test ) ->
test.expect 2
oEvt = objects.events.eventOne
oEvt = objects.events.eventOne
semaphore = 2
fPopEvent = () ->
fCb = ( err, obj ) ->
oEvt.eventid = obj.eventid # because the event id is generated by the system
test.deepEqual obj, oEvt, 'Caught event is not what we expected'
if --semaphore is 0
test.done()
db.popEvent fCb
semaphore = 2
fPopEvent = () ->
fCb = ( err, obj ) ->
oEvt.eventid = obj.eventid # because the event id is generated by the system
test.deepEqual obj, oEvt, 'Caught event is not what we expected'
if --semaphore is 0
test.done()
db.popEvent fCb
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 200
if --semaphore is 0
test.done()
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 200
if --semaphore is 0
test.done()
rh.handleEvent req, resp # set the handler to listening
postRequestData req, JSON.stringify oEvt # emit the data post event
setTimeout fPopEvent, 200 # try to fetch the db entry
rh.handleEvent req, resp # set the handler to listening
postRequestData req, JSON.stringify oEvt # emit the data post event
setTimeout fPopEvent, 200 # try to fetch the db entry
testIncorrectEvent: ( test ) ->
test.expect 2
testIncorrectEvent: ( test ) ->
test.expect 2
oEvt =
data: 'event misses event type property'
oEvt =
data: 'event misses event type property'
semaphore = 2
fPopEvent = () ->
fCb = ( err, obj ) ->
test.deepEqual obj, null, 'We caught an event!?'
if --semaphore is 0
test.done()
db.popEvent fCb
semaphore = 2
fPopEvent = () ->
fCb = ( err, obj ) ->
test.deepEqual obj, null, 'We caught an event!?'
if --semaphore is 0
test.done()
db.popEvent fCb
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 400
if --semaphore is 0
test.done()
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 400
if --semaphore is 0
test.done()
rh.handleEvent req, resp # set the handler to listening
postRequestData req, JSON.stringify oEvt # emit the data post event
setTimeout fPopEvent, 200 # try to fetch the db entry
rh.handleEvent req, resp # set the handler to listening
postRequestData req, JSON.stringify oEvt # emit the data post event
setTimeout fPopEvent, 200 # try to fetch the db entry
exports.testLoginOrPage = ( test ) ->
test.expect 3
test.expect 3
req = createRequest()
req.query =
page: 'forge_event'
resp = createResponse ( code, msg ) ->
# Ensure we have to login first
test.ok msg.indexOf( 'document.title = \'Login\'' ) > 0, 'Didn\'t get login page?'
req = createLoggedInRequest()
req.query =
page: 'forge_event'
resp = createResponse ( code, msg ) ->
req = createRequest()
req.query =
page: 'forge_event'
resp = createResponse ( code, msg ) ->
# Ensure we have to login first
test.ok msg.indexOf( 'document.title = \'Login\'' ) > 0, 'Didn\'t get login page?'
req = createLoggedInRequest()
req.query =
page: 'forge_event'
resp = createResponse ( code, msg ) ->
# After being logged in we should get the expected page
test.ok msg.indexOf( 'document.title = \'Event Forge!\'' ) > 0, 'Didn\' get forge page?'
req = createLoggedInRequest()
req.query =
page: 'wrongpage'
resp = createResponse ( code, msg ) ->
# After being logged in we should get the expected page
test.ok msg.indexOf( 'document.title = \'Event Forge!\'' ) > 0, 'Didn\' get forge page?'
req = createLoggedInRequest()
req.query =
page: 'wrongpage'
resp = createResponse ( code, msg ) ->
# A wrong page request should give back an error page
test.ok msg.indexOf( 'document.title = \'Error!\'' ) > 0, 'Didn\' get forge page?'
test.done()
# A wrong page request should give back an error page
test.ok msg.indexOf( 'document.title = \'Error!\'' ) > 0, 'Didn\' get forge page?'
test.done()
rh.handleForge req, resp # set the handler to listening
rh.handleForge req, resp # set the handler to listening
rh.handleForge req, resp # set the handler to listening
rh.handleForge req, resp # set the handler to listening
rh.handleForge req, resp # set the handler to listening
rh.handleForge req, resp # set the handler to listening
exports.testUserCommandsNoLogin = ( test ) ->
test.expect 1
test.expect 1
req = createRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 401, 'Login did not fail?'
test.done()
rh.handleUserCommand req, resp # set the handler to listening
req = createRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 401, 'Login did not fail?'
test.done()
rh.handleUserCommand req, resp # set the handler to listening
exports.testUserCommands = ( test ) ->
test.expect 3
test.expect 3
oReqData =
command: 'get_something'
# store_action
# store_event
# store_rule
# get_eventmodules
# get_actionmodules
oReqData =
command: 'get_something'
# store_action
# store_event
# store_rule
# get_eventmodules
# get_actionmodules
oRespData =
code: 200
some: 'very'
important: 'data'
oRespData =
code: 200
some: 'very'
important: 'data'
args =
logger: log
args[ 'request-service' ] = ( usr, obj, cb ) ->
test.ok true, 'Yay we got the request!'
cb oRespData
rh args
args =
logger: log
args[ 'request-service' ] = ( usr, obj, cb ) ->
test.ok true, 'Yay we got the request!'
cb oRespData
rh args
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 200, 'Service wasn\'t happy with our request'
test.deepEqual msg, oRespData, 'Service didn\'t return expected'
test.done()
rh.handleUserCommand req, resp # set the handler to listening
postRequestData req, JSON.stringify oReqData # emit the data post event
req = createLoggedInRequest()
resp = createResponse ( code, msg ) ->
test.strictEqual code, 200, 'Service wasn\'t happy with our request'
test.deepEqual msg, oRespData, 'Service didn\'t return expected'
test.done()
rh.handleUserCommand req, resp # set the handler to listening
postRequestData req, JSON.stringify oReqData # emit the data post event

View file

@ -6,125 +6,125 @@ path = require 'path'
# TODO test wrong/invalid config file
exports.testShutDown = ( test ) ->
test.expect 1
test.expect 1
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-w', '8640' ] # [ '-i' , 'warn' ]
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-w', '8640' ] # [ '-i' , 'warn' ]
engine.on 'error', ( err ) ->
console.log err
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, '"testShutDown" Engine didn\'t shut down!'
engine.kill()
setTimeout test.done, 100
engine.on 'error', ( err ) ->
console.log err
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, '"testShutDown" Engine didn\'t shut down!'
engine.kill()
setTimeout test.done, 100
setTimeout fWaitForStartup, 1000
setTimeout fWaitForStartup, 1000
exports.testKill = ( test ) ->
test.expect 1
test.expect 1
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-w', '8641' ] # [ '-i' , 'warn' ]
engine.on 'error', ( err ) ->
console.log err
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-w', '8641' ] # [ '-i' , 'warn' ]
engine.on 'error', ( err ) ->
console.log err
fWaitForStartup = () ->
engine.kill()
setTimeout fWaitForDeath, 1000
# Garbage collect eventually still running process
fWaitForDeath = () ->
test.ok engine.killed, '"testKill" Engine didn\'t shut down!'
test.done()
fWaitForStartup = () ->
engine.kill()
setTimeout fWaitForDeath, 1000
# Garbage collect eventually still running process
fWaitForDeath = () ->
test.ok engine.killed, '"testKill" Engine didn\'t shut down!'
test.done()
setTimeout fWaitForStartup, 1000
setTimeout fWaitForStartup, 1000
exports.testHttpPortAlreadyUsed = ( test ) =>
test.expect 1
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
# Strange! why can't we make these variables local without
# the tests failing in one of the next tests...
@engine_one = cp.fork pth, [ '-n', '-w', '8642' ] # [ '-i' , 'warn' ]
@engine_one.on 'error', ( err ) ->
console.log err
test.expect 1
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
# Strange! why can't we make these variables local without
# the tests failing in one of the next tests...
@engine_one = cp.fork pth, [ '-n', '-w', '8642' ] # [ '-i' , 'warn' ]
@engine_one.on 'error', ( err ) ->
console.log err
fWaitForFirstStartup = () =>
@engine_two = cp.fork pth, [ '-n', '-w', '8642' ] # [ '-i' , 'warn' ]
@engine_two.on 'error', ( err ) ->
console.log err
fWaitForFirstStartup = () =>
@engine_two = cp.fork pth, [ '-n', '-w', '8642' ] # [ '-i' , 'warn' ]
@engine_two.on 'error', ( err ) ->
console.log err
@engine_two.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
setTimeout fWaitForDeath, 12000
# Garbage collect eventually still running process
fWaitForDeath = () =>
if isRunning
test.ok false, '"testHttpPortAlreadyUsed" Engine didn\'t shut down!'
test.done()
@engine_two.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
setTimeout fWaitForDeath, 12000
# Garbage collect eventually still running process
fWaitForDeath = () =>
if isRunning
test.ok false, '"testHttpPortAlreadyUsed" Engine didn\'t shut down!'
test.done()
@engine_one.kill()
@engine_two.kill()
@engine_one.kill()
@engine_two.kill()
setTimeout fWaitForFirstStartup, 1000
setTimeout fWaitForFirstStartup, 1000
exports.testHttpPortInvalid = ( test ) ->
test.expect 1
isRunning = true
pth = path.resolve 'js', '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()
engine.on 'error', ( err ) ->
console.log err
test.expect 1
isRunning = true
pth = path.resolve 'js', '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()
engine.on 'error', ( err ) ->
console.log err
# Garbage collect eventually still running process
fWaitForDeath = () ->
if isRunning
test.ok false, '"testHttpPortInvalid" Engine didn\'t shut down!'
test.done()
# engine.kill()
# Garbage collect eventually still running process
fWaitForDeath = () ->
if isRunning
test.ok false, '"testHttpPortInvalid" Engine didn\'t shut down!'
test.done()
# engine.kill()
setTimeout fWaitForDeath, 12000
setTimeout fWaitForDeath, 12000
exports.testDbPortInvalid = ( test ) ->
test.expect 1
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-d', '10'] # [ '-i' , 'warn' ]
engine.on 'error', ( err ) ->
console.log err
engine.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
test.expect 1
isRunning = true
pth = path.resolve 'js', 'webapi-eca'
engine = cp.fork pth, [ '-n', '-d', '10'] # [ '-i' , 'warn' ]
engine.on 'error', ( err ) ->
console.log err
engine.on 'exit', ( code, signal ) ->
test.ok true, 'Engine stopped'
isRunning = false
test.done()
# Garbage collect eventually still running process
fWaitForDeath = () ->
engine.kill()
if isRunning
test.ok false, '"testHttpPortInvalid" Engine didn\'t shut down!'
test.done()
# Garbage collect eventually still running process
fWaitForDeath = () ->
engine.kill()
if isRunning
test.ok false, '"testHttpPortInvalid" Engine didn\'t shut down!'
test.done()
setTimeout fWaitForDeath, 12000
setTimeout fWaitForDeath, 12000

View file

@ -1,22 +1,22 @@
fOnLoad = () ->
document.title = 'Administrate'
$( '#pagetitle' ).text 'Hi {{{user.username}}}, issue your commands please:'
$( '#but_submit' ).click () ->
data =
command: $( '#inp_command' ).val()
$.post( 'admincommand', data )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
fDelayed = () ->
if err.responseText is ''
err.responseText = 'No Response from Server!'
$( '#info' ).text 'Error: ' + err.responseText
$( '#info' ).attr 'class', 'error'
if err.status is 401
window.location.href = 'admin'
setTimeout fDelayed, 500
document.title = 'Administrate'
$( '#pagetitle' ).text 'Hi {{{user.username}}}, issue your commands please:'
$( '#but_submit' ).click () ->
data =
command: $( '#inp_command' ).val()
$.post( 'admincommand', data )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
fDelayed = () ->
if err.responseText is ''
err.responseText = 'No Response from Server!'
$( '#info' ).text 'Error: ' + err.responseText
$( '#info' ).attr 'class', 'error'
if err.status is 401
window.location.href = 'admin'
setTimeout fDelayed, 500
window.addEventListener 'load', fOnLoad, true

View file

@ -1,111 +1,111 @@
fOnLoad = () ->
document.title = 'Edit Modules'
$( '#pagetitle' ).text "{{{user.username}}}, edit your Modules!"
document.title = 'Edit Modules'
$( '#pagetitle' ).text "{{{user.username}}}, edit your Modules!"
moduleType = $( '#module_type' ).val()
$( '#module_type' ).change () ->
moduleType = $( this ).val()
console.log moduleType
fFetchModules()
moduleType = $( '#module_type' ).val()
$( '#module_type' ).change () ->
moduleType = $( this ).val()
console.log moduleType
fFetchModules()
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.setReadOnly true
editor.setShowPrintMargin false
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.setReadOnly true
editor.setShowPrintMargin false
fErrHandler = ( errMsg ) ->
( err ) ->
if err.status is 401
window.location.href = 'forge?page=edit_modules'
else
$( '#moduleName' ).html "<h2>&nbsp;</h2>"
$( '#moduleLanguage' ).html "<b>&nbsp;</b>"
editor.setValue ""
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text errMsg + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
fErrHandler = ( errMsg ) ->
( err ) ->
if err.status is 401
window.location.href = 'forge?page=edit_modules'
else
$( '#moduleName' ).html "<h2>&nbsp;</h2>"
$( '#moduleLanguage' ).html "<b>&nbsp;</b>"
editor.setValue ""
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text errMsg + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
fFetchModules = () ->
if moduleType is 'Event Poller'
cmd = 'get_event_pollers'
else
cmd = 'get_action_invokers'
$.post( '/usercommand', command: cmd )
.done fUpdateModuleList
.fail fErrHandler 'Did not retrieve rules! '
fFetchModules = () ->
if moduleType is 'Event Poller'
cmd = 'get_event_pollers'
else
cmd = 'get_action_invokers'
$.post( '/usercommand', command: cmd )
.done fUpdateModuleList
.fail fErrHandler 'Did not retrieve rules! '
fUpdateModuleList = ( data ) ->
$( '#tableModules tr' ).remove()
oMods = JSON.parse data.message
for modName of oMods
tr = $ '<tr>'
inp = $( '<div>' ).text modName
img = $( '<img>' ).attr( 'class', 'del' )
.attr( 'title', 'Delete Module' ).attr 'src', 'red_cross_small.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'log' )
.attr( 'title', 'Edit Module' ).attr 'src', 'edit.png'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append inp )
$( '#tableModules' ).append tr
fUpdateModuleList = ( data ) ->
$( '#tableModules tr' ).remove()
oMods = JSON.parse data.message
for modName of oMods
tr = $ '<tr>'
inp = $( '<div>' ).text modName
img = $( '<img>' ).attr( 'class', 'del' )
.attr( 'title', 'Delete Module' ).attr 'src', 'red_cross_small.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'log' )
.attr( 'title', 'Edit Module' ).attr 'src', 'edit.png'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append inp )
$( '#tableModules' ).append tr
fFetchModules()
fFetchModules()
$( '#tableModules' ).on 'click', 'img.del', () ->
modName = $( 'div', $( this ).closest( 'tr' )).text()
if confirm "Do you really want to delete the Module '#{ modName }'?
The module might still be active in some of your rules!"
$( '#moduleName' ).html "<h2>&nbsp;</h2>"
$( '#moduleLanguage' ).html "<b>&nbsp;</b>"
editor.setValue ""
if moduleType is 'Event Poller'
cmd = 'delete_event_poller'
else
cmd = 'delete_action_invoker'
data =
command: cmd
payload:
id: modName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done fFetchModules
.fail fErrHandler 'Could not delete module! '
$( '#tableModules' ).on 'click', 'img.del', () ->
modName = $( 'div', $( this ).closest( 'tr' )).text()
if confirm "Do you really want to delete the Module '#{ modName }'?
The module might still be active in some of your rules!"
$( '#moduleName' ).html "<h2>&nbsp;</h2>"
$( '#moduleLanguage' ).html "<b>&nbsp;</b>"
editor.setValue ""
if moduleType is 'Event Poller'
cmd = 'delete_event_poller'
else
cmd = 'delete_action_invoker'
data =
command: cmd
payload:
id: modName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done fFetchModules
.fail fErrHandler 'Could not delete module! '
$( '#tableModules' ).on 'click', 'img.log', () ->
modName = $( 'div', $( this ).closest( 'tr' )).text()
if moduleType is 'Event Poller'
cmd = 'get_full_event_poller'
else
cmd = 'get_full_action_invoker'
data =
command: cmd
payload:
id: modName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done ( data ) ->
try
oMod = JSON.parse data.message
catch err
fErrHandler err.message
if oMod.lang is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
editor.setValue oMod.data
editor.gotoLine 1, 1
editor.scrollToRow 1
$( '#moduleName' ).html "<h2>#{ oMod.id }</h2>"
$( '#moduleLanguage' ).html "<b>#{ oMod.lang }</b>"
$( '#tableModules' ).on 'click', 'img.log', () ->
modName = $( 'div', $( this ).closest( 'tr' )).text()
if moduleType is 'Event Poller'
cmd = 'get_full_event_poller'
else
cmd = 'get_full_action_invoker'
data =
command: cmd
payload:
id: modName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done ( data ) ->
try
oMod = JSON.parse data.message
catch err
fErrHandler err.message
if oMod.lang is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
editor.setValue oMod.data
editor.gotoLine 1, 1
editor.scrollToRow 1
$( '#moduleName' ).html "<h2>#{ oMod.id }</h2>"
$( '#moduleLanguage' ).html "<b>#{ oMod.lang }</b>"
.fail fErrHandler 'Could not get module! '
.fail fErrHandler 'Could not get module! '
window.addEventListener 'load', fOnLoad, true

View file

@ -12,112 +12,112 @@
fOnLoad = () ->
document.title = 'Edit Rules'
$( '#pagetitle' ).text "{{{user.username}}}, edit your Rules!"
document.title = 'Edit Rules'
$( '#pagetitle' ).text "{{{user.username}}}, edit your Rules!"
fErrHandler = ( errMsg ) ->
( err ) ->
if err.status is 401
window.location.href = 'forge?page=edit_rules'
else
$( '#log_col' ).text ""
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text errMsg + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
fErrHandler = ( errMsg ) ->
( err ) ->
if err.status is 401
window.location.href = 'forge?page=edit_rules'
else
$( '#log_col' ).text ""
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text errMsg + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
fFetchRules = () ->
$.post( '/usercommand', command: 'get_rules' )
.done fUpdateRuleList
.fail fErrHandler 'Did not retrieve rules! '
fFetchRules = () ->
$.post( '/usercommand', command: 'get_rules' )
.done fUpdateRuleList
.fail fErrHandler 'Did not retrieve rules! '
fUpdateRuleList = ( data ) ->
$( '#tableRules tr' ).remove()
for ruleName in data.message
tr = $ '<tr>'
img = $( '<img>' ).attr( 'class', 'del' )
.attr( 'title', 'Delete Rule' ).attr 'src', 'red_cross_small.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'edit' )
.attr( 'title', 'Edit Rule' ).attr 'src', 'edit.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'log' )
.attr( 'title', 'Show Rule Log' ).attr 'src', 'logicon.png'
tr.append( $( '<td>' ).append img )
inp = $( '<div>' ).text ruleName
tr.append( $( '<td>' ).append inp )
$( '#tableRules' ).append tr
fUpdateRuleList = ( data ) ->
$( '#tableRules tr' ).remove()
for ruleName in data.message
tr = $ '<tr>'
img = $( '<img>' ).attr( 'class', 'del' )
.attr( 'title', 'Delete Rule' ).attr 'src', 'red_cross_small.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'edit' )
.attr( 'title', 'Edit Rule' ).attr 'src', 'edit.png'
tr.append( $( '<td>' ).append img )
img = $( '<img>' ).attr( 'class', 'log' )
.attr( 'title', 'Show Rule Log' ).attr 'src', 'logicon.png'
tr.append( $( '<td>' ).append img )
inp = $( '<div>' ).text ruleName
tr.append( $( '<td>' ).append inp )
$( '#tableRules' ).append tr
fFetchRules()
fFetchRules()
$( '#tableRules' ).on 'click', 'img.del', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
if confirm "Do you really want to delete the rule '#{ ruleName }'?"
$( '#log_col' ).text ""
data =
command: 'delete_rule'
payload:
id: ruleName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done fFetchRules
.fail fErrHandler 'Could not delete rule! '
$( '#tableRules' ).on 'click', 'img.del', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
if confirm "Do you really want to delete the rule '#{ ruleName }'?"
$( '#log_col' ).text ""
data =
command: 'delete_rule'
payload:
id: ruleName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done fFetchRules
.fail fErrHandler 'Could not delete rule! '
$( '#tableRules' ).on 'click', 'img.edit', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
window.location.href = 'forge?page=forge_rule&id=' + encodeURIComponent ruleName
$( '#tableRules' ).on 'click', 'img.edit', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
window.location.href = 'forge?page=forge_rule&id=' + encodeURIComponent ruleName
$( '#tableRules' ).on 'click', 'img.log', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
data =
command: 'get_rule_log'
payload:
id: ruleName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done ( data ) ->
log = data.message.replace new RegExp("\n", 'g'), "<br>"
$( '#log_col' ).html "<h3>#{ ruleName } Log:</h3>#{ log }"
.fail fErrHandler 'Could not get rule log! '
$( '#tableRules' ).on 'click', 'img.log', () ->
ruleName = $( 'div', $( this ).closest( 'tr' )).text()
data =
command: 'get_rule_log'
payload:
id: ruleName
data.payload = JSON.stringify data.payload
$.post( '/usercommand', data )
.done ( data ) ->
log = data.message.replace new RegExp("\n", 'g'), "<br>"
$( '#log_col' ).html "<h3>#{ ruleName } Log:</h3>#{ log }"
.fail fErrHandler 'Could not get rule log! '
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest 'tr'
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append $( '<td>' ).append img
tr.append $( '<td>' ).append cb
tr.append $( '<td>' ).append inp
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest 'tr'
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append $( '<td>' ).append img
tr.append $( '<td>' ).append cb
tr.append $( '<td>' ).append inp
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
fChangeInputVisibility()
fChangeInputVisibility()
window.addEventListener 'load', fOnLoad, true

View file

@ -1,95 +1,95 @@
fOnLoad = () ->
document.title = 'Forge Action Invoker'
$( '#pagetitle' ).text "{{{user.username}}}, forge your custom action invoker!"
document.title = 'Forge Action Invoker'
$( '#pagetitle' ).text "{{{user.username}}}, forge your custom action invoker!"
# Setup the ACE editor
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/coffee"
editor.setShowPrintMargin false
editor.session.setUseSoftTabs false
$( '#editor_mode' ).change ( el ) ->
if $( this ).val() is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
# Setup the ACE editor
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/coffee"
editor.setShowPrintMargin false
editor.session.setUseSoftTabs false
$( '#editor_mode' ).change ( el ) ->
if $( this ).val() is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest( 'tr' )
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append cb )
tr.append( $( '<td>' ).append inp )
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest( 'tr' )
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append cb )
tr.append( $( '<td>' ).append inp )
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
fChangeInputVisibility()
fChangeInputVisibility()
# Add submit button logic
$( '#but_submit' ).click () ->
if $( '#input_id' ).val() is ''
alert 'Please enter an action invoker name!'
else
listParams = {}
$( '#tableParams tr' ).each () ->
val = $( 'input.textinput', this ).val()
shld = $( 'input[type=checkbox]', this ).is ':checked'
if val isnt ""
listParams[val] = shld
true
obj =
command: 'forge_action_invoker'
payload:
id: $( '#input_id' ).val()
lang: $( '#editor_mode' ).val()
public: $( '#is_public' ).is ':checked'
data: editor.getValue()
params: JSON.stringify listParams
obj.payload = JSON.stringify obj.payload
window.scrollTo 0, 0
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_action_invoker'
else
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text 'Action Invoker not stored! ' + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
# Add submit button logic
$( '#but_submit' ).click () ->
if $( '#input_id' ).val() is ''
alert 'Please enter an action invoker name!'
else
listParams = {}
$( '#tableParams tr' ).each () ->
val = $( 'input.textinput', this ).val()
shld = $( 'input[type=checkbox]', this ).is ':checked'
if val isnt ""
listParams[val] = shld
true
obj =
command: 'forge_action_invoker'
payload:
id: $( '#input_id' ).val()
lang: $( '#editor_mode' ).val()
public: $( '#is_public' ).is ':checked'
data: editor.getValue()
params: JSON.stringify listParams
obj.payload = JSON.stringify obj.payload
window.scrollTo 0, 0
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_action_invoker'
else
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text 'Action Invoker not stored! ' + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
window.addEventListener 'load', fOnLoad, true

View file

@ -1,38 +1,38 @@
fOnLoad = () ->
document.title = 'Event Forge!'
$( '#pagetitle' ).text 'Invoke your custom event!'
document.title = 'Event Forge!'
$( '#pagetitle' ).text 'Invoke your custom event!'
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/json"
editor.setShowPrintMargin false
$( '#editor' ).css 'height', '400px'
$( '#editor' ).css 'width', '600px'
$( '#but_submit' ).click () ->
try
val = editor.getValue()
JSON.parse val # try to parse, throw an error if JSON not valid
window.scrollTo 0, 0
$.post( '/event', val )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_event'
else
fDelayed = () ->
if err.responseText is ''
err.responseText = 'No Response from Server!'
$( '#info' ).text 'Error in upload: ' + err.responseText
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
catch err
$( '#info' ).text 'You have errors in your JSON object! ' + err
$( '#info' ).attr 'class', 'error'
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/json"
editor.setShowPrintMargin false
$( '#editor' ).css 'height', '400px'
$( '#editor' ).css 'width', '600px'
$( '#but_submit' ).click () ->
try
val = editor.getValue()
JSON.parse val # try to parse, throw an error if JSON not valid
window.scrollTo 0, 0
$.post( '/event', val )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_event'
else
fDelayed = () ->
if err.responseText is ''
err.responseText = 'No Response from Server!'
$( '#info' ).text 'Error in upload: ' + err.responseText
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
catch err
$( '#info' ).text 'You have errors in your JSON object! ' + err
$( '#info' ).attr 'class', 'error'
window.addEventListener 'load', fOnLoad, true

View file

@ -1,95 +1,95 @@
fOnLoad = () ->
document.title = 'Forge Event Poller'
$( '#pagetitle' ).text "{{{user.username}}}, forge your custom event poller!"
document.title = 'Forge Event Poller'
$( '#pagetitle' ).text "{{{user.username}}}, forge your custom event poller!"
# Setup the ACE editor
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/coffee"
editor.setShowPrintMargin false
$( '#editor_mode' ).change ( el ) ->
if $( this ).val() is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
# Setup the ACE editor
editor = ace.edit "editor"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/coffee"
editor.setShowPrintMargin false
$( '#editor_mode' ).change ( el ) ->
if $( this ).val() is 'CoffeeScript'
editor.getSession().setMode "ace/mode/coffee"
else
editor.getSession().setMode "ace/mode/javascript"
# Add parameter list functionality
fChangeInputVisibility = () ->
$( '#tableParams tr' ).each ( id ) ->
if $( this ).is ':last-child' or $( this ).is ':only-child'
$( 'img', this ).hide()
$( 'input[type=checkbox]', this ).hide()
else
$( 'img', this ).show()
$( 'input[type=checkbox]', this ).show()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'click', 'img', () ->
par = $( this ).closest 'tr'
if not par.is ':last-child'
par.remove()
fChangeInputVisibility()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest( 'tr' )
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append cb )
tr.append( $( '<td>' ).append inp )
tr.append $( '<td>' )
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
$( '#tableParams' ).on 'keyup', 'input', ( e ) ->
code = e.keyCode or e.which
if code isnt 9
par = $( this ).closest( 'tr' )
if par.is ':last-child'
tr = $ '<tr>'
img = $( '<img>' ).attr( 'title', 'Remove?').attr 'src', 'red_cross_small.png'
cb = $( '<input>' ).attr( 'type', 'checkbox' ).attr 'title', 'Password shielded input?'
inp = $( '<input>' ).attr( 'type', 'text' ).attr 'class', 'textinput'
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append cb )
tr.append( $( '<td>' ).append inp )
tr.append $( '<td>' )
par.parent().append tr
fChangeInputVisibility()
else if $( this ).val() is '' and not par.is ':only-child'
par.remove()
fChangeInputVisibility()
fChangeInputVisibility()
# Add submit button logic
$( '#but_submit' ).click () ->
if $( '#input_id' ).val() is ''
alert 'Please enter an event poller name!'
else
listParams = {}
$( '#tableParams tr' ).each () ->
val = $( 'input.textinput', this ).val()
shld = $( 'input[type=checkbox]', this ).is ':checked'
if val isnt ""
listParams[val] = shld
true
obj =
command: 'forge_event_poller'
payload:
id: $( '#input_id' ).val()
lang: $( '#editor_mode' ).val()
public: $( '#is_public' ).is ':checked'
data: editor.getValue()
params: JSON.stringify listParams
obj.payload = JSON.stringify obj.payload
window.scrollTo 0, 0
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_event_poller'
else
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text 'Event Poller not stored! ' + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
# Add submit button logic
$( '#but_submit' ).click () ->
if $( '#input_id' ).val() is ''
alert 'Please enter an event poller name!'
else
listParams = {}
$( '#tableParams tr' ).each () ->
val = $( 'input.textinput', this ).val()
shld = $( 'input[type=checkbox]', this ).is ':checked'
if val isnt ""
listParams[val] = shld
true
obj =
command: 'forge_event_poller'
payload:
id: $( '#input_id' ).val()
lang: $( '#editor_mode' ).val()
public: $( '#is_public' ).is ':checked'
data: editor.getValue()
params: JSON.stringify listParams
obj.payload = JSON.stringify obj.payload
window.scrollTo 0, 0
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_event_poller'
else
fDelayed = () ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
oErr = JSON.parse err.responseText
msg = oErr.message
$( '#info' ).text 'Event Poller not stored! ' + msg
$( '#info' ).attr 'class', 'error'
setTimeout fDelayed, 500
window.addEventListener 'load', fOnLoad, true

View file

@ -1,280 +1,332 @@
strPublicKey = ''
fPlaceAndPaintInterval = () ->
$( '#input_interval' ).html 'Interval:
<input id="event_interval" type="text" />
<b>"days hours:minutes"</b>, default = 10 minutes'
fFailedRequest = ( msg ) ->
( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_rule'
else
$( '#info' ).text msg
$( '#info' ).attr 'class', 'error'
( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_rule'
else
$( '#info' ).text msg
$( '#info' ).attr 'class', 'error'
$.post( '/usercommand', command: 'get_public_key' )
.done ( data ) ->
strPublicKey = data.message
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_rule'
else
$( '#info' ).text 'Error fetching public key, unable to send user specific parameters securely'
$( '#info' ).attr 'class', 'error'
.done ( data ) ->
strPublicKey = data.message
.fail ( err ) ->
if err.status is 401
window.location.href = 'forge?page=forge_rule'
else
$( '#info' ).text 'Error fetching public key, unable to send user specific parameters securely'
$( '#info' ).attr 'class', 'error'
fOnLoad = () ->
document.title = 'Rule Forge!'
$( '#pagetitle' ).text '{{{user.username}}}, forge your ECA Rule!'
document.title = 'Rule Forge!'
$( '#pagetitle' ).text '{{{user.username}}}, forge your ECA Rule!'
editor = ace.edit "editor_conditions"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/json"
editor.setShowPrintMargin false
# editor.session.setUseSoftTabs false
editor = ace.edit "editor_conditions"
editor.setTheme "ace/theme/monokai"
editor.getSession().setMode "ace/mode/json"
editor.setShowPrintMargin false
# editor.session.setUseSoftTabs false
# Fetch Event Poller user-specific parameters
fFetchEventParams = ( name ) ->
if name
arr = name.split ' -> '
obj =
command: 'get_event_poller_params'
payload:
id: arr[0]
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
$( '#event_poller_params table' ).remove()
table = $ '<table>'
$( '#event_poller_params' ).append table
fAppendParam = ( name, shielded ) ->
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key' ).text name
inp = $( '<input>' ).attr 'id', "#{ name }"
if shielded
inp.attr( 'type', 'password' )
tr.append $( '<td>' ).text( ' : ' ).append inp
table.append tr
fAppendParam name, shielded for name, shielded of oParams
.fail fFailedRequest 'Error fetching event poller params'
# Fetch Event Poller user-specific parameters
fFetchEventParams = ( name ) ->
$( '#event_poller_params *' ).remove()
if name
arr = name.split ' -> '
obj =
command: 'get_event_poller_params'
payload:
id: arr[0]
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
$( '#event_poller_params' ).html '<br><b>Required Parameters:</b>'
table = $ '<table>'
$( '#event_poller_params' ).append table
fAppendParam = ( name, shielded ) ->
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key' ).text name
inp = $( '<input>' ).attr 'id', "#{ name }"
if shielded
inp.attr( 'type', 'password' )
tr.append $( '<td>' ).text( ' : ' ).append inp
table.append tr
fAppendParam name, shielded for name, shielded of oParams
.fail fFailedRequest 'Error fetching event poller params'
# Init Event Pollers
$.post( '/usercommand', command: 'get_event_pollers' )
.done ( data ) ->
try
oEps = JSON.parse data.message
catch err
console.error 'ERROR: non-object received from server: ' + data.message
return
fAppendEvents = ( id, events ) ->
fAppendEvent = ( evt ) ->
$( '#select_event' ).append $( '<option>' ).text id + ' -> ' + evt
fAppendEvent evt for evt in events
fAppendEvents id, events for id, events of oEps
fFetchEventParams $( '#select_event option:selected' ).text()
.fail fFailedRequest 'Error fetching event poller'
# Init Event Pollers
$.post( '/usercommand', command: 'get_event_pollers' )
.done ( data ) ->
try
oEps = JSON.parse data.message
catch err
console.error 'ERROR: non-object received from server: ' + data.message
return
fAppendEvents = ( id, events ) ->
fAppendEvent = ( evt ) ->
$( '#select_event' ).append $( '<option>' ).text id + ' -> ' + evt
fAppendEvent evt for evt in events
fAppendEvents id, events for id, events of oEps
$( '#input_event' ).val $( '#select_event' ).val()
fFetchEventParams $( '#select_event option:selected' ).text()
.fail fFailedRequest 'Error fetching event poller'
$( '#select_event' ).change () ->
fFetchEventParams $( this ).val()
$( '#select_event' ).change () ->
if $( this ).val() is ''
$( '#input_interval' ).html ''
else
fPlaceAndPaintInterval()
$( '#input_event' ).val $( this ).val()
fFetchEventParams $( this ).val()
# Init Action Invoker
obj =
command: 'get_action_invokers'
$.post( '/usercommand', obj )
$( '#input_event' ).change () ->
$( '#select_event' ).val ''
$( '#select_event' ).val $( this ).val()
fFetchEventParams $( '#select_event' ).val()
if $( '#select_event' ).val() is ''
$( '#input_interval' ).html ''
else
fPlaceAndPaintInterval()
.done ( data ) ->
try
oAis = JSON.parse data.message
catch err
console.error 'ERROR: non-object received from server: ' + data.message
return
fAppendActions = ( module, actions ) ->
for act in actions
$( '#select_actions' ).append $( '<option>' ).text module + ' -> ' + act
fAppendActions module, actions for module, actions of oAis
.fail fFailedRequest 'Error fetching event poller'
# Init Action Invoker
obj =
command: 'get_action_invokers'
$.post( '/usercommand', obj )
fFetchActionParams = ( div, modName ) ->
obj =
command: 'get_action_invoker_params'
payload:
id: modName
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
table = $ '<table>'
div.append table
fAppendActionParam = ( name, shielded ) ->
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key').text name
inp = $( '<input>' ).attr 'id', "#{ name }"
if shielded
inp.attr( 'type', 'password' )
else
inp.attr( 'type', 'text' )
tr.append $( '<td>' ).text(' : ').append inp
table.append tr
fAppendActionParam name, sh for name, sh of oParams
.fail fFailedRequest 'Error fetching action invoker params'
.done ( data ) ->
try
oAis = JSON.parse data.message
catch err
console.error 'ERROR: non-object received from server: ' + data.message
return
fAppendActions = ( module, actions ) ->
for act in actions
$( '#select_actions' ).append $( '<option>' ).text module + ' -> ' + act
fAppendActions module, actions for module, actions of oAis
.fail fFailedRequest 'Error fetching event poller'
fFetchActionFunctionParams = ( tag, arrName ) ->
obj =
command: 'get_action_invoker_function_params'
payload:
id: arrName[ 0 ]
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
if oParams[ arrName[ 1 ] ]
table = $( '<table>' ).appendTo tag
for functionArgument in oParams[ arrName[ 1 ] ]
tr = $( '<tr>' ).appendTo table
td = $( '<td>' ).appendTo tr
td.append $( '<div>' ).attr( 'class', 'funcarg' ).text functionArgument
tr.append td
td = $( '<td>' ).appendTo tr
td.append $( '<input>' ).attr 'type', 'text'
tr.append td
tr.append td
td = $( '<td>' ).appendTo tr
td.append $( '<input>' ).attr( 'type', 'checkbox' )
.attr 'title', 'js-select expression to be resolved on event?'
.fail fFailedRequest 'Error fetching action invoker function params'
fFetchActionParams = ( div, modName ) ->
obj =
command: 'get_action_invoker_params'
payload:
id: modName
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
table = $ '<table>'
div.append table
fAppendActionParam = ( name, shielded ) ->
#TODO check if already stored, if yes, indicate no entry is required
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key').text name
inp = $( '<input>' ).attr 'id', "#{ name }"
if shielded
inp.attr( 'type', 'password' )
else
inp.attr( 'type', 'text' )
tr.append $( '<td>' ).text(' : ').append inp
table.append tr
fAppendActionParam name, sh for name, sh of oParams
.fail fFailedRequest 'Error fetching action invoker params'
$( '#select_actions' ).on 'change', () ->
opt = $ 'option:selected', this
arrName = opt.text().split ' -> '
arrEls = $( "#action_params div.modName" ).map( () ->
$( this ).text()
).get()
table = $( '#selected_actions' )
tr = $( '<tr>' ).appendTo table
img = $( '<img>' ).attr 'src', 'red_cross_small.png'
tr.append $( '<td>' ).css( 'width', '20px' ).append img
tr.append $( '<td>' ).attr( 'class', 'title').text opt.val()
td = $( '<td>' ).attr( 'class', 'funcMappings').appendTo tr
fFetchActionFunctionParams td, arrName
if arrName[ 0 ] not in arrEls
div = $( '<div>' ).appendTo $( '#action_params' )
subdiv = $( '<div> ').appendTo div
subdiv.append $( '<div>' )
.attr( 'class', 'modName underlined' ).text arrName[ 0 ]
fFetchActionParams div, arrName[ 0 ]
opt.remove()
fFetchActionFunctionParams = ( tag, arrName ) ->
obj =
command: 'get_action_invoker_function_params'
payload:
id: arrName[ 0 ]
obj.payload = JSON.stringify( obj.payload );
$.post( '/usercommand', obj )
.done ( data ) ->
if data.message
oParams = JSON.parse data.message
if oParams[ arrName[ 1 ] ]
table = $( '<table>' ).appendTo tag
for functionArgument in oParams[ arrName[ 1 ] ]
tr = $( '<tr>' ).appendTo table
td = $( '<td>' ).appendTo tr
td.append $( '<div>' ).attr( 'class', 'funcarg' ).text functionArgument
tr.append td
td = $( '<td>' ).appendTo tr
td.append $( '<input>' ).attr 'type', 'text'
tr.append td
tr.append td
td = $( '<td>' ).appendTo tr
td.append $( '<input>' ).attr( 'type', 'checkbox' )
.attr 'title', 'js-select expression to be resolved on event?'
.fail fFailedRequest 'Error fetching action invoker function params'
$( '#selected_actions' ).on 'click', 'img', () ->
act = $( this ).closest( 'td' ).siblings( '.title' ).text()
arrName = act.split ' -> '
$( '#select_actions' ).on 'change', () ->
opt = $ 'option:selected', this
arrName = opt.text().split ' -> '
arrEls = $( "#action_params div.modName" ).map( () ->
$( this ).text()
).get()
table = $( '#selected_actions' )
tr = $( '<tr>' ).appendTo table
img = $( '<img>' ).attr 'src', 'red_cross_small.png'
tr.append $( '<td>' ).css( 'width', '20px' ).append img
tr.append $( '<td>' ).attr( 'class', 'title').text opt.val()
td = $( '<td>' ).attr( 'class', 'funcMappings').appendTo tr
fFetchActionFunctionParams td, arrName
if arrName[ 0 ] not in arrEls
div = $( '<div>' ).appendTo $( '#action_params' )
subdiv = $( '<div> ').appendTo div
subdiv.append $( '<div>' )
.attr( 'class', 'modName underlined' ).text arrName[ 0 ]
fFetchActionParams div, arrName[ 0 ]
opt.remove()
nMods = 0
# Check whether we're the only function left that was selected from this module
$( "#selected_actions td.title" ).each () ->
arrNm = $( this ).text().split ' -> '
nMods++ if arrNm[0] is arrName[0]
if nMods is 1
$('#action_params > div').each () ->
if $( this ).children( 'div.modName' ).text() is arrName[ 0 ]
$( this ).remove()
$( '#selected_actions' ).on 'click', 'img', () ->
act = $( this ).closest( 'td' ).siblings( '.title' ).text()
arrName = act.split ' -> '
opt = $( '<option>' ).text arrName[ 0 ]
$( '#select_actions' ).append opt
$( this ).closest( 'tr' ).remove()
nMods = 0
# Check whether we're the only function left that was selected from this module
$( "#selected_actions td.title" ).each () ->
arrNm = $( this ).text().split ' -> '
nMods++ if arrNm[0] is arrName[0]
if nMods is 1
$('#action_params > div').each () ->
if $( this ).children( 'div.modName' ).text() is arrName[ 0 ]
$( this ).remove()
opt = $( '<option>' ).text arrName[ 0 ]
$( '#select_actions' ).append opt
$( this ).closest( 'tr' ).remove()
$( '#but_submit' ).click () ->
try
if $( '#select_event option:selected' ).length is 0
throw new Error 'Please create an Event Poller first!'
$( '#but_submit' ).click () ->
window.scrollTo 0, 0
$( '#info' ).text ''
if $( '#input_id' ).val() is ''
throw new Error 'Please enter a rule name!'
try
if $( '#input_id' ).val() is ''
$( '#input_id' ).focus()
throw new Error 'Please enter a rule name!'
ep = {}
$( "#event_poller_params tr" ).each () ->
val = $( 'input', this ).val()
name = $( this ).children( '.key' ).text()
if val is ''
throw new Error "Please enter a value for '#{ name }' in the event module!"
ep[name] = val
if $( '#input_event' ).val() is ''
$( '#input_event' ).focus()
throw new Error 'Please assign an event!'
if $( '#selected_actions tr' ).length is 0
throw new Error 'Please select at least one action or create one!'
ep = {}
$( "#event_poller_params tr" ).each () ->
val = $( 'input', this ).val()
name = $( this ).children( '.key' ).text()
if val is ''
$( 'input', this ).focus()
throw new Error "Please enter a value for '#{ name }' in the event module!"
ep[name] = val
# Store all selected action invokers
ap = {}
$( '> div', $( '#action_params' ) ).each () ->
modName = $( '.modName', this ).text()
params = {}
$( 'tr', this ).each () ->
key = $( '.key', this ).text()
val = $( 'input', this ).val()
if val is ''
throw new Error "'#{ key }' missing for '#{ modName }'"
params[key] = val
encryptedParams = cryptico.encrypt JSON.stringify( params ), strPublicKey
ap[modName] = encryptedParams.cipher
acts = []
actParams = {}
$( '#selected_actions' ).each () ->
actionName = $( '.title', this ).text()
acts.push actionName
$( '.funcMappings tr' ).each () ->
tmp =
argument: $( 'div.funcarg', this ).val()
value: $( 'input[type=text]', this ).val()
regexp: $( 'input[type=checkbox]', this ).is( ':checked' )
actParams[ actionName ] = cryptico.encrypt JSON.stringify( tmp ), strPublicKey
try
conds = JSON.parse editor.getValue()
catch err
throw new Error "Parsing of your conditions failed! Needs to be an Array of Strings!"
if conds not instanceof Array
throw new Error "Conditions Invalid! Needs to be an Array of Strings!"
if $( '#selected_actions tr' ).length is 0
throw new Error 'Please select at least one action or create one!'
encryptedParams = cryptico.encrypt JSON.stringify( ep ), strPublicKey
obj =
command: 'forge_rule'
payload:
id: $( '#input_id' ).val()
event: $( '#select_event option:selected' ).val()
event_params: encryptedParams.cipher
conditions: conds
actions: acts
action_params: ap
action_functions: actParams
obj.payload = JSON.stringify obj.payload
window.scrollTo 0, 0
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
msg = JSON.parse( err.responseText ).message
fFailedRequest( 'Error in upload: ' + msg ) err
catch err
$( '#info' ).text 'Error in upload: ' + err.message
$( '#info' ).attr 'class', 'error'
alert err.message
# Store all selected action invokers
ap = {}
$( '> div', $( '#action_params' ) ).each () ->
modName = $( '.modName', this ).text()
params = {}
$( 'tr', this ).each () ->
key = $( '.key', this ).text()
val = $( 'input', this ).val()
if val is ''
$( 'input', this ).focus()
throw new Error "'#{ key }' missing for '#{ modName }'"
params[key] = val
encryptedParams = cryptico.encrypt JSON.stringify( params ), strPublicKey
ap[modName] = encryptedParams.cipher
acts = []
actParams = {}
$( '#selected_actions' ).each () ->
actionName = $( '.title', this ).text()
acts.push actionName
$( '.funcMappings tr' ).each () ->
tmp =
argument: $( 'div.funcarg', this ).val()
value: $( 'input[type=text]', this ).val()
regexp: $( 'input[type=checkbox]', this ).is( ':checked' )
actParams[ actionName ] = cryptico.encrypt JSON.stringify( tmp ), strPublicKey
try
conds = JSON.parse editor.getValue()
catch err
throw new Error "Parsing of your conditions failed! Needs to be an Array of Strings!"
if conds not instanceof Array
throw new Error "Conditions Invalid! Needs to be an Array of Strings!"
arrParams = window.location.search.substring(1).split '&'
id = ''
for param in arrParams
arrKV = param.split '='
if arrKV[ 0 ] is 'id'
id = decodeURIComponent arrKV[ 1 ]
if id isnt ''
console.log id
# Parse a time string
fParseTime = ( str, hasDay ) ->
arrTime = str.split ':'
# If there's only one entry, this is the amount of minutes
if arrTime.length = 1
time = parseInt( str ) || 10
if hasDay
time * 60
else
time
else
h = parseInt( arrTime[ 0 ] ) || 0
h * 60 + ( parseInt( arrTime[ 1 ] ) || 10 )
arrInp = $( '#event_interval' ).text().split ' '
# There's only one string entered, either day or hour
if arrInp.length = 1
mins = fParseTime arrInp[ 0 ]
else
d = parseInt( arrInp[ 0 ] ) || 0
mins = d * 24 * 60 + fParseTime arrInp[ 1 ], true
encryptedParams = cryptico.encrypt JSON.stringify( ep ), strPublicKey
obj =
command: 'forge_rule'
payload:
id: $( '#input_id' ).val()
event: $( '#input_event' ).val()
event_params: encryptedParams.cipher
event_interval: mins
conditions: conds
actions: acts
action_params: ap
action_functions: actParams
obj.payload = JSON.stringify obj.payload
$.post( '/usercommand', obj )
.done ( data ) ->
$( '#info' ).text data.message
$( '#info' ).attr 'class', 'success'
.fail ( err ) ->
if err.responseText is ''
msg = 'No Response from Server!'
else
try
msg = JSON.parse( err.responseText ).message
fFailedRequest( 'Error in upload: ' + msg ) err
catch err
$( '#info' ).text 'Error in upload: ' + err.message
$( '#info' ).attr 'class', 'error'
alert err.message
arrParams = window.location.search.substring(1).split '&'
id = ''
for param in arrParams
arrKV = param.split '='
if arrKV[ 0 ] is 'id'
id = decodeURIComponent arrKV[ 1 ]
if id isnt ''
console.log id

View file

@ -1,22 +1,22 @@
fOnLoad = () ->
document.title = 'Login'
$( '#pagetitle' ).text 'Login!'
document.title = 'Login'
$( '#pagetitle' ).text 'Login!'
if not window.CryptoJS
$( '#info' ).text 'CryptoJS library missing! Are you connected to the internet?'
if not window.CryptoJS
$( '#info' ).text 'CryptoJS library missing! Are you connected to the internet?'
$( '#but_submit' ).click () ->
hp = CryptoJS.SHA3 $( '#password' ).val(),
outputLength: 512
data =
username: $( '#username' ).val()
password: hp.toString()
$.post( '/login', JSON.stringify( data ) )
.done ( data ) ->
window.location.href = document.URL
.fail ( err ) ->
alert 'Authentication not successful!'
$( '#but_submit' ).click () ->
hp = CryptoJS.SHA3 $( '#password' ).val(),
outputLength: 512
data =
username: $( '#username' ).val()
password: hp.toString()
$.post( '/login', JSON.stringify( data ) )
.done ( data ) ->
window.location.href = document.URL
.fail ( err ) ->
alert 'Authentication not successful!'
window.addEventListener 'load', fOnLoad, true

View file

@ -1,10 +1,14 @@
// Generated by CoffeeScript 1.7.1
(function() {
var fFailedRequest, fOnLoad, strPublicKey,
var fFailedRequest, fOnLoad, fPlaceAndPaintInterval, strPublicKey,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
strPublicKey = '';
fPlaceAndPaintInterval = function() {
return $('#input_interval').html('Interval: <input id="event_interval" type="text" /> <b>"days hours:minutes"</b>, default = 10 minutes');
};
fFailedRequest = function(msg) {
return function(err) {
if (err.status === 401) {
@ -39,6 +43,7 @@
editor.setShowPrintMargin(false);
fFetchEventParams = function(name) {
var arr, obj;
$('#event_poller_params *').remove();
if (name) {
arr = name.split(' -> ');
obj = {
@ -52,7 +57,7 @@
var fAppendParam, oParams, shielded, table, _results;
if (data.message) {
oParams = JSON.parse(data.message);
$('#event_poller_params table').remove();
$('#event_poller_params').html('<br><b>Required Parameters:</b>');
table = $('<table>');
$('#event_poller_params').append(table);
fAppendParam = function(name, shielded) {
@ -104,11 +109,28 @@
events = oEps[id];
fAppendEvents(id, events);
}
$('#input_event').val($('#select_event').val());
return fFetchEventParams($('#select_event option:selected').text());
}).fail(fFailedRequest('Error fetching event poller'));
$('#select_event').change(function() {
if ($(this).val() === '') {
$('#input_interval').html('');
} else {
fPlaceAndPaintInterval();
}
$('#input_event').val($(this).val());
return fFetchEventParams($(this).val());
});
$('#input_event').change(function() {
$('#select_event').val('');
$('#select_event').val($(this).val());
fFetchEventParams($('#select_event').val());
if ($('#select_event').val() === '') {
return $('#input_interval').html('');
} else {
return fPlaceAndPaintInterval();
}
});
obj = {
command: 'get_action_invokers'
};
@ -254,20 +276,25 @@
return $(this).closest('tr').remove();
});
$('#but_submit').click(function() {
var actParams, acts, ap, conds, encryptedParams, ep, err;
var actParams, acts, ap, arrInp, conds, d, encryptedParams, ep, err, fParseTime, mins;
window.scrollTo(0, 0);
$('#info').text('');
try {
if ($('#select_event option:selected').length === 0) {
throw new Error('Please create an Event Poller first!');
}
if ($('#input_id').val() === '') {
$('#input_id').focus();
throw new Error('Please enter a rule name!');
}
if ($('#input_event').val() === '') {
$('#input_event').focus();
throw new Error('Please assign an event!');
}
ep = {};
$("#event_poller_params tr").each(function() {
var name, val;
val = $('input', this).val();
name = $(this).children('.key').text();
if (val === '') {
$('input', this).focus();
throw new Error("Please enter a value for '" + name + "' in the event module!");
}
return ep[name] = val;
@ -285,6 +312,7 @@
key = $('.key', this).text();
val = $('input', this).val();
if (val === '') {
$('input', this).focus();
throw new Error("'" + key + "' missing for '" + modName + "'");
}
return params[key] = val;
@ -317,13 +345,36 @@
if (!(conds instanceof Array)) {
throw new Error("Conditions Invalid! Needs to be an Array of Strings!");
}
fParseTime = function(str, hasDay) {
var arrTime, h, time;
arrTime = str.split(':');
if (arrTime.length = 1) {
time = parseInt(str) || 10;
if (hasDay) {
return time * 60;
} else {
return time;
}
} else {
h = parseInt(arrTime[0]) || 0;
return h * 60 + (parseInt(arrTime[1]) || 10);
}
};
arrInp = $('#event_interval').text().split(' ');
if (arrInp.length = 1) {
mins = fParseTime(arrInp[0]);
} else {
d = parseInt(arrInp[0]) || 0;
mins = d * 24 * 60 + fParseTime(arrInp[1], true);
}
encryptedParams = cryptico.encrypt(JSON.stringify(ep), strPublicKey);
obj = {
command: 'forge_rule',
payload: {
id: $('#input_id').val(),
event: $('#select_event option:selected').val(),
event: $('#input_event').val(),
event_params: encryptedParams.cipher,
event_interval: mins,
conditions: conds,
actions: acts,
action_params: ap,
@ -331,7 +382,6 @@
}
};
obj.payload = JSON.stringify(obj.payload);
window.scrollTo(0, 0);
return $.post('/usercommand', obj).done(function(data) {
$('#info').text(data.message);
return $('#info').attr('class', 'success');

View file

@ -52,7 +52,7 @@ callService = ( args ) ->
if not args.callback
args.callback = standardCallback 'call'
url = urlService + args.service + '/' + args.method
needlereq 'post', url, args.data, credentials, args.callback
needle.request 'post', url, args.data, credentials, args.callback
###

View file

@ -1,9 +1,9 @@
<b>Rule Name: </b><input id="input_id" type="text" /><br>
<h2>EVENT</h2>
<select id="select_event"></select>
<div id="event_poller_params">
<br><b>Required Parameters:</b>
</div>
<select id="select_event"><option></option></select><br/>
<input id="input_event" type="text" /><br/>
<div id="input_interval"></div>
<div id="event_poller_params"></div>
<br>
<h2>CONDITIONS</h2>
Refer to <a target="_blank" href="https://github.com/harthur/js-select#selectors">js-select selectors</a> for valid selectors!