mirror of
https://github.com/Hopiu/webapi-eca.git
synced 2026-03-16 22:10:31 +00:00
Engine started in coffeescript
This commit is contained in:
parent
1f4ee71cc5
commit
0cb2241ea0
302 changed files with 1679 additions and 7707 deletions
|
|
@ -13,16 +13,15 @@ Components Manager
|
|||
# - [Persistence](persistence.html)
|
||||
db = require './persistence'
|
||||
# - [Dynamic Modules](dynamic-modules.html)
|
||||
dynmod = require './dynamic-modules' #TODO Rename to code-loader
|
||||
dynmod = require './dynamic-modules'
|
||||
|
||||
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html),
|
||||
# [vm](http://nodejs.org/api/vm.html) and
|
||||
# [path](http://nodejs.org/api/path.html),
|
||||
# [path](http://nodejs.org/api/path.html) and
|
||||
# [events](http://nodejs.org/api/events.html)
|
||||
fs = require 'fs'
|
||||
vm = require 'vm'
|
||||
path = require 'path'
|
||||
events = require 'events'
|
||||
eventEmitter = new events.EventEmitter()
|
||||
|
||||
###
|
||||
Module call
|
||||
|
|
@ -33,29 +32,40 @@ Initializes the Components Manager and constructs a new Event Emitter.
|
|||
###
|
||||
exports = module.exports = ( args ) =>
|
||||
@log = args.logger
|
||||
@ee = new events.EventEmitter()
|
||||
db args
|
||||
dynmod args
|
||||
module.exports
|
||||
|
||||
|
||||
###
|
||||
Add an event handler (eh) for a certain event (evt).
|
||||
Current events are:
|
||||
Add an event handler (eh) that listens for rules.
|
||||
|
||||
- init: as soon as an event handler is added, the init events are emitted for all existing rules.
|
||||
- newRule: If a new rule is activated, the newRule event is emitted
|
||||
|
||||
@public addListener ( *evt, eh* )
|
||||
@param {String} evt
|
||||
@public addRuleListener ( *eh* )
|
||||
@param {function} eh
|
||||
###
|
||||
|
||||
exports.addListener = ( evt, eh ) =>
|
||||
@ee.addListener evt, eh
|
||||
if evt is 'init'
|
||||
db.getRules ( err, obj ) =>
|
||||
@ee.emit 'init', rule for id, rule of obj
|
||||
exports.addRuleListener = ( eh ) =>
|
||||
eventEmitter.addListener 'rule', eh
|
||||
|
||||
# Fetch all active rules per user
|
||||
db.getAllActivatedRuleIdsPerUser ( err, objUsers ) ->
|
||||
|
||||
# Go through all rules of each user
|
||||
fGoThroughUsers = ( user, rules ) ->
|
||||
|
||||
# Fetch the rules object for each rule in each user
|
||||
fFetchRule = ( rule ) ->
|
||||
db.getRule rule, ( err, oRule ) =>
|
||||
eventEmitter.emit 'rule',
|
||||
event: 'init'
|
||||
user: user
|
||||
rule: JSON.parse oRule
|
||||
|
||||
# Go through all rules for each user
|
||||
fFetchRule 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.
|
||||
|
|
@ -91,7 +101,7 @@ exports.processRequest = ( user, oReq, callback ) ->
|
|||
hasRequiredParams = ( arrParams, oPayload ) ->
|
||||
answ =
|
||||
code: 400
|
||||
message: "Your request didn't contain all necessary fields! id and params required"
|
||||
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'
|
||||
|
|
@ -125,6 +135,7 @@ getModuleParams = ( user, oPayload, dbMod, callback ) ->
|
|||
answ.message = oPayload
|
||||
callback answ
|
||||
|
||||
|
||||
forgeModule = ( user, oPayload, dbMod, callback ) =>
|
||||
answ = hasRequiredParams [ 'id', 'params', 'lang', 'data' ], oPayload
|
||||
if answ.code isnt 200
|
||||
|
|
@ -151,6 +162,11 @@ forgeModule = ( user, oPayload, dbMod, callback ) =>
|
|||
callback answ
|
||||
|
||||
commandFunctions =
|
||||
get_public_key: ( user, oPayload, callback ) ->
|
||||
callback
|
||||
code: 200
|
||||
message: dynmod.getPublicKey()
|
||||
|
||||
get_event_pollers: ( user, oPayload, callback ) ->
|
||||
getModules user, oPayload, db.eventPollers, callback
|
||||
|
||||
|
|
@ -177,12 +193,12 @@ commandFunctions =
|
|||
# - event
|
||||
# - conditions
|
||||
# - actions
|
||||
forge_rule: ( user, oPayload, callback ) =>
|
||||
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 ) =>
|
||||
db.getRule oPayload.id, ( err, oExisting ) ->
|
||||
if oExisting isnt null
|
||||
answ =
|
||||
code: 409
|
||||
|
|
@ -198,10 +214,14 @@ commandFunctions =
|
|||
db.linkRule rule.id, user.username
|
||||
db.activateRule rule.id, user.username
|
||||
if oPayload.event_params
|
||||
db.eventPollers.storeUserParams ep.module, user.username, oPayload.event_params
|
||||
epModId = rule.event.split( ' -> ' )[0]
|
||||
db.eventPollers.storeUserParams epModId, user.username, oPayload.event_params
|
||||
arrParams = oPayload.action_params
|
||||
db.actionInvokers.storeUserParams id, user.username, JSON.stringify params for id, params of arrParams
|
||||
@ee.emit 'newRule', strRule
|
||||
eventEmitter.emit 'rule',
|
||||
event: 'new'
|
||||
user: user.username
|
||||
rule: rule
|
||||
answ =
|
||||
code: 200
|
||||
message: 'Rule stored and activated!'
|
||||
|
|
|
|||
|
|
@ -6,33 +6,17 @@ Dynamic Modules
|
|||
> with only a few allowed node.js modules.
|
||||
###
|
||||
|
||||
# **Loads Modules:**
|
||||
|
||||
# - Node.js Modules: [vm](http://nodejs.org/api/vm.html) and
|
||||
# [events](http://nodejs.org/api/events.html)
|
||||
vm = require 'vm'
|
||||
needle = require 'needle'
|
||||
|
||||
# - External Modules: [coffee-script](http://coffeescript.org/)
|
||||
# - External Modules: [coffee-script](http://coffeescript.org/),
|
||||
# [cryptico](https://github.com/wwwtyro/cryptico)
|
||||
cs = require 'coffee-script'
|
||||
|
||||
|
||||
|
||||
# cryptico = require 'my-cryptico'
|
||||
|
||||
# conf = require path.join '..', 'js-coffee', 'config'
|
||||
# conf opts
|
||||
|
||||
# passPhrase = conf.getKeygenPassphrase()
|
||||
# numBits = 1024
|
||||
# console.log passPhrase
|
||||
|
||||
# oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
|
||||
# strPublicKey = cryptico.publicKeyString oPrivateRSAkey
|
||||
# plainText = "Matt, I need you to help me with my Starcraft strategy."
|
||||
# oEncrypted = cryptico.encrypt plainText, strPublicKey
|
||||
|
||||
# console.log oEncrypted.cipher
|
||||
# oDecrypted = cryptico.decrypt oEncrypted.cipher, oPrivateRSAkey
|
||||
# console.log oDecrypted.plaintext
|
||||
cryptico = require 'my-cryptico'
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,9 +29,27 @@ Initializes the dynamic module handler.
|
|||
###
|
||||
exports = module.exports = ( args ) =>
|
||||
@log = args.logger
|
||||
# FIXME this can't come through the arguments
|
||||
if not @strPublicKey and args[ 'keygen' ]
|
||||
passPhrase = args[ 'keygen' ]
|
||||
numBits = 1024
|
||||
@oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits
|
||||
@strPublicKey = cryptico.publicKeyString @oPrivateRSAkey
|
||||
@log.info "Public Key generated: #{ @strPublicKey }"
|
||||
|
||||
# plainText = "Matt, I need you to help me with my Starcraft strategy."
|
||||
# oEncrypted = cryptico.encrypt plainText, strPublicKey
|
||||
|
||||
# console.log oEncrypted.cipher
|
||||
# oDecrypted = cryptico.decrypt oEncrypted.cipher, oPrivateRSAkey
|
||||
# console.log oDecrypted.plaintext
|
||||
|
||||
module.exports
|
||||
|
||||
|
||||
exports.getPublicKey = () =>
|
||||
@strPublicKey
|
||||
|
||||
###
|
||||
Try to run a JS module from a string, together with the
|
||||
given parameters. If it is written in CoffeeScript we
|
||||
|
|
@ -59,13 +61,12 @@ compile it first into JS.
|
|||
@param {Object} params
|
||||
@param {String} lang
|
||||
###
|
||||
exports.compileString = ( src, userId, moduleId, params, lang ) =>
|
||||
exports.compileString = ( src, userId, modId, params, lang ) =>
|
||||
answ =
|
||||
code: 200
|
||||
message: 'Successfully compiled'
|
||||
|
||||
# src = "'use strict;'\n" + src
|
||||
if lang is '0'
|
||||
if lang is 'CoffeeScript'
|
||||
try
|
||||
src = cs.compile src
|
||||
catch err
|
||||
|
|
@ -74,7 +75,7 @@ exports.compileString = ( src, userId, moduleId, params, lang ) =>
|
|||
err.location.first_line
|
||||
#FIXME not log but debug module is required to provide information to the user
|
||||
sandbox =
|
||||
id: userId + '.' + moduleId + '.vm'
|
||||
id: userId + '.' + modId + '.vm'
|
||||
params: params
|
||||
needle: needle
|
||||
log: console.log
|
||||
|
|
@ -86,6 +87,8 @@ exports.compileString = ( src, userId, moduleId, params, lang ) =>
|
|||
#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
|
||||
answ.message = 'Loading Module failed: ' + err.message
|
||||
|
|
|
|||
193
coffee/engine.coffee
Normal file
193
coffee/engine.coffee
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
###
|
||||
|
||||
Engine
|
||||
==================
|
||||
> The heart of the WebAPI ECA System. The engine loads action invoker modules
|
||||
> corresponding to active rules actions and invokes them if an appropriate event
|
||||
> is retrieved.
|
||||
|
||||
###
|
||||
|
||||
# **Loads Modules:**
|
||||
|
||||
# - [Persistence](persistence.html)
|
||||
db = require './persistence'
|
||||
# - [Dynamic Modules](dynamic-modules.html)
|
||||
dynmod = require './dynamic-modules'
|
||||
|
||||
listUserRules = {}
|
||||
isRunning = false
|
||||
|
||||
###
|
||||
Module call
|
||||
-----------
|
||||
Initializes the Engine and starts polling the event queue for new events.
|
||||
|
||||
@param {Object} args
|
||||
###
|
||||
exports = module.exports = ( args ) =>
|
||||
if not isRunning
|
||||
isRunning = true
|
||||
@log = args.logger
|
||||
db args
|
||||
dynmod args
|
||||
pollQueue()
|
||||
module.exports
|
||||
|
||||
|
||||
###
|
||||
Add an event handler (eh) that listens for rules.
|
||||
|
||||
@public addRuleListener ( *eh* )
|
||||
@param {function} eh
|
||||
###
|
||||
|
||||
exports.internalEvent = ( evt ) =>
|
||||
if not listUserRules[evt.user]
|
||||
listUserRules[evt.user] =
|
||||
rules: {}
|
||||
actions: {}
|
||||
|
||||
oUser = listUserRules[evt.user]
|
||||
oRule = evt.rule
|
||||
if evt.event is 'new' or ( evt.event is 'init' and not oUser.rules[oRule.id] )
|
||||
oUser.rules[oRule.id] = oRule
|
||||
updateActionModules oRule
|
||||
|
||||
updateActionModules = ( oNewRule ) ->
|
||||
|
||||
# Remove all action invoker modules that are not required anymore
|
||||
fRemoveNotRequired = ( oUser ) ->
|
||||
|
||||
# Check whether the action is still existing in a rule
|
||||
fRequired = ( actionName ) ->
|
||||
return true for nmRl, oRl of oUser.rules when actionName in oRl.actions
|
||||
return false
|
||||
|
||||
# Go thorugh all actions and check whether the action is still required
|
||||
delete oUser.actions[action] for action of oUser.actions when not fRequired action
|
||||
|
||||
fRemoveNotRequired oUser for name, oUser of listUserRules
|
||||
|
||||
# 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 = ( oRule ) ->
|
||||
|
||||
# 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 oUser.actions[moduleName] or oRule.id is oNewRule.id
|
||||
db.actionInvokers.getModule moduleName, ( err, obj ) ->
|
||||
params = {}
|
||||
res = dynmod.compileString obj.data, userName, moduleName, params, obj.lang
|
||||
oUser.actions[moduleName] = res.module
|
||||
|
||||
fAddIfNewOrNotExisting action for action in oRule.actions
|
||||
|
||||
# Go thorugh all actions and check whether the action is still required
|
||||
fCheckRules oRl for nmRl, oRl of oUser.rules
|
||||
|
||||
fAddRequired userName, oUser for userName, oUser of listUserRules
|
||||
|
||||
pollQueue = () ->
|
||||
if isRunning
|
||||
db.popEvent ( err, obj ) ->
|
||||
if not err and obj
|
||||
processEvent obj
|
||||
setTimeout pollQueue, 50 #TODO adapt to load
|
||||
|
||||
###
|
||||
Checks whether all conditions of the rule are met by the event.
|
||||
|
||||
@private validConditions ( *evt, rule* )
|
||||
@param {Object} evt
|
||||
@param {Object} rule
|
||||
###
|
||||
validConditions = ( evt, rule ) ->
|
||||
conds = rule.conditions
|
||||
return false for prop of conds when not evt[prop] or evt[prop] isnt conds[prop]
|
||||
return true
|
||||
|
||||
###
|
||||
Handles retrieved events.
|
||||
|
||||
@private processEvent ( *evt* )
|
||||
@param {Object} evt
|
||||
###
|
||||
processEvent = ( evt ) ->
|
||||
@log.info('EN | processing event: ' + evt.event + '(' + evt.eventid + ')');
|
||||
# var actions = checkEvent(evt);
|
||||
# console.log('found actions to invoke:');
|
||||
# console.log(actions);
|
||||
# for(var user in actions) {
|
||||
# for(var module in actions[user]) {
|
||||
# for(var i = 0; i < actions[user][module]['functions'].length; i++) {
|
||||
# var act = {
|
||||
# module: module,
|
||||
# function: actions[user][module]['functions'][i]
|
||||
# }
|
||||
# invokeAction(evt, user, act);
|
||||
|
||||
# */
|
||||
# function checkEvent(evt) {
|
||||
# var actions = {}, tEvt;
|
||||
# for(var user in listRules) {
|
||||
# actions[user] = {};
|
||||
# for(var rule in listRules[user]) {
|
||||
# //TODO this needs to get depth safe, not only data but eventually also
|
||||
# // on one level above (eventid and other meta)
|
||||
# tEvt = listRules[user][rule].event;
|
||||
# if(tEvt.module + ' -> ' + tEvt.function === evt.event && validConditions(evt.payload, listRules[user][rule])) {
|
||||
# log.info('EN', 'Rule "' + rule + '" fired');
|
||||
# var oAct = listRules[user][rule].actions;
|
||||
# console.log (oAct);
|
||||
# for(var module in oAct) {
|
||||
# if(!actions[user][module]) {
|
||||
# actions[user][module] = {
|
||||
# functions: []
|
||||
# };
|
||||
# }
|
||||
# for(var i = 0; i < oAct[module]['functions'].length; i++ ){
|
||||
# console.log ('processing action ' + i + ', ' + oAct[module]['functions'][i]);
|
||||
# actions[user][module]['functions'].push(oAct[module]['functions'][i]);
|
||||
# // if(actions[user].indexOf(arrAct[i]) === -1) actions[user].push(arrAct[i]);
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# return actions;
|
||||
# }
|
||||
|
||||
# /**
|
||||
# * Invoke an action according to its type.
|
||||
# * @param {Object} evt The event that invoked the action
|
||||
# * @param {Object} action The action to be invoked
|
||||
# */
|
||||
# function invokeAction( evt, user, action ) {
|
||||
# console.log('invoking action');
|
||||
# var actionargs = {};
|
||||
# //FIXME internal events, such as loopback ha sno arrow
|
||||
# //TODO this requires change. the module property will be the identifier
|
||||
# // in the actions object (or shall we allow several times the same action?)
|
||||
# console.log(action.module);
|
||||
# console.log(listActionModules);
|
||||
# var srvc = listActionModules[user][action.module];
|
||||
# console.log(srvc);
|
||||
# if(srvc && srvc[action.function]) {
|
||||
# //FIXME preprocessing not only on data
|
||||
# //FIXME no preprocessing at all, why don't we just pass the whole event to the action?'
|
||||
# // preprocessActionArguments(evt.payload, action.arguments, actionargs);
|
||||
# try {
|
||||
# if(srvc[action.function]) srvc[action.function](evt.payload);
|
||||
# } catch(err) {
|
||||
# log.error('EN', 'during action execution: ' + err);
|
||||
# }
|
||||
# }
|
||||
# else log.info('EN', 'No api interface found for: ' + action.module);
|
||||
# }
|
||||
|
||||
exports.shutDown = () ->
|
||||
isRunning = false
|
||||
|
|
@ -129,6 +129,9 @@ init = =>
|
|||
# > 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
|
||||
|
|
@ -167,19 +170,9 @@ init = =>
|
|||
# from engine and event poller
|
||||
@log.info 'RS | Initialzing module manager'
|
||||
cm args
|
||||
cm.addListener 'init', ( evt ) ->
|
||||
poller.send
|
||||
event: 'init'
|
||||
data: evt
|
||||
cm.addListener 'newRule', ( evt ) ->
|
||||
poller.send
|
||||
event: 'newRule'
|
||||
data: evt
|
||||
cm.addListener 'init', ( evt ) ->
|
||||
engine.internalEvent 'init', evt
|
||||
cm.addListener 'newRule', ( evt ) ->
|
||||
engine.internalEvent 'newRule', evt
|
||||
|
||||
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
|
||||
|
|
@ -195,7 +188,7 @@ Shuts down the server.
|
|||
shutDown = () =>
|
||||
@log.warn 'RS | Received shut down command!'
|
||||
db?.shutDown()
|
||||
engine?.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()
|
||||
|
|
|
|||
|
|
@ -112,7 +112,12 @@ and the engine fetches the same but modularized code from the npm repository via
|
|||
|
||||
this also allows us to send privately stored modules and rules encrypted to the user, which will then see it decrypted after it arrived at the browser
|
||||
|
||||
\subsection{Request formats}
|
||||
\subsection{Message Formats}
|
||||
\subsubsection{Internal Events}
|
||||
\subsubsubsection{Event Poller}
|
||||
\subsubsubsection{Rule events}
|
||||
\subsubsection{Client GUI}
|
||||
|
||||
|
||||
\subsubsection{User commands}
|
||||
object that has a command as string and an optional payload as a stringified JSON
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
|
||||
Components Manager
|
||||
|
|
@ -7,10 +6,12 @@ Components Manager
|
|||
> The components manager takes care of the dynamic JS modules and the rules.
|
||||
> Event Poller and Action Invoker modules are loaded as strings and stored in the database,
|
||||
> then compiled into node modules and rules and used in the engine and event poller.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var commandFunctions, db, dynmod, events, exports, forgeModule, fs, getModuleParams, getModules, hasRequiredParams, path, vm;
|
||||
var commandFunctions, db, dynmod, eventEmitter, events, exports, forgeModule, fs, getModuleParams, getModules, hasRequiredParams, path,
|
||||
_this = this;
|
||||
|
||||
db = require('./persistence');
|
||||
|
||||
|
|
@ -18,12 +19,11 @@ Components Manager
|
|||
|
||||
fs = require('fs');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
path = require('path');
|
||||
|
||||
events = require('events');
|
||||
|
||||
eventEmitter = new events.EventEmitter();
|
||||
|
||||
/*
|
||||
Module call
|
||||
|
|
@ -31,48 +31,55 @@ Components Manager
|
|||
Initializes the Components Manager and constructs a new Event Emitter.
|
||||
|
||||
@param {Object} args
|
||||
*/
|
||||
*/
|
||||
|
||||
exports = module.exports = (function(_this) {
|
||||
return function(args) {
|
||||
_this.log = args.logger;
|
||||
_this.ee = new events.EventEmitter();
|
||||
db(args);
|
||||
dynmod(args);
|
||||
return module.exports;
|
||||
};
|
||||
})(this);
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
_this.log = args.logger;
|
||||
db(args);
|
||||
dynmod(args);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
/*
|
||||
Add an event handler (eh) for a certain event (evt).
|
||||
Current events are:
|
||||
Add an event handler (eh) that listens for rules.
|
||||
|
||||
- init: as soon as an event handler is added, the init events are emitted for all existing rules.
|
||||
- newRule: If a new rule is activated, the newRule event is emitted
|
||||
|
||||
@public addListener ( *evt, eh* )
|
||||
@param {String} evt
|
||||
@public addRuleListener ( *eh* )
|
||||
@param {function} eh
|
||||
*/
|
||||
*/
|
||||
|
||||
exports.addListener = (function(_this) {
|
||||
return function(evt, eh) {
|
||||
_this.ee.addListener(evt, eh);
|
||||
if (evt === 'init') {
|
||||
return db.getRules(function(err, obj) {
|
||||
var id, rule, _results;
|
||||
_results = [];
|
||||
for (id in obj) {
|
||||
rule = obj[id];
|
||||
_results.push(_this.ee.emit('init', rule));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
|
||||
exports.addRuleListener = function(eh) {
|
||||
eventEmitter.addListener('rule', eh);
|
||||
return db.getAllActivatedRuleIdsPerUser(function(err, objUsers) {
|
||||
var fGoThroughUsers, rules, user, _results;
|
||||
fGoThroughUsers = function(user, rules) {
|
||||
var fFetchRule, rule, _i, _len, _results;
|
||||
fFetchRule = function(rule) {
|
||||
var _this = this;
|
||||
return db.getRule(rule, function(err, oRule) {
|
||||
return eventEmitter.emit('rule', {
|
||||
event: 'init',
|
||||
user: user,
|
||||
rule: JSON.parse(oRule)
|
||||
});
|
||||
});
|
||||
};
|
||||
_results = [];
|
||||
for (_i = 0, _len = rules.length; _i < _len; _i++) {
|
||||
rule = rules[_i];
|
||||
_results.push(fFetchRule(rule));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
_results = [];
|
||||
for (user in objUsers) {
|
||||
rules = objUsers[user];
|
||||
_results.push(fGoThroughUsers(user, rules));
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
|
||||
return _results;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Processes a user request coming through the request-handler.
|
||||
|
|
@ -87,7 +94,8 @@ Components Manager
|
|||
@param {Object} user
|
||||
@param {Object} oReq
|
||||
@param {function} callback
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
exports.processRequest = function(user, oReq, callback) {
|
||||
var dat, err;
|
||||
|
|
@ -117,7 +125,7 @@ Components Manager
|
|||
var answ, param, _i, _len;
|
||||
answ = {
|
||||
code: 400,
|
||||
message: "Your request didn't contain all necessary fields! id and params required"
|
||||
message: "Your request didn't contain all necessary fields! Requires: " + (arrParams.join())
|
||||
};
|
||||
for (_i = 0, _len = arrParams.length; _i < _len; _i++) {
|
||||
param = arrParams[_i];
|
||||
|
|
@ -132,7 +140,8 @@ Components Manager
|
|||
|
||||
getModules = function(user, oPayload, dbMod, callback) {
|
||||
return dbMod.getAvailableModuleIds(user.username, function(err, arrNames) {
|
||||
var answReq, fGetFunctions, id, oRes, sem, _i, _len, _results;
|
||||
var answReq, fGetFunctions, id, oRes, sem, _i, _len, _results,
|
||||
_this = this;
|
||||
oRes = {};
|
||||
answReq = function() {
|
||||
return callback({
|
||||
|
|
@ -144,18 +153,16 @@ Components Manager
|
|||
if (sem === 0) {
|
||||
return answReq();
|
||||
} else {
|
||||
fGetFunctions = (function(_this) {
|
||||
return function(id) {
|
||||
return dbMod.getModule(id, function(err, oModule) {
|
||||
if (oModule) {
|
||||
oRes[id] = JSON.parse(oModule.functions);
|
||||
}
|
||||
if (--sem === 0) {
|
||||
return answReq();
|
||||
}
|
||||
});
|
||||
};
|
||||
})(this);
|
||||
fGetFunctions = function(id) {
|
||||
return dbMod.getModule(id, function(err, oModule) {
|
||||
if (oModule) {
|
||||
oRes[id] = JSON.parse(oModule.functions);
|
||||
}
|
||||
if (--sem === 0) {
|
||||
return answReq();
|
||||
}
|
||||
});
|
||||
};
|
||||
_results = [];
|
||||
for (_i = 0, _len = arrNames.length; _i < _len; _i++) {
|
||||
id = arrNames[_i];
|
||||
|
|
@ -179,45 +186,49 @@ Components Manager
|
|||
}
|
||||
};
|
||||
|
||||
forgeModule = (function(_this) {
|
||||
return function(user, oPayload, dbMod, callback) {
|
||||
var answ;
|
||||
answ = hasRequiredParams(['id', 'params', 'lang', 'data'], oPayload);
|
||||
if (answ.code !== 200) {
|
||||
return callback(answ);
|
||||
} else {
|
||||
return dbMod.getModule(oPayload.id, function(err, mod) {
|
||||
var cm, funcs, id, name, src, _ref;
|
||||
if (mod) {
|
||||
answ.code = 409;
|
||||
answ.message = 'Event Poller module name already existing: ' + oPayload.id;
|
||||
} else {
|
||||
src = oPayload.data;
|
||||
cm = dynmod.compileString(src, user.username, oPayload.id, {}, oPayload.lang);
|
||||
answ = cm.answ;
|
||||
if (answ.code === 200) {
|
||||
funcs = [];
|
||||
_ref = cm.module;
|
||||
for (name in _ref) {
|
||||
id = _ref[name];
|
||||
funcs.push(name);
|
||||
}
|
||||
_this.log.info("CM | Storing new module with functions " + (funcs.join()));
|
||||
answ.message = "Event Poller module successfully stored! Found following function(s): " + funcs;
|
||||
oPayload.functions = JSON.stringify(funcs);
|
||||
dbMod.storeModule(user.username, oPayload);
|
||||
if (oPayload["public"] === 'true') {
|
||||
dbMod.publish(oPayload.id);
|
||||
}
|
||||
forgeModule = function(user, oPayload, dbMod, callback) {
|
||||
var answ;
|
||||
answ = hasRequiredParams(['id', 'params', 'lang', 'data'], oPayload);
|
||||
if (answ.code !== 200) {
|
||||
return callback(answ);
|
||||
} else {
|
||||
return dbMod.getModule(oPayload.id, function(err, mod) {
|
||||
var cm, funcs, id, name, src, _ref;
|
||||
if (mod) {
|
||||
answ.code = 409;
|
||||
answ.message = 'Event Poller module name already existing: ' + oPayload.id;
|
||||
} else {
|
||||
src = oPayload.data;
|
||||
cm = dynmod.compileString(src, user.username, oPayload.id, {}, oPayload.lang);
|
||||
answ = cm.answ;
|
||||
if (answ.code === 200) {
|
||||
funcs = [];
|
||||
_ref = cm.module;
|
||||
for (name in _ref) {
|
||||
id = _ref[name];
|
||||
funcs.push(name);
|
||||
}
|
||||
_this.log.info("CM | Storing new module with functions " + (funcs.join()));
|
||||
answ.message = "Event Poller module successfully stored! Found following function(s): " + funcs;
|
||||
oPayload.functions = JSON.stringify(funcs);
|
||||
dbMod.storeModule(user.username, oPayload);
|
||||
if (oPayload["public"] === 'true') {
|
||||
dbMod.publish(oPayload.id);
|
||||
}
|
||||
}
|
||||
return callback(answ);
|
||||
});
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
}
|
||||
return callback(answ);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
commandFunctions = {
|
||||
get_public_key: function(user, oPayload, callback) {
|
||||
return callback({
|
||||
code: 200,
|
||||
message: dynmod.getPublicKey()
|
||||
});
|
||||
},
|
||||
get_event_pollers: function(user, oPayload, callback) {
|
||||
return getModules(user, oPayload, db.eventPollers, callback);
|
||||
},
|
||||
|
|
@ -239,50 +250,53 @@ Components Manager
|
|||
get_rules: function(user, oPayload, callback) {
|
||||
return console.log('CM | Implement get_rules');
|
||||
},
|
||||
forge_rule: (function(_this) {
|
||||
return function(user, oPayload, callback) {
|
||||
var answ;
|
||||
answ = hasRequiredParams(['id', 'event', 'conditions', 'actions'], oPayload);
|
||||
if (answ.code !== 200) {
|
||||
return callback(answ);
|
||||
} else {
|
||||
return db.getRule(oPayload.id, function(err, oExisting) {
|
||||
var arrParams, id, params, rule, strRule;
|
||||
if (oExisting !== 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) {
|
||||
db.eventPollers.storeUserParams(ep.module, user.username, oPayload.event_params);
|
||||
}
|
||||
arrParams = oPayload.action_params;
|
||||
for (id in arrParams) {
|
||||
params = arrParams[id];
|
||||
db.actionInvokers.storeUserParams(id, user.username, JSON.stringify(params));
|
||||
}
|
||||
_this.ee.emit('newRule', strRule);
|
||||
answ = {
|
||||
code: 200,
|
||||
message: 'Rule stored and activated!'
|
||||
};
|
||||
forge_rule: function(user, oPayload, callback) {
|
||||
var answ;
|
||||
answ = hasRequiredParams(['id', 'event', 'conditions', 'actions'], oPayload);
|
||||
if (answ.code !== 200) {
|
||||
return callback(answ);
|
||||
} else {
|
||||
return db.getRule(oPayload.id, function(err, oExisting) {
|
||||
var arrParams, epModId, id, params, rule, strRule;
|
||||
if (oExisting !== 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);
|
||||
}
|
||||
return callback(answ);
|
||||
});
|
||||
}
|
||||
};
|
||||
})(this)
|
||||
arrParams = oPayload.action_params;
|
||||
for (id in arrParams) {
|
||||
params = arrParams[id];
|
||||
db.actionInvokers.storeUserParams(id, user.username, JSON.stringify(params));
|
||||
}
|
||||
eventEmitter.emit('rule', {
|
||||
event: 'new',
|
||||
user: user.username,
|
||||
rule: rule
|
||||
});
|
||||
answ = {
|
||||
code: 200,
|
||||
message: 'Rule stored and activated!'
|
||||
};
|
||||
}
|
||||
return callback(answ);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
|
||||
Configuration
|
||||
=============
|
||||
> Loads the configuration file and acts as an interface to it.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var exports, fetchProp, fs, loadConfigFile, path;
|
||||
var exports, fetchProp, fs, loadConfigFile, path,
|
||||
_this = this;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
|
||||
/*
|
||||
Module call
|
||||
-----------
|
||||
|
|
@ -24,23 +24,21 @@ Configuration
|
|||
be generated) and configPath for a custom configuration file path.
|
||||
|
||||
@param {Object} args
|
||||
*/
|
||||
*/
|
||||
|
||||
exports = module.exports = (function(_this) {
|
||||
return function(args) {
|
||||
args = args != null ? args : {};
|
||||
if (args.nolog) {
|
||||
_this.nolog = true;
|
||||
}
|
||||
if (args.configPath) {
|
||||
loadConfigFile(args.configPath);
|
||||
} else {
|
||||
loadConfigFile(path.join('config', 'system.json'));
|
||||
}
|
||||
return module.exports;
|
||||
};
|
||||
})(this);
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args != null ? args : {};
|
||||
if (args.nolog) {
|
||||
_this.nolog = true;
|
||||
}
|
||||
if (args.configPath) {
|
||||
loadConfigFile(args.configPath);
|
||||
} else {
|
||||
loadConfigFile(path.join('config', 'system.json'));
|
||||
}
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
/*
|
||||
Tries to load a configuration file from the path relative to this module's parent folder.
|
||||
|
|
@ -48,102 +46,97 @@ Configuration
|
|||
|
||||
@private loadConfigFile
|
||||
@param {String} configPath
|
||||
*/
|
||||
*/
|
||||
|
||||
loadConfigFile = (function(_this) {
|
||||
return function(configPath) {
|
||||
var confProperties, e, prop, _i, _len;
|
||||
_this.config = null;
|
||||
confProperties = ['log', 'http-port', 'db-port'];
|
||||
try {
|
||||
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath)));
|
||||
_this.isReady = true;
|
||||
for (_i = 0, _len = confProperties.length; _i < _len; _i++) {
|
||||
prop = confProperties[_i];
|
||||
if (!_this.config[prop]) {
|
||||
_this.isReady = false;
|
||||
}
|
||||
}
|
||||
if (!_this.isReady && !_this.nolog) {
|
||||
return console.error("Missing property in config file, requires:\n" + (" - " + (confProperties.join("\n - "))));
|
||||
}
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
_this.isReady = false;
|
||||
if (!_this.nolog) {
|
||||
return console.error("Failed loading config file: " + e.message);
|
||||
|
||||
loadConfigFile = function(configPath) {
|
||||
var confProperties, e, prop, _i, _len;
|
||||
_this.config = null;
|
||||
confProperties = ['log', 'http-port', 'db-port'];
|
||||
try {
|
||||
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath)));
|
||||
_this.isReady = true;
|
||||
for (_i = 0, _len = confProperties.length; _i < _len; _i++) {
|
||||
prop = confProperties[_i];
|
||||
if (!_this.config[prop]) {
|
||||
_this.isReady = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
|
||||
if (!_this.isReady && !_this.nolog) {
|
||||
return console.error("Missing property in config file, requires:\n" + (" - " + (confProperties.join("\n - "))));
|
||||
}
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
_this.isReady = false;
|
||||
if (!_this.nolog) {
|
||||
return console.error("Failed loading config file: " + e.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Fetch a property from the configuration
|
||||
|
||||
@private fetchProp( *prop* )
|
||||
@param {String} prop
|
||||
*/
|
||||
*/
|
||||
|
||||
fetchProp = (function(_this) {
|
||||
return function(prop) {
|
||||
var _ref;
|
||||
return (_ref = _this.config) != null ? _ref[prop] : void 0;
|
||||
};
|
||||
})(this);
|
||||
|
||||
fetchProp = function(prop) {
|
||||
var _ref;
|
||||
return (_ref = _this.config) != null ? _ref[prop] : void 0;
|
||||
};
|
||||
|
||||
/*
|
||||
***Returns*** true if the config file is ready, else false
|
||||
|
||||
@public isReady()
|
||||
*/
|
||||
*/
|
||||
|
||||
exports.isReady = (function(_this) {
|
||||
return function() {
|
||||
return _this.isReady;
|
||||
};
|
||||
})(this);
|
||||
|
||||
exports.isReady = function() {
|
||||
return _this.isReady;
|
||||
};
|
||||
|
||||
/*
|
||||
***Returns*** the HTTP port
|
||||
|
||||
@public getHttpPort()
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
exports.getHttpPort = function() {
|
||||
return fetchProp('http-port');
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
***Returns*** the DB port*
|
||||
|
||||
@public getDBPort()
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
exports.getDbPort = function() {
|
||||
return fetchProp('db-port');
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
***Returns*** the log conf object
|
||||
|
||||
@public getLogConf()
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
exports.getLogConf = function() {
|
||||
return fetchProp('log');
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
***Returns*** the crypto key
|
||||
|
||||
@public getCryptoKey()
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
exports.getKeygenPassphrase = function() {
|
||||
return fetchProp('keygen-passphrase');
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
|
||||
Dynamic Modules
|
||||
===============
|
||||
> Compiles CoffeeScript modules and loads JS modules in a VM, together
|
||||
> with only a few allowed node.js modules.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var cs, exports, needle, vm;
|
||||
var cryptico, cs, exports, needle, vm,
|
||||
_this = this;
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ Dynamic Modules
|
|||
|
||||
cs = require('coffee-script');
|
||||
|
||||
cryptico = require('my-cryptico');
|
||||
|
||||
/*
|
||||
Module call
|
||||
|
|
@ -24,15 +26,25 @@ Dynamic Modules
|
|||
Initializes the dynamic module handler.
|
||||
|
||||
@param {Object} args
|
||||
*/
|
||||
*/
|
||||
|
||||
exports = module.exports = (function(_this) {
|
||||
return function(args) {
|
||||
_this.log = args.logger;
|
||||
return module.exports;
|
||||
};
|
||||
})(this);
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
var numBits, passPhrase;
|
||||
_this.log = args.logger;
|
||||
if (!_this.strPublicKey && args['keygen']) {
|
||||
passPhrase = args['keygen'];
|
||||
numBits = 1024;
|
||||
_this.oPrivateRSAkey = cryptico.generateRSAKey(passPhrase, numBits);
|
||||
_this.strPublicKey = cryptico.publicKeyString(_this.oPrivateRSAkey);
|
||||
_this.log.info("Public Key generated: " + _this.strPublicKey);
|
||||
}
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
exports.getPublicKey = function() {
|
||||
return _this.strPublicKey;
|
||||
};
|
||||
|
||||
/*
|
||||
Try to run a JS module from a string, together with the
|
||||
|
|
@ -44,44 +56,43 @@ Dynamic Modules
|
|||
@param {String} id
|
||||
@param {Object} params
|
||||
@param {String} lang
|
||||
*/
|
||||
*/
|
||||
|
||||
exports.compileString = (function(_this) {
|
||||
return function(src, userId, moduleId, params, lang) {
|
||||
var answ, err, ret, sandbox;
|
||||
answ = {
|
||||
code: 200,
|
||||
message: 'Successfully compiled'
|
||||
};
|
||||
if (lang === '0') {
|
||||
try {
|
||||
src = cs.compile(src);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
answ.code = 400;
|
||||
answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line;
|
||||
}
|
||||
}
|
||||
sandbox = {
|
||||
id: userId + '.' + moduleId + '.vm',
|
||||
params: params,
|
||||
needle: needle,
|
||||
log: console.log,
|
||||
exports: {}
|
||||
};
|
||||
|
||||
exports.compileString = function(src, userId, modId, params, lang) {
|
||||
var answ, err, ret, sandbox;
|
||||
answ = {
|
||||
code: 200,
|
||||
message: 'Successfully compiled'
|
||||
};
|
||||
if (lang === 'CoffeeScript') {
|
||||
try {
|
||||
vm.runInNewContext(src, sandbox, sandbox.id);
|
||||
src = cs.compile(src);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
answ.code = 400;
|
||||
answ.message = 'Loading Module failed: ' + err.message;
|
||||
answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line;
|
||||
}
|
||||
ret = {
|
||||
answ: answ,
|
||||
module: sandbox.exports
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
sandbox = {
|
||||
id: userId + '.' + modId + '.vm',
|
||||
params: params,
|
||||
needle: needle,
|
||||
log: console.log,
|
||||
exports: {}
|
||||
};
|
||||
})(this);
|
||||
try {
|
||||
vm.runInNewContext(src, sandbox, sandbox.id);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
answ.code = 400;
|
||||
answ.message = 'Loading Module failed: ' + err.message;
|
||||
}
|
||||
ret = {
|
||||
answ: answ,
|
||||
module: sandbox.exports
|
||||
};
|
||||
return ret;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
|
|||
|
|
@ -1,244 +1,183 @@
|
|||
'use strict';
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
|
||||
var path = require('path'),
|
||||
regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X
|
||||
listRules = {},
|
||||
listActionModules = {},
|
||||
isRunning = true,
|
||||
dynmod = require('./dynamic-modules'),
|
||||
db = require('./persistence'), log;
|
||||
|
||||
exports = module.exports = function( args ) {
|
||||
log = args.logger;
|
||||
db( args);
|
||||
dynmod(args);
|
||||
pollQueue();
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
var updateActionModules = function() {
|
||||
for ( var user in listRules ) {
|
||||
if(!listActionModules[user]) listActionModules[user] = {};
|
||||
for ( var rule in listRules[user] ) {
|
||||
var actions = listRules[user][rule].actions;
|
||||
console.log(actions);
|
||||
for ( var module in actions ){
|
||||
for ( var i = 0; i < actions[module]['functions'].length; i++ ){
|
||||
db.actionInvokers.getModule(module, function( err, objAM ){
|
||||
db.actionInvokers.getUserParams(module, user, function( err, objParams ) {
|
||||
console.log (objAM);
|
||||
|
||||
//FIXME am name is called 'actions'???
|
||||
// if(objParams) { //TODO we don't need them for all modules
|
||||
var answ = dynmod.compileString(objAM.code, objAM.actions + "_" + user, objParams, objAM.lang);
|
||||
console.log('answ');
|
||||
console.log(answ);
|
||||
listActionModules[user][module] = answ.module;
|
||||
console.log('loaded ' + user + ': ' + module);
|
||||
console.log(listActionModules);
|
||||
// }
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.internalEvent = function( evt, data ) {
|
||||
try {
|
||||
// TODO do we need to determine init from newRule?
|
||||
console.log (evt);
|
||||
console.log (data);
|
||||
var obj = JSON.parse( data );
|
||||
db.getRuleActivatedUsers(obj.id, function ( err, arrUsers ) {
|
||||
console.log (arrUsers);
|
||||
for(var i = 0; i < arrUsers.length; i++) {
|
||||
if( !listRules[arrUsers[i]]) listRules[arrUsers[i]] = {};
|
||||
listRules[arrUsers[i]][obj.id] = obj;
|
||||
updateActionModules();
|
||||
}
|
||||
});
|
||||
} catch( err ) {
|
||||
console.log( err );
|
||||
}
|
||||
};
|
||||
Engine
|
||||
==================
|
||||
> The heart of the WebAPI ECA System. The engine loads action invoker modules
|
||||
> corresponding to active rules actions and invokes them if an appropriate event
|
||||
> is retrieved.
|
||||
*/
|
||||
|
||||
|
||||
function pollQueue() {
|
||||
if(isRunning) {
|
||||
db.popEvent(function (err, obj) {
|
||||
if(!err && obj) {
|
||||
processEvent(obj);
|
||||
}
|
||||
setTimeout(pollQueue, 50); //TODO adapt to load
|
||||
});
|
||||
}
|
||||
}
|
||||
(function() {
|
||||
var db, dynmod, exports, isRunning, listUserRules, pollQueue, processEvent, updateActionModules, validConditions,
|
||||
_this = this,
|
||||
__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; };
|
||||
|
||||
/**
|
||||
* Handles correctly posted events
|
||||
* @param {Object} evt The event object
|
||||
*/
|
||||
function processEvent(evt) {
|
||||
log.info('EN', 'processing event: ' + evt.event + '(' + evt.eventid + ')');
|
||||
var actions = checkEvent(evt);
|
||||
console.log('found actions to invoke:');
|
||||
console.log(actions);
|
||||
for(var user in actions) {
|
||||
for(var module in actions[user]) {
|
||||
for(var i = 0; i < actions[user][module]['functions'].length; i++) {
|
||||
var act = {
|
||||
module: module,
|
||||
function: actions[user][module]['functions'][i]
|
||||
}
|
||||
invokeAction(evt, user, act);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
db = require('./persistence');
|
||||
|
||||
/**
|
||||
FIXME merge with processEvent
|
||||
dynmod = require('./dynamic-modules');
|
||||
|
||||
* Check an event against the rules repository and return the actions
|
||||
* if the conditons are met.
|
||||
* @param {Object} evt the event to check
|
||||
*/
|
||||
function checkEvent(evt) {
|
||||
var actions = {}, tEvt;
|
||||
for(var user in listRules) {
|
||||
actions[user] = {};
|
||||
for(var rule in listRules[user]) {
|
||||
//TODO this needs to get depth safe, not only data but eventually also
|
||||
// on one level above (eventid and other meta)
|
||||
tEvt = listRules[user][rule].event;
|
||||
if(tEvt.module + ' -> ' + tEvt.function === evt.event && validConditions(evt.payload, listRules[user][rule])) {
|
||||
log.info('EN', 'Rule "' + rule + '" fired');
|
||||
var oAct = listRules[user][rule].actions;
|
||||
console.log (oAct);
|
||||
for(var module in oAct) {
|
||||
if(!actions[user][module]) {
|
||||
actions[user][module] = {
|
||||
functions: []
|
||||
};
|
||||
}
|
||||
for(var i = 0; i < oAct[module]['functions'].length; i++ ){
|
||||
console.log ('processing action ' + i + ', ' + oAct[module]['functions'][i]);
|
||||
actions[user][module]['functions'].push(oAct[module]['functions'][i]);
|
||||
// if(actions[user].indexOf(arrAct[i]) === -1) actions[user].push(arrAct[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
listUserRules = {};
|
||||
|
||||
// {
|
||||
// "event": "emailyak -> newMail",
|
||||
// "payload": {
|
||||
// "TextBody": "hello"
|
||||
// }
|
||||
// }
|
||||
|
||||
// exports.sendMail = ( args ) ->
|
||||
// url = 'https://api.emailyak.com/v1/ps1g59ndfcwg10w/json/send/email/'
|
||||
|
||||
// data =
|
||||
// FromAddress: 'tester@mscliveweb.simpleyak.com'
|
||||
// ToAddress: 'dominic.bosch.db@gmail.com'
|
||||
// TextBody: 'test'
|
||||
|
||||
// needle.post url, JSON.stringify( data ), {json: true}, ( err, resp, body ) ->
|
||||
// log err
|
||||
// log body
|
||||
/**
|
||||
* Checks whether all conditions of the rule are met by the event.
|
||||
* @param {Object} evt the event to check
|
||||
* @param {Object} rule the rule with its conditions
|
||||
*/
|
||||
function validConditions(evt, rule) {
|
||||
for(var property in rule.conditions){
|
||||
if(!evt[property] || evt[property] != rule.condition[property]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke an action according to its type.
|
||||
* @param {Object} evt The event that invoked the action
|
||||
* @param {Object} action The action to be invoked
|
||||
*/
|
||||
function invokeAction( evt, user, action ) {
|
||||
console.log('invoking action');
|
||||
var actionargs = {};
|
||||
//FIXME internal events, such as loopback ha sno arrow
|
||||
//TODO this requires change. the module property will be the identifier
|
||||
// in the actions object (or shall we allow several times the same action?)
|
||||
console.log(action.module);
|
||||
console.log(listActionModules);
|
||||
var srvc = listActionModules[user][action.module];
|
||||
console.log(srvc);
|
||||
if(srvc && srvc[action.function]) {
|
||||
//FIXME preprocessing not only on data
|
||||
//FIXME no preprocessing at all, why don't we just pass the whole event to the action?'
|
||||
// preprocessActionArguments(evt.payload, action.arguments, actionargs);
|
||||
try {
|
||||
if(srvc[action.function]) srvc[action.function](evt.payload);
|
||||
} catch(err) {
|
||||
log.error('EN', 'during action execution: ' + err);
|
||||
}
|
||||
}
|
||||
else log.info('EN', 'No api interface found for: ' + action.module);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Action properties may contain event properties which need to be resolved beforehand.
|
||||
// * @param {Object} evt The event whose property values can be used in the rules action
|
||||
// * @param {Object} act The rules action arguments
|
||||
// * @param {Object} res The object to be used to enter the new properties
|
||||
// */
|
||||
// function preprocessActionArguments(evt, act, res) {
|
||||
// for(var prop in act) {
|
||||
// /*
|
||||
// * If the property is an object itself we go into recursion
|
||||
// */
|
||||
// if(typeof act[prop] === 'object') {
|
||||
// res[prop] = {};
|
||||
// preprocessActionArguments(evt, act[prop], res[prop]);
|
||||
// }
|
||||
// else {
|
||||
// var txt = act[prop];
|
||||
// var arr = txt.match(regex);
|
||||
|
||||
// * If rules action property holds event properties we resolve them and
|
||||
// * replace the original action property
|
||||
|
||||
// // console.log(evt);
|
||||
// if(arr) {
|
||||
// for(var i = 0; i < arr.length; i++) {
|
||||
// /*
|
||||
// * The first three characters are '$X.', followed by the property
|
||||
// */
|
||||
// var actionProp = arr[i].substring(3).toLowerCase();
|
||||
// // console.log(actionProp);
|
||||
// for(var eprop in evt) {
|
||||
// // our rules language doesn't care about upper or lower case
|
||||
// if(eprop.toLowerCase() === actionProp) {
|
||||
// txt = txt.replace(arr[i], evt[eprop]);
|
||||
// }
|
||||
// }
|
||||
// txt = txt.replace(arr[i], '[property not available]');
|
||||
// }
|
||||
// }
|
||||
// res[prop] = txt;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
exports.shutDown = function() {
|
||||
if(log) log.info('EN', 'Shutting down Poller and DB Link');
|
||||
isRunning = false;
|
||||
if(db) db.shutDown();
|
||||
};
|
||||
|
||||
/*
|
||||
Module call
|
||||
-----------
|
||||
Initializes the Engine and starts polling the event queue for new events.
|
||||
|
||||
@param {Object} args
|
||||
*/
|
||||
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
if (!isRunning) {
|
||||
isRunning = true;
|
||||
_this.log = args.logger;
|
||||
db(args);
|
||||
dynmod(args);
|
||||
pollQueue();
|
||||
return module.exports;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Add an event handler (eh) that listens for rules.
|
||||
|
||||
@public addRuleListener ( *eh* )
|
||||
@param {function} eh
|
||||
*/
|
||||
|
||||
|
||||
exports.internalEvent = function(evt) {
|
||||
var oRule, oUser;
|
||||
if (!listUserRules[evt.user]) {
|
||||
listUserRules[evt.user] = {
|
||||
rules: {},
|
||||
actions: {}
|
||||
};
|
||||
}
|
||||
oUser = listUserRules[evt.user];
|
||||
oRule = evt.rule;
|
||||
if (evt.event === 'new' || (evt.event === 'init' && !oUser.rules[oRule.id])) {
|
||||
oUser.rules[oRule.id] = oRule;
|
||||
return updateActionModules(oRule);
|
||||
}
|
||||
};
|
||||
|
||||
updateActionModules = function(oNewRule) {
|
||||
var fAddRequired, fRemoveNotRequired, name, oUser, userName, _results;
|
||||
fRemoveNotRequired = function(oUser) {
|
||||
var action, fRequired, _results;
|
||||
fRequired = function(actionName) {
|
||||
var nmRl, oRl, _ref;
|
||||
_ref = oUser.rules;
|
||||
for (nmRl in _ref) {
|
||||
oRl = _ref[nmRl];
|
||||
if (__indexOf.call(oRl.actions, actionName) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
_results = [];
|
||||
for (action in oUser.actions) {
|
||||
if (!fRequired(action)) {
|
||||
_results.push(delete oUser.actions[action]);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
for (name in listUserRules) {
|
||||
oUser = listUserRules[name];
|
||||
fRemoveNotRequired(oUser);
|
||||
}
|
||||
fAddRequired = function(userName, oUser) {
|
||||
var fCheckRules, nmRl, oRl, _ref, _results;
|
||||
fCheckRules = function(oRule) {
|
||||
var action, fAddIfNewOrNotExisting, _i, _len, _ref, _results;
|
||||
fAddIfNewOrNotExisting = function(actionName) {
|
||||
var moduleName;
|
||||
moduleName = (actionName.split(' -> '))[0];
|
||||
if (!oUser.actions[moduleName] || oRule.id === oNewRule.id) {
|
||||
return db.actionInvokers.getModule(moduleName, function(err, obj) {
|
||||
var params, res;
|
||||
params = {};
|
||||
res = dynmod.compileString(obj.data, userName, moduleName, params, obj.lang);
|
||||
return oUser.actions[moduleName] = res.module;
|
||||
});
|
||||
}
|
||||
};
|
||||
_ref = oRule.actions;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
action = _ref[_i];
|
||||
_results.push(fAddIfNewOrNotExisting(action));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
_ref = oUser.rules;
|
||||
_results = [];
|
||||
for (nmRl in _ref) {
|
||||
oRl = _ref[nmRl];
|
||||
_results.push(fCheckRules(oRl));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
_results = [];
|
||||
for (userName in listUserRules) {
|
||||
oUser = listUserRules[userName];
|
||||
_results.push(fAddRequired(userName, oUser));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
pollQueue = function() {
|
||||
if (isRunning) {
|
||||
return db.popEvent(function(err, obj) {
|
||||
if (!err && obj) {
|
||||
processEvent(obj);
|
||||
}
|
||||
return setTimeout(pollQueue, 50);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Checks whether all conditions of the rule are met by the event.
|
||||
|
||||
@private validConditions ( *evt, rule* )
|
||||
@param {Object} evt
|
||||
@param {Object} rule
|
||||
*/
|
||||
|
||||
|
||||
validConditions = function(evt, rule) {
|
||||
var conds, prop;
|
||||
conds = rule.conditions;
|
||||
for (prop in conds) {
|
||||
if (!evt[prop] || evt[prop] !== conds[prop]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Handles retrieved events.
|
||||
|
||||
@private processEvent ( *evt* )
|
||||
@param {Object} evt
|
||||
*/
|
||||
|
||||
|
||||
processEvent = function(evt) {
|
||||
return this.log.info('EN | processing event: ' + evt.event + '(' + evt.eventid + ')');
|
||||
};
|
||||
|
||||
exports.shutDown = function() {
|
||||
return isRunning = false;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ var logger = require('./logging'),
|
|||
|
||||
//TODO allow different polling intervals (a wrapper together with settimeout per to be polled could be an easy and solution)
|
||||
|
||||
// FIXME Eventually we don't even need to pass these arguments because they are anyways cached even over child_processes
|
||||
|
||||
function init() {
|
||||
if(process.argv.length < 7){
|
||||
|
|
@ -33,7 +34,6 @@ function init() {
|
|||
var args = { logger: log };
|
||||
(ml = require('./components-manager'))(args);
|
||||
(db = require('./persistence'))(args);
|
||||
initAdminCommands();
|
||||
initMessageActions();
|
||||
pollLoop();
|
||||
log.info('Event Poller instantiated');
|
||||
|
|
@ -106,31 +106,24 @@ function initMessageActions() {
|
|||
}
|
||||
};
|
||||
|
||||
//TODO this goes into module_manager, this will receive notification about
|
||||
// new loaded/stored event modules and fetch them from the db
|
||||
listMessageActions['cmd'] = function(args) {
|
||||
var func = listAdminCommands[args[1]];
|
||||
if(typeof(func) === 'function') func(args);
|
||||
};
|
||||
|
||||
process.on('message', function( msg ) {
|
||||
|
||||
console.log (JSON.parse(msg.data));
|
||||
console.log( 'EVENT POLLER GOT MESSAGE!');
|
||||
console.log( typeof msg);
|
||||
console.log(msg);
|
||||
// var arrProps = obj .split('|');
|
||||
// if(arrProps.length < 2) log.error('EP', 'too few parameter in message!');
|
||||
// else {
|
||||
// var func = listMessageActions[arrProps[0]];
|
||||
// if(func) func(arrProps);
|
||||
// }
|
||||
console.log('EP internal event handled');
|
||||
});
|
||||
|
||||
// very important so the process doesnt linger on when the paren process is killed
|
||||
process.on('disconnect', shutDown);
|
||||
}
|
||||
|
||||
function initAdminCommands() {
|
||||
listAdminCommands['shutdown'] = shutDown
|
||||
}
|
||||
|
||||
function checkRemotes() {
|
||||
for(var prop in listPoll) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,4 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
|
||||
WebAPI-ECA Engine
|
||||
|
|
@ -10,10 +9,12 @@ WebAPI-ECA Engine
|
|||
> node webapi-eca [opt]
|
||||
>
|
||||
> See below in the optimist CLI preparation for allowed optional parameters `[opt]`.
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var argv, cm, conf, cp, db, engine, fs, http, init, logconf, logger, nameEP, opt, optimist, path, procCmds, shutDown, usage;
|
||||
var argv, cm, conf, cp, db, engine, fs, http, init, logconf, logger, nameEP, opt, optimist, path, procCmds, shutDown, usage,
|
||||
_this = this;
|
||||
|
||||
logger = require('./logging');
|
||||
|
||||
|
|
@ -39,10 +40,10 @@ WebAPI-ECA Engine
|
|||
|
||||
procCmds = {};
|
||||
|
||||
|
||||
/*
|
||||
Let's prepare the optimist CLI optional arguments `[opt]`:
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
usage = 'This runs your webapi-based ECA engine';
|
||||
|
||||
|
|
@ -129,91 +130,72 @@ WebAPI-ECA Engine
|
|||
|
||||
this.log.info('RS | STARTING SERVER');
|
||||
|
||||
|
||||
/*
|
||||
This function is invoked right after the module is loaded and starts the server.
|
||||
|
||||
@private init()
|
||||
*/
|
||||
*/
|
||||
|
||||
init = (function(_this) {
|
||||
return function() {
|
||||
var args;
|
||||
args = {
|
||||
logger: _this.log,
|
||||
logconf: logconf
|
||||
};
|
||||
args['http-port'] = parseInt(argv.w || conf.getHttpPort());
|
||||
args['db-port'] = parseInt(argv.d || conf.getDbPort());
|
||||
_this.log.info('RS | Initialzing DB');
|
||||
db(args);
|
||||
return db.isConnected(function(err) {
|
||||
var cliArgs, poller;
|
||||
if (err) {
|
||||
_this.log.error('RS | No DB connection, shutting down system!');
|
||||
return shutDown();
|
||||
} else {
|
||||
_this.log.info('RS | Initialzing engine');
|
||||
engine(args);
|
||||
_this.log.info('RS | Forking a child process for the event poller');
|
||||
cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']];
|
||||
poller = cp.fork(path.resolve(__dirname, nameEP), cliArgs);
|
||||
_this.log.info('RS | Initialzing module manager');
|
||||
cm(args);
|
||||
cm.addListener('init', function(evt) {
|
||||
return poller.send({
|
||||
event: 'init',
|
||||
data: evt
|
||||
});
|
||||
});
|
||||
cm.addListener('newRule', function(evt) {
|
||||
return poller.send({
|
||||
event: 'newRule',
|
||||
data: evt
|
||||
});
|
||||
});
|
||||
cm.addListener('init', function(evt) {
|
||||
return engine.internalEvent('init', evt);
|
||||
});
|
||||
cm.addListener('newRule', function(evt) {
|
||||
return engine.internalEvent('newRule', evt);
|
||||
});
|
||||
_this.log.info('RS | Initialzing http listener');
|
||||
args['request-service'] = cm.processRequest;
|
||||
args['shutdown-function'] = shutDown;
|
||||
return http(args);
|
||||
}
|
||||
});
|
||||
|
||||
init = function() {
|
||||
var args;
|
||||
args = {
|
||||
logger: _this.log,
|
||||
logconf: logconf
|
||||
};
|
||||
})(this);
|
||||
|
||||
args['http-port'] = parseInt(argv.w || conf.getHttpPort());
|
||||
args['db-port'] = parseInt(argv.d || conf.getDbPort());
|
||||
args['keygen'] = conf.getKeygenPassphrase();
|
||||
_this.log.info('RS | Initialzing DB');
|
||||
db(args);
|
||||
return db.isConnected(function(err) {
|
||||
var cliArgs, poller;
|
||||
if (err) {
|
||||
_this.log.error('RS | No DB connection, shutting down system!');
|
||||
return shutDown();
|
||||
} else {
|
||||
_this.log.info('RS | Initialzing engine');
|
||||
engine(args);
|
||||
_this.log.info('RS | Forking a child process for the event poller');
|
||||
cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']];
|
||||
poller = cp.fork(path.resolve(__dirname, nameEP), cliArgs);
|
||||
_this.log.info('RS | Initialzing module manager');
|
||||
cm(args);
|
||||
cm.addRuleListener(engine.internalEvent);
|
||||
cm.addRuleListener(function(evt) {
|
||||
return poller.send(evt);
|
||||
});
|
||||
_this.log.info('RS | Initialzing http listener');
|
||||
args['request-service'] = cm.processRequest;
|
||||
args['shutdown-function'] = shutDown;
|
||||
return http(args);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Shuts down the server.
|
||||
|
||||
@private shutDown()
|
||||
*/
|
||||
*/
|
||||
|
||||
shutDown = (function(_this) {
|
||||
return function() {
|
||||
_this.log.warn('RS | Received shut down command!');
|
||||
if (db != null) {
|
||||
db.shutDown();
|
||||
}
|
||||
if (engine != null) {
|
||||
engine.shutDown();
|
||||
}
|
||||
return process.exit();
|
||||
};
|
||||
})(this);
|
||||
|
||||
shutDown = function() {
|
||||
_this.log.warn('RS | Received shut down command!');
|
||||
if (db != null) {
|
||||
db.shutDown();
|
||||
}
|
||||
engine.shutDown();
|
||||
return process.exit();
|
||||
};
|
||||
|
||||
/*
|
||||
*# Process Commands
|
||||
## Process Commands
|
||||
|
||||
When the server is run as a child process, this function handles messages
|
||||
from the parent process (e.g. the testing suite)
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
process.on('message', function(cmd) {
|
||||
return typeof procCmds[cmd] === "function" ? procCmds[cmd]() : void 0;
|
||||
|
|
|
|||
327
js/engine.js
327
js/engine.js
|
|
@ -1,156 +1,166 @@
|
|||
'use strict';
|
||||
|
||||
var path = require('path'),
|
||||
cp = require('child_process'),
|
||||
log = require('./logging'),
|
||||
qEvents = new (require('./queue')).Queue(), //TODO export queue into redis
|
||||
regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X
|
||||
listRules = {},
|
||||
listActionModules = {},
|
||||
isRunning = true,
|
||||
ml, poller, db;
|
||||
dynmod = require('./dynamic-modules'),
|
||||
db = require('./persistence'), log;
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
ml = require('./module_loader')(args);
|
||||
poller = cp.fork(path.resolve(__dirname, 'eventpoller'), [log.getLogType()]);
|
||||
poller.on('message', function(evt) {
|
||||
exports.pushEvent(evt);
|
||||
});
|
||||
//start to poll the event queue
|
||||
exports = module.exports = function( args ) {
|
||||
log = args.logger;
|
||||
db( args);
|
||||
dynmod(args);
|
||||
pollQueue();
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the rules engine which initializes the module loader.
|
||||
* @param {Object} db_link the link to the db, see [db\_interface](db_interface.html)
|
||||
* @param {String} db_port the db port
|
||||
* @param {String} crypto_key the key to be used for encryption on the db, max legnth 256
|
||||
*/
|
||||
exports.addDBLinkAndLoadActionsAndRules = function(db_link) {
|
||||
//TODO only load rules on beginning, if rules require certain actions, load them in order to allow fast firing
|
||||
// if rules are set inactive, remove the action module from the memory
|
||||
db = db_link;
|
||||
if(ml && db) db.actionInvokers.getModules(function(err, obj) {
|
||||
if(err) log.error('EN', 'retrieving Action Modules from DB!');
|
||||
else {
|
||||
if(!obj) {
|
||||
log.print('EN', 'No Action Modules found in DB!');
|
||||
} else {
|
||||
var m;
|
||||
for(var el in obj) {
|
||||
log.print('EN', 'Loading Action Module from DB: ' + el);
|
||||
try {
|
||||
m = ml.requireFromString(obj[el], el);
|
||||
// db.getActionModuleAuth(el, function(mod) {
|
||||
// return function(err, obj) {
|
||||
// if(obj && mod.loadCredentials) mod.loadCredentials(JSON.parse(obj));
|
||||
// };
|
||||
// }(m));
|
||||
//FIXME !!!
|
||||
listActionModules[el] = m;
|
||||
} catch(e) {
|
||||
e.addInfo = 'error in action module "' + el + '"';
|
||||
log.error('EN', e);
|
||||
}
|
||||
var updateActionModules = function() {
|
||||
for ( var user in listRules ) {
|
||||
if(!listActionModules[user]) listActionModules[user] = {};
|
||||
for ( var rule in listRules[user] ) {
|
||||
var actions = listRules[user][rule].actions;
|
||||
console.log(actions);
|
||||
for ( var module in actions ){
|
||||
for ( var i = 0; i < actions[module]['functions'].length; i++ ){
|
||||
db.actionInvokers.getModule(module, function( err, objAM ){
|
||||
db.actionInvokers.getUserParams(module, user, function( err, objParams ) {
|
||||
console.log (objAM);
|
||||
|
||||
//FIXME am name is called 'actions'???
|
||||
// if(objParams) { //TODO we don't need them for all modules
|
||||
var answ = dynmod.compileString(objAM.code, objAM.actions + "_" + user, objParams, objAM.lang);
|
||||
console.log('answ');
|
||||
console.log(answ);
|
||||
listActionModules[user][module] = answ.module;
|
||||
console.log('loaded ' + user + ': ' + module);
|
||||
console.log(listActionModules);
|
||||
// }
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if(db) db.getRules(function(err, obj) {
|
||||
for(var el in obj) exports.addRule(JSON.parse(obj[el]));
|
||||
});
|
||||
});
|
||||
else log.severe('EN', new Error('Module Loader or DB not defined!'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert an action module into the list of available interfaces.
|
||||
* @param {Object} objModule the action module object
|
||||
*/
|
||||
//TODO action modules should be loaded once a user activates a rule with the respective
|
||||
// action, if the user deletes the rule it has to be garrbage collected from the engine's list
|
||||
exports.loadActionModule = function(name, objModule) {
|
||||
log.print('EN', 'Action module "' + name + '" loaded');
|
||||
listActionModules[name] = objModule;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a rule into the working memory
|
||||
* @param {Object} objRule the rule object
|
||||
*/
|
||||
exports.addRule = function(objRule) {
|
||||
//TODO validate rule
|
||||
log.print('EN', 'Loading Rule');
|
||||
log.print('EN', 'Loading Rule: ' + objRule.id);
|
||||
if(listRules[objRule.id]) log.print('EN', 'Replacing rule: ' + objRule.id);
|
||||
listRules[objRule.id] = objRule;
|
||||
|
||||
// Notify poller about eventual candidate
|
||||
try {
|
||||
poller.send('event|'+objRule.event);
|
||||
} catch (err) {
|
||||
log.print('EN', 'Unable to inform poller about new active rule!');
|
||||
}
|
||||
};
|
||||
|
||||
exports.internalEvent = function( evt ) {
|
||||
try {
|
||||
// TODO do we need to determine init from newRule?
|
||||
console.log (evt);
|
||||
// console.log (data);
|
||||
// var obj = JSON.parse( data );
|
||||
// db.getRuleActivatedUsers(obj.id, function ( err, arrUsers ) {
|
||||
// console.log (arrUsers);
|
||||
// for(var i = 0; i < arrUsers.length; i++) {
|
||||
// if( !listRules[arrUsers[i]]) listRules[arrUsers[i]] = {};
|
||||
// listRules[arrUsers[i]][obj.id] = obj;
|
||||
// updateActionModules();
|
||||
// }
|
||||
// });
|
||||
} catch( err ) {
|
||||
console.log( err );
|
||||
}
|
||||
console.log('internal event handled');
|
||||
};
|
||||
|
||||
|
||||
function pollQueue() {
|
||||
if(isRunning) {
|
||||
var evt = qEvents.dequeue();
|
||||
if(evt) {
|
||||
processEvent(evt);
|
||||
}
|
||||
setTimeout(pollQueue, 50); //TODO adapt to load
|
||||
db.popEvent(function (err, obj) {
|
||||
if(!err && obj) {
|
||||
processEvent(obj);
|
||||
}
|
||||
setTimeout(pollQueue, 50); //TODO adapt to load
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores correctly posted events in the queue
|
||||
* @param {Object} evt The event object
|
||||
*/
|
||||
exports.pushEvent = function(evt) {
|
||||
qEvents.enqueue(evt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles correctly posted events
|
||||
* @param {Object} evt The event object
|
||||
*/
|
||||
function processEvent(evt) {
|
||||
log.print('EN', 'processing event: ' + evt.event + '(' + evt.eventid + ')');
|
||||
log.info('EN', 'processing event: ' + evt.event + '(' + evt.eventid + ')');
|
||||
var actions = checkEvent(evt);
|
||||
for(var i = 0; i < actions.length; i++) {
|
||||
invokeAction(evt, actions[i]);
|
||||
console.log('found actions to invoke:');
|
||||
console.log(actions);
|
||||
for(var user in actions) {
|
||||
for(var module in actions[user]) {
|
||||
for(var i = 0; i < actions[user][module]['functions'].length; i++) {
|
||||
var act = {
|
||||
module: module,
|
||||
function: actions[user][module]['functions'][i]
|
||||
}
|
||||
invokeAction(evt, user, act);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
FIXME merge with processEvent
|
||||
|
||||
* Check an event against the rules repository and return the actions
|
||||
* if the conditons are met.
|
||||
* @param {Object} evt the event to check
|
||||
*/
|
||||
function checkEvent(evt) {
|
||||
var actions = [];
|
||||
for(var rn in listRules) {
|
||||
var actions = {}, tEvt;
|
||||
for(var user in listRules) {
|
||||
actions[user] = {};
|
||||
for(var rule in listRules[user]) {
|
||||
//TODO this needs to get depth safe, not only data but eventually also
|
||||
// on one level above (eventid and other meta)
|
||||
if(listRules[rn].event === evt.event && validConditions(evt.payload, listRules[rn])) {
|
||||
log.print('EN', 'Rule "' + rn + '" fired');
|
||||
actions = actions.concat(listRules[rn].actions);
|
||||
tEvt = listRules[user][rule].event;
|
||||
if(tEvt.module + ' -> ' + tEvt.function === evt.event && validConditions(evt.payload, listRules[user][rule])) {
|
||||
log.info('EN', 'Rule "' + rule + '" fired');
|
||||
var oAct = listRules[user][rule].actions;
|
||||
console.log (oAct);
|
||||
for(var module in oAct) {
|
||||
if(!actions[user][module]) {
|
||||
actions[user][module] = {
|
||||
functions: []
|
||||
};
|
||||
}
|
||||
for(var i = 0; i < oAct[module]['functions'].length; i++ ){
|
||||
console.log ('processing action ' + i + ', ' + oAct[module]['functions'][i]);
|
||||
actions[user][module]['functions'].push(oAct[module]['functions'][i]);
|
||||
// if(actions[user].indexOf(arrAct[i]) === -1) actions[user].push(arrAct[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
// {
|
||||
// "event": "emailyak -> newMail",
|
||||
// "payload": {
|
||||
// "TextBody": "hello"
|
||||
// }
|
||||
// }
|
||||
|
||||
// exports.sendMail = ( args ) ->
|
||||
// url = 'https://api.emailyak.com/v1/ps1g59ndfcwg10w/json/send/email/'
|
||||
|
||||
// data =
|
||||
// FromAddress: 'tester@mscliveweb.simpleyak.com'
|
||||
// ToAddress: 'dominic.bosch.db@gmail.com'
|
||||
// TextBody: 'test'
|
||||
|
||||
// needle.post url, JSON.stringify( data ), {json: true}, ( err, resp, body ) ->
|
||||
// log err
|
||||
// log body
|
||||
/**
|
||||
* Checks whether all conditions of the rule are met by the event.
|
||||
* @param {Object} evt the event to check
|
||||
* @param {Object} rule the rule with its conditions
|
||||
*/
|
||||
function validConditions(evt, rule) {
|
||||
for(var property in rule.condition){
|
||||
for(var property in rule.conditions){
|
||||
if(!evt[property] || evt[property] != rule.condition[property]) return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -161,76 +171,75 @@ function validConditions(evt, rule) {
|
|||
* @param {Object} evt The event that invoked the action
|
||||
* @param {Object} action The action to be invoked
|
||||
*/
|
||||
function invokeAction(evt, action) {
|
||||
var actionargs = {},
|
||||
arrModule = action.module.split('->');
|
||||
function invokeAction( evt, user, action ) {
|
||||
console.log('invoking action');
|
||||
var actionargs = {};
|
||||
//FIXME internal events, such as loopback ha sno arrow
|
||||
//TODO this requires change. the module property will be the identifier
|
||||
// in the actions object (or shall we allow several times the same action?)
|
||||
if(arrModule.length < 2) {
|
||||
log.error('EN', 'Invalid rule detected!');
|
||||
return;
|
||||
}
|
||||
var srvc = listActionModules[arrModule[0]];
|
||||
if(srvc && srvc[arrModule[1]]) {
|
||||
console.log(action.module);
|
||||
console.log(listActionModules);
|
||||
var srvc = listActionModules[user][action.module];
|
||||
console.log(srvc);
|
||||
if(srvc && srvc[action.function]) {
|
||||
//FIXME preprocessing not only on data
|
||||
//FIXME no preprocessing at all, why don't we just pass the whole event to the action?'
|
||||
preprocessActionArguments(evt.payload, action.arguments, actionargs);
|
||||
// preprocessActionArguments(evt.payload, action.arguments, actionargs);
|
||||
try {
|
||||
if(srvc[arrModule[1]]) srvc[arrModule[1]](actionargs);
|
||||
if(srvc[action.function]) srvc[action.function](evt.payload);
|
||||
} catch(err) {
|
||||
log.error('EN', 'during action execution: ' + err);
|
||||
}
|
||||
}
|
||||
else log.print('EN', 'No api interface found for: ' + action.module);
|
||||
else log.info('EN', 'No api interface found for: ' + action.module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action properties may contain event properties which need to be resolved beforehand.
|
||||
* @param {Object} evt The event whose property values can be used in the rules action
|
||||
* @param {Object} act The rules action arguments
|
||||
* @param {Object} res The object to be used to enter the new properties
|
||||
*/
|
||||
function preprocessActionArguments(evt, act, res) {
|
||||
for(var prop in act) {
|
||||
/*
|
||||
* If the property is an object itself we go into recursion
|
||||
*/
|
||||
if(typeof act[prop] === 'object') {
|
||||
res[prop] = {};
|
||||
preprocessActionArguments(evt, act[prop], res[prop]);
|
||||
}
|
||||
else {
|
||||
var txt = act[prop];
|
||||
var arr = txt.match(regex);
|
||||
/*
|
||||
* If rules action property holds event properties we resolve them and
|
||||
* replace the original action property
|
||||
*/
|
||||
// console.log(evt);
|
||||
if(arr) {
|
||||
for(var i = 0; i < arr.length; i++) {
|
||||
/*
|
||||
* The first three characters are '$X.', followed by the property
|
||||
*/
|
||||
var actionProp = arr[i].substring(3).toLowerCase();
|
||||
// console.log(actionProp);
|
||||
for(var eprop in evt) {
|
||||
// our rules language doesn't care about upper or lower case
|
||||
if(eprop.toLowerCase() === actionProp) {
|
||||
txt = txt.replace(arr[i], evt[eprop]);
|
||||
}
|
||||
}
|
||||
txt = txt.replace(arr[i], '[property not available]');
|
||||
}
|
||||
}
|
||||
res[prop] = txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * Action properties may contain event properties which need to be resolved beforehand.
|
||||
// * @param {Object} evt The event whose property values can be used in the rules action
|
||||
// * @param {Object} act The rules action arguments
|
||||
// * @param {Object} res The object to be used to enter the new properties
|
||||
// */
|
||||
// function preprocessActionArguments(evt, act, res) {
|
||||
// for(var prop in act) {
|
||||
// /*
|
||||
// * If the property is an object itself we go into recursion
|
||||
// */
|
||||
// if(typeof act[prop] === 'object') {
|
||||
// res[prop] = {};
|
||||
// preprocessActionArguments(evt, act[prop], res[prop]);
|
||||
// }
|
||||
// else {
|
||||
// var txt = act[prop];
|
||||
// var arr = txt.match(regex);
|
||||
|
||||
// * If rules action property holds event properties we resolve them and
|
||||
// * replace the original action property
|
||||
|
||||
// // console.log(evt);
|
||||
// if(arr) {
|
||||
// for(var i = 0; i < arr.length; i++) {
|
||||
// /*
|
||||
// * The first three characters are '$X.', followed by the property
|
||||
// */
|
||||
// var actionProp = arr[i].substring(3).toLowerCase();
|
||||
// // console.log(actionProp);
|
||||
// for(var eprop in evt) {
|
||||
// // our rules language doesn't care about upper or lower case
|
||||
// if(eprop.toLowerCase() === actionProp) {
|
||||
// txt = txt.replace(arr[i], evt[eprop]);
|
||||
// }
|
||||
// }
|
||||
// txt = txt.replace(arr[i], '[property not available]');
|
||||
// }
|
||||
// }
|
||||
// res[prop] = txt;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
exports.shutDown = function() {
|
||||
log.print('EN', 'Shutting down Poller and DB Link');
|
||||
if(log) log.info('EN', 'Shutting down Poller and DB Link');
|
||||
isRunning = false;
|
||||
if(poller) poller.send('cmd|shutdown');
|
||||
if(db) db.shutDown();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"eps": {
|
||||
"epOne": {
|
||||
"id":"epOne",
|
||||
"lang":"0",
|
||||
"lang":"CoffeeScript",
|
||||
"data":"\n#\n# EmailYak EVENT POLLER\n#\n# Requires user params:\n# - apikey: The user's EmailYak API key\n#\n\nurl = 'https://api.emailyak.com/v1/' + params.apikey + '/json/get/new/email/'\n\nexports.newMail = ( pushEvent ) ->\n needle.get url, ( err, resp, body ) ->\n if not err and resp.statusCode is 200\n mails = JSON.parse( body ).Emails\n pushEvent mail for mail in mails\n else\n log.error 'Error in EmailYak EM newMail: ' + err.message\n\n",
|
||||
"public":"false",
|
||||
"params":"[\"apikey\"]",
|
||||
|
|
@ -24,13 +24,31 @@
|
|||
},
|
||||
"epTwo": {
|
||||
"id":"epTwo",
|
||||
"lang":"0",
|
||||
"lang":"CoffeeScript",
|
||||
"data":"\nurl = 'https://api.emailyak.com/v1/' + params.firstparam + '/json/get/new/email/'\n\nexports.newEvent = ( pushEvent ) ->\n needle.get url, ( err, resp, body ) ->\n if not err and resp.statusCode is 200\n mails = JSON.parse( body ).Emails\n pushEvent mail for mail in mails\n else\n log.error 'Error in EmailYak EM newMail: ' + err.message\n\nexports.randomNess = ( pushEvent ) ->\n console.log 'test runs: ' + params.secondparam\n",
|
||||
"public":"true",
|
||||
"params":"[\"firstparam\",\"secondparam\"]",
|
||||
"functions":"[\"newEvent\",\"randomNess\"]"
|
||||
}
|
||||
},
|
||||
"ais": {
|
||||
"aiOne": {
|
||||
"id":"aiOne",
|
||||
"lang":"CoffeeScript",
|
||||
"data":"# Send a mail through emailyak\nexports.sendMail = ( args ) ->\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\"]",
|
||||
"functions":"[\"sendMail\"]"
|
||||
},
|
||||
"aiTwo": {
|
||||
"id":"aiTwo",
|
||||
"lang":"CoffeeScript",
|
||||
"data":"# Send a mail through emailyak\nexports.sendMail = ( args ) ->\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":"[\"sendMail\"]"
|
||||
}
|
||||
},
|
||||
"userparams": {
|
||||
"epUpOne": {
|
||||
"apikey": "testkey"
|
||||
|
|
@ -52,6 +70,20 @@
|
|||
"property": "yourValue2"
|
||||
},
|
||||
"actions": []
|
||||
},
|
||||
"ruleThree": {
|
||||
"id": "ruleThree_id",
|
||||
"event": "custom-test-3",
|
||||
"conditions": {
|
||||
"property": "yourValue3"
|
||||
},
|
||||
"actions": []
|
||||
},
|
||||
"ruleReal": {
|
||||
"id": "ruleReal",
|
||||
"event": "epOne -> newMail",
|
||||
"conditions": {},
|
||||
"actions": ["aiOne -> sendMail"]
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
|
|
|
|||
|
|
@ -25,12 +25,14 @@ db opts
|
|||
oUser = objects.users.userOne
|
||||
oRuleOne = objects.rules.ruleOne
|
||||
oRuleTwo = objects.rules.ruleTwo
|
||||
oRuleThree = objects.rules.ruleThree
|
||||
oEpOne = objects.eps.epOne
|
||||
oEpTwo = objects.eps.epTwo
|
||||
|
||||
exports.tearDown = ( cb ) ->
|
||||
db.deleteRule oRuleOne.id
|
||||
db.deleteRule oRuleTwo.id
|
||||
db.deleteRule oRuleThree.id
|
||||
setTimeout cb, 100
|
||||
|
||||
exports.requestProcessing =
|
||||
|
|
@ -56,33 +58,50 @@ exports.requestProcessing =
|
|||
test.done()
|
||||
|
||||
exports.testListener = ( test ) =>
|
||||
test.expect 2
|
||||
test.expect 3
|
||||
|
||||
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.storeRule oRuleOne.id, JSON.stringify oRuleOne
|
||||
request =
|
||||
command: 'forge_rule'
|
||||
payload: JSON.stringify oRuleTwo
|
||||
payload: strRuleThree
|
||||
|
||||
cm.addRuleListener ( evt ) =>
|
||||
strEvt = JSON.stringify evt.rule
|
||||
console.log evt
|
||||
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 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!'
|
||||
|
||||
cm.addListener 'newRule', ( evt ) =>
|
||||
try
|
||||
newRule = JSON.parse evt
|
||||
catch err
|
||||
test.ok false, 'Failed to parse the newRule event'
|
||||
test.deepEqual newRule, oRuleTwo, 'New Rule is not the same!'
|
||||
test.done()
|
||||
|
||||
cm.addListener 'init', ( evt ) =>
|
||||
try
|
||||
initRule = JSON.parse evt
|
||||
catch err
|
||||
test.ok false, 'Failed to parse the newRule event'
|
||||
test.deepEqual initRule, oRuleOne, 'Init Rule is not the same!'
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -96,6 +115,7 @@ exports.moduleHandling =
|
|||
test.expect 2
|
||||
|
||||
db.eventPollers.storeModule oUser.username, oEpOne
|
||||
db.eventPollers.storeModule oUser.username, oEpTwo
|
||||
request =
|
||||
command: 'get_event_pollers'
|
||||
|
||||
|
|
@ -103,23 +123,25 @@ exports.moduleHandling =
|
|||
test.strictEqual 200, answ.code, 'GetModules failed...'
|
||||
oExpected = {}
|
||||
oExpected[oEpOne.id] = JSON.parse oEpOne.functions
|
||||
test.strictEqual JSON.stringify(oExpected), answ.message,
|
||||
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
|
||||
|
||||
db.eventPollers.storeModule oUser.username, oEpTwo
|
||||
db.eventPollers.storeModule oUser.username, oEpOne
|
||||
|
||||
request =
|
||||
command: 'get_event_poller_params'
|
||||
payload: '{"id": "' + oEpTwo.id + '"}'
|
||||
|
||||
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 oEpTwo.params, answ.message,
|
||||
test.strictEqual oEpOne.params, answ.message,
|
||||
'Required Module Parameters did not match'
|
||||
test.done()
|
||||
|
||||
|
|
|
|||
41
testing/test_dynamic-modules.coffee
Normal file
41
testing/test_dynamic-modules.coffee
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
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
|
||||
catch err
|
||||
console.log 'Error fetching standard objects file: ' + err.message
|
||||
|
||||
logger = require path.join '..', 'js-coffee', 'logging'
|
||||
log = logger.getLogger
|
||||
nolog: true
|
||||
opts =
|
||||
logger: log
|
||||
|
||||
dm = require path.join '..', 'js-coffee', 'dynamic-modules'
|
||||
dm opts
|
||||
|
||||
exports.testCompile = ( test ) ->
|
||||
test.expect 5
|
||||
|
||||
paramsOne =
|
||||
testParam: 'First Test'
|
||||
paramsTwo =
|
||||
testParam: 'Second Test'
|
||||
|
||||
code = "exports.testFunc = () ->\n\tparams.testParam"
|
||||
result = dm.compileString code, 'userOne', 'moduleOne', paramsOne, 'CoffeeScript'
|
||||
test.strictEqual 200, result.answ.code
|
||||
moduleOne = result.module
|
||||
test.strictEqual paramsOne.testParam, moduleOne.testFunc(), "Other result expected"
|
||||
|
||||
result = dm.compileString code, 'userOne', 'moduleOne', paramsTwo, 'CoffeeScript'
|
||||
test.strictEqual 200, result.answ.code
|
||||
moduleTwo = result.module
|
||||
test.strictEqual paramsTwo.testParam, moduleTwo.testFunc(), "Other result expected"
|
||||
test.notStrictEqual paramsOne.testParam, moduleTwo.testFunc(), "Other result expected"
|
||||
test.done()
|
||||
84
testing/test_engine.coffee
Normal file
84
testing/test_engine.coffee
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
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
|
||||
catch err
|
||||
console.log 'Error fetching standard objects file: ' + err.message
|
||||
|
||||
logger = require path.join '..', 'js-coffee', 'logging'
|
||||
log = logger.getLogger()
|
||||
# nolog: true
|
||||
opts =
|
||||
logger: log
|
||||
|
||||
engine = require path.join '..', 'js-coffee', 'engine'
|
||||
engine opts
|
||||
|
||||
db = require path.join '..', 'js-coffee', 'persistence'
|
||||
db opts
|
||||
|
||||
oUser = objects.users.userOne
|
||||
oRuleOne = objects.rules.ruleOne
|
||||
oRuleTwo = objects.rules.ruleTwo
|
||||
oRuleReal = objects.rules.ruleReal
|
||||
oEpOne = objects.eps.epOne
|
||||
oEpTwo = objects.eps.epTwo
|
||||
oAiOne = objects.ais.aiOne
|
||||
|
||||
exports.tearDown = ( cb ) ->
|
||||
db.deleteRule oRuleOne.id
|
||||
db.deleteRule oRuleTwo.id
|
||||
db.deleteRule oRuleReal.id
|
||||
db.actionInvokers.deleteModule oAiOne.id
|
||||
db.deleteUser oUser.username
|
||||
setTimeout cb, 100
|
||||
|
||||
exports.ruleEvents =
|
||||
# init: first registration, multiple registration
|
||||
# actions loaded and added correctly
|
||||
# new: new actions added
|
||||
# old actions removed
|
||||
# delete: all actions removed if not required anymore
|
||||
testInit: ( test ) ->
|
||||
db.storeUser oUser
|
||||
test.done()
|
||||
strRuleOne = JSON.stringify oRuleOne
|
||||
strRuleTwo = JSON.stringify oRuleTwo
|
||||
strRuleReal = JSON.stringify oRuleReal
|
||||
|
||||
db.actionInvokers.storeModule oUser.username, oAiOne
|
||||
|
||||
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.storeRule oRuleReal.id, strRuleReal
|
||||
db.linkRule oRuleReal.id, oUser.username
|
||||
db.activateRule oRuleReal.id, oUser.username
|
||||
|
||||
db.getAllActivatedRuleIdsPerUser ( err, obj ) =>
|
||||
@existingRules = obj
|
||||
console.log 'existing'
|
||||
console.log obj
|
||||
|
||||
engine.internalEvent
|
||||
event: 'init'
|
||||
user: oUser.username
|
||||
rule: oRuleReal
|
||||
|
||||
fCheckRules = () ->
|
||||
db.getAllActivatedRuleIdsPerUser ( err, obj ) =>
|
||||
console.log 'after init'
|
||||
console.log obj
|
||||
console.log @existingRules is obj
|
||||
|
||||
setTimeout fCheckRules, 500
|
||||
|
|
@ -10,7 +10,7 @@ fOnLoad = () ->
|
|||
editor.setShowPrintMargin false
|
||||
|
||||
$( '#editor_mode' ).change ( el ) ->
|
||||
if $( this ).val() is '0'
|
||||
if $( this ).val() is 'CoffeeScript'
|
||||
editor.getSession().setMode "ace/mode/coffee"
|
||||
else
|
||||
editor.getSession().setMode "ace/mode/javascript"
|
||||
|
|
@ -80,24 +80,3 @@ fOnLoad = () ->
|
|||
window.location.href = 'forge?page=forge_action_invoker'
|
||||
|
||||
window.addEventListener 'load', fOnLoad, true
|
||||
|
||||
# "ais": {
|
||||
# "ai1": {
|
||||
# "code": "
|
||||
# url = 'https://api.emailyak.com/v1/' + params.apikey + '/json/send/email/'
|
||||
|
||||
# exports.sendMail = ( args ) ->
|
||||
# data:
|
||||
# FromAddress: "no-reply@mscliveweb.simpleyak.com"
|
||||
# ToAddress: "test@mscliveweb.simpleyak.com"
|
||||
# log 'set data, posting now'
|
||||
# needle.post url, data, ( err, resp, body ) ->
|
||||
# log 'post returned'
|
||||
# if not err and resp.statusCode is 200
|
||||
# log 'Sent mail...'
|
||||
# else
|
||||
# log 'Error in EmailYak EM sendMail: ' + err.message
|
||||
# "
|
||||
|
||||
# }
|
||||
# },
|
||||
|
|
@ -10,7 +10,7 @@ fOnLoad = () ->
|
|||
editor.setShowPrintMargin false
|
||||
|
||||
$( '#editor_mode' ).change ( el ) ->
|
||||
if $( this ).val() is '0'
|
||||
if $( this ).val() is 'CoffeeScript'
|
||||
editor.getSession().setMode "ace/mode/coffee"
|
||||
else
|
||||
editor.getSession().setMode "ace/mode/javascript"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
|
||||
strPublicKey = ''
|
||||
$.post( '/usercommand', command: 'get_public_key' )
|
||||
.done ( data ) ->
|
||||
strPublicKey = data.message
|
||||
.fail ( err ) ->
|
||||
console.log err
|
||||
$( '#info' ).text 'Error fetching public key, unable to send user-specific parameters securely'
|
||||
$( '#info' ).attr 'class', 'error'
|
||||
|
||||
fOnLoad = () ->
|
||||
|
||||
|
|
@ -12,19 +19,19 @@ fOnLoad = () ->
|
|||
command: 'get_event_poller_params'
|
||||
payload:
|
||||
id: arr[0]
|
||||
obj.payload = JSON.stringify( obj.payload );
|
||||
$.post( '/usercommand', obj )
|
||||
.done ( data ) ->
|
||||
if data.message
|
||||
arrParams = JSON.parse data.message
|
||||
$( '#event_poller_params table' ).remove()
|
||||
if arrParams.length > 0
|
||||
$( '#event_poller_params' ).text 'Required user-specific params:'
|
||||
table = $ '<table>'
|
||||
$( '#event_poller_params' ).append table
|
||||
fAppendParam = ( name ) ->
|
||||
tr = $( '<tr>' )
|
||||
tr.append $( '<td>' ).css 'width', '20px'
|
||||
tr.append $( '<td>' ).text name
|
||||
tr.append $( '<td>' ).attr( 'class', 'key' ).text name
|
||||
inp = $( '<input>' ).attr( 'type', 'password' ).attr 'id', "#{ name }"
|
||||
tr.append $( '<td>' ).text( ' :' ).append inp
|
||||
table.append tr
|
||||
|
|
@ -45,13 +52,17 @@ fOnLoad = () ->
|
|||
command: 'get_event_pollers'
|
||||
$.post( '/usercommand', obj )
|
||||
.done ( data ) ->
|
||||
try
|
||||
oEps = JSON.parse data.message
|
||||
catch err
|
||||
console.error 'ERROR: non-object received from server: ' + data.message
|
||||
return
|
||||
|
||||
fAppendEvents = ( id, events ) ->
|
||||
try
|
||||
arrNames = JSON.parse events
|
||||
$( '#select_event' ).append $( '<option>' ).text id + ' -> ' + name for name in arrNames
|
||||
catch err
|
||||
console.error 'ERROR: non-array received from server: ' + events
|
||||
fAppendEvents id, events for id, events of data.message
|
||||
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 ( err ) ->
|
||||
console.log err
|
||||
|
|
@ -67,17 +78,20 @@ fOnLoad = () ->
|
|||
command: 'get_action_invokers'
|
||||
$.post( '/usercommand', obj )
|
||||
.done ( data ) ->
|
||||
try
|
||||
oAis = JSON.parse data.message
|
||||
catch err
|
||||
console.error 'ERROR: non-object received from server: ' + data.message
|
||||
return
|
||||
i = 0
|
||||
fAppendActions = ( id, actions ) ->
|
||||
try
|
||||
arrNames = JSON.parse actions
|
||||
for name in arrNames
|
||||
$( '#select_actions' ).append $( '<option>' ).attr( 'id', i++ ).text id + ' -> ' + name
|
||||
arrActionInvoker.push id + ' -> ' + name
|
||||
catch err
|
||||
console.error 'ERROR: non-array received from server: ' + actions
|
||||
fAppendActions id, actions for id, actions of data.message
|
||||
.fail ( err ) ->
|
||||
fAppendAction = ( act ) ->
|
||||
$( '#select_actions' ).append $( '<option>' ).attr( 'id', i++ ).text id + ' -> ' + act
|
||||
arrActionInvoker.push id + ' -> ' + act
|
||||
fAppendAction act for act in actions
|
||||
fAppendActions id, actions for id, actions of oAis
|
||||
|
||||
.fail ( err ) ->
|
||||
console.log err
|
||||
$( '#info' ).text 'Error fetching event poller'
|
||||
$( '#info' ).attr 'class', 'error'
|
||||
|
|
@ -86,7 +100,9 @@ fOnLoad = () ->
|
|||
fFetchActionParams = ( div, name ) ->
|
||||
obj =
|
||||
command: 'get_action_invoker_params'
|
||||
id: name
|
||||
payload:
|
||||
id: name
|
||||
obj.payload = JSON.stringify( obj.payload );
|
||||
$.post( '/usercommand', obj )
|
||||
.done ( data ) ->
|
||||
if data.message
|
||||
|
|
@ -117,7 +133,11 @@ fOnLoad = () ->
|
|||
tr.append $( '<td>' ).attr( 'class', 'title').text( opt.val() )
|
||||
table.append tr
|
||||
if $( '#ap_' + arrAI[0] ).length is 0
|
||||
div = $( '<div>' ).attr( 'id', 'ap_' + arrAI[0] ).html "<i>#{ arrAI[0] }</i>"
|
||||
div = $( '<div>' )
|
||||
.attr( 'id', 'ap_' + arrAI[0] )
|
||||
div.append $( '<div> ')
|
||||
.attr( 'class', 'underlined')
|
||||
.text arrAI[0]
|
||||
$( '#action_params' ).append div
|
||||
fFetchActionParams div, arrAI[0]
|
||||
opt.remove()
|
||||
|
|
@ -149,7 +169,7 @@ fOnLoad = () ->
|
|||
ep = {}
|
||||
$( "#event_poller_params tr" ).each () ->
|
||||
val = $( 'input', this ).val()
|
||||
name = $( 'td:nth-child(2)', this ).text()
|
||||
name = $( this ).children( '.key' ).text()
|
||||
if val is ''
|
||||
throw new Error "Please enter a value for '#{ name }' in the event module!"
|
||||
ep[name] = val
|
||||
|
|
@ -159,7 +179,7 @@ fOnLoad = () ->
|
|||
|
||||
# Store all selected action invokers
|
||||
ap = {}
|
||||
$( '#action_params div' ).each () ->
|
||||
$( '> div', $( '#action_params' ) ).each () ->
|
||||
id = $( this ).attr( 'id' ).substring 3
|
||||
params = {}
|
||||
$( 'tr', this ).each () ->
|
||||
|
|
@ -168,23 +188,26 @@ fOnLoad = () ->
|
|||
if val is ''
|
||||
throw new Error "'#{ key }' missing for '#{ id }'"
|
||||
params[key] = val
|
||||
ap[id] = params
|
||||
encryptedParams = cryptico.encrypt JSON.stringify( params ), strPublicKey
|
||||
ap[id] = encryptedParams.cipher
|
||||
acts = []
|
||||
$( '#selected_actions .title' ).each () ->
|
||||
acts.push $( this ).text()
|
||||
|
||||
encryptedParams = cryptico.encrypt JSON.stringify( ep ), strPublicKey
|
||||
obj =
|
||||
command: 'forge_rule'
|
||||
payload:
|
||||
id: $( '#input_id' ).val()
|
||||
event: $( '#select_event option:selected' ).val()
|
||||
event_params: ep
|
||||
event_params: encryptedParams.cipher
|
||||
conditions: {} #TODO Add conditions!
|
||||
actions: acts
|
||||
action_params: ap
|
||||
obj.payload = JSON.stringify obj.payload
|
||||
$.post( '/usercommand', obj )
|
||||
.done ( data ) ->
|
||||
console.log 'success'
|
||||
$( '#info' ).text data.message
|
||||
$( '#info' ).attr 'class', 'success'
|
||||
.fail ( err ) ->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var fOnLoad;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
editor.getSession().setMode("ace/mode/coffee");
|
||||
editor.setShowPrintMargin(false);
|
||||
$('#editor_mode').change(function(el) {
|
||||
if ($(this).val() === '0') {
|
||||
if ($(this).val() === 'CoffeeScript') {
|
||||
return editor.getSession().setMode("ace/mode/coffee");
|
||||
} else {
|
||||
return editor.getSession().setMode("ace/mode/javascript");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var fOnLoad;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
editor.getSession().setMode("ace/mode/coffee");
|
||||
editor.setShowPrintMargin(false);
|
||||
$('#editor_mode').change(function(el) {
|
||||
if ($(this).val() === '0') {
|
||||
if ($(this).val() === 'CoffeeScript') {
|
||||
return editor.getSession().setMode("ace/mode/coffee");
|
||||
} else {
|
||||
return editor.getSession().setMode("ace/mode/javascript");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
// Generated by CoffeeScript 1.7.1
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var fOnLoad;
|
||||
var fOnLoad, strPublicKey;
|
||||
|
||||
strPublicKey = '';
|
||||
|
||||
$.post('/usercommand', {
|
||||
command: 'get_public_key'
|
||||
}).done(function(data) {
|
||||
return strPublicKey = data.message;
|
||||
}).fail(function(err) {
|
||||
console.log(err);
|
||||
$('#info').text('Error fetching public key, unable to send user-specific parameters securely');
|
||||
return $('#info').attr('class', 'error');
|
||||
});
|
||||
|
||||
fOnLoad = function() {
|
||||
var arrActionInvoker, fFetchActionParams, fFetchEventParams, obj;
|
||||
|
|
@ -15,20 +27,20 @@
|
|||
id: arr[0]
|
||||
}
|
||||
};
|
||||
obj.payload = JSON.stringify(obj.payload);
|
||||
return $.post('/usercommand', obj).done(function(data) {
|
||||
var arrParams, fAppendParam, table, _i, _len, _results;
|
||||
if (data.message) {
|
||||
arrParams = JSON.parse(data.message);
|
||||
$('#event_poller_params table').remove();
|
||||
if (arrParams.length > 0) {
|
||||
$('#event_poller_params').text('Required user-specific params:');
|
||||
table = $('<table>');
|
||||
$('#event_poller_params').append(table);
|
||||
fAppendParam = function(name) {
|
||||
var inp, tr;
|
||||
tr = $('<tr>');
|
||||
tr.append($('<td>').css('width', '20px'));
|
||||
tr.append($('<td>').text(name));
|
||||
tr.append($('<td>').attr('class', 'key').text(name));
|
||||
inp = $('<input>').attr('type', 'password').attr('id', "" + name);
|
||||
tr.append($('<td>').text(' :').append(inp));
|
||||
return table.append(tr);
|
||||
|
|
@ -51,25 +63,28 @@
|
|||
command: 'get_event_pollers'
|
||||
};
|
||||
$.post('/usercommand', obj).done(function(data) {
|
||||
var events, fAppendEvents, id, _ref;
|
||||
var err, events, fAppendEvents, id, oEps;
|
||||
try {
|
||||
oEps = JSON.parse(data.message);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
console.error('ERROR: non-object received from server: ' + data.message);
|
||||
return;
|
||||
}
|
||||
fAppendEvents = function(id, events) {
|
||||
var arrNames, err, name, _i, _len, _results;
|
||||
try {
|
||||
arrNames = JSON.parse(events);
|
||||
_results = [];
|
||||
for (_i = 0, _len = arrNames.length; _i < _len; _i++) {
|
||||
name = arrNames[_i];
|
||||
_results.push($('#select_event').append($('<option>').text(id + ' -> ' + name)));
|
||||
}
|
||||
return _results;
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
return console.error('ERROR: non-array received from server: ' + events);
|
||||
var evt, fAppendEvent, _i, _len, _results;
|
||||
fAppendEvent = function(evt) {
|
||||
return $('#select_event').append($('<option>').text(id + ' -> ' + evt));
|
||||
};
|
||||
_results = [];
|
||||
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
||||
evt = events[_i];
|
||||
_results.push(fAppendEvent(evt));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
_ref = data.message;
|
||||
for (id in _ref) {
|
||||
events = _ref[id];
|
||||
for (id in oEps) {
|
||||
events = oEps[id];
|
||||
fAppendEvents(id, events);
|
||||
}
|
||||
return fFetchEventParams($('#select_event option:selected').text());
|
||||
|
|
@ -86,26 +101,31 @@
|
|||
command: 'get_action_invokers'
|
||||
};
|
||||
$.post('/usercommand', obj).done(function(data) {
|
||||
var actions, fAppendActions, i, id, _ref, _results;
|
||||
var actions, err, fAppendActions, i, id, oAis, _results;
|
||||
try {
|
||||
oAis = JSON.parse(data.message);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
console.error('ERROR: non-object received from server: ' + data.message);
|
||||
return;
|
||||
}
|
||||
i = 0;
|
||||
fAppendActions = function(id, actions) {
|
||||
var arrNames, err, name, _i, _len;
|
||||
try {
|
||||
arrNames = JSON.parse(actions);
|
||||
for (_i = 0, _len = arrNames.length; _i < _len; _i++) {
|
||||
name = arrNames[_i];
|
||||
$('#select_actions').append($('<option>').attr('id', i++).text(id + ' -> ' + name));
|
||||
}
|
||||
return arrActionInvoker.push(id + ' -> ' + name);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
return console.error('ERROR: non-array received from server: ' + actions);
|
||||
var act, fAppendAction, _i, _len, _results;
|
||||
fAppendAction = function(act) {
|
||||
$('#select_actions').append($('<option>').attr('id', i++).text(id + ' -> ' + act));
|
||||
return arrActionInvoker.push(id + ' -> ' + act);
|
||||
};
|
||||
_results = [];
|
||||
for (_i = 0, _len = actions.length; _i < _len; _i++) {
|
||||
act = actions[_i];
|
||||
_results.push(fAppendAction(act));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
_ref = data.message;
|
||||
_results = [];
|
||||
for (id in _ref) {
|
||||
actions = _ref[id];
|
||||
for (id in oAis) {
|
||||
actions = oAis[id];
|
||||
_results.push(fAppendActions(id, actions));
|
||||
}
|
||||
return _results;
|
||||
|
|
@ -117,8 +137,11 @@
|
|||
fFetchActionParams = function(div, name) {
|
||||
obj = {
|
||||
command: 'get_action_invoker_params',
|
||||
id: name
|
||||
payload: {
|
||||
id: name
|
||||
}
|
||||
};
|
||||
obj.payload = JSON.stringify(obj.payload);
|
||||
return $.post('/usercommand', obj).done(function(data) {
|
||||
var arrParams, fAppendActionParam, table, _i, _len, _results;
|
||||
if (data.message) {
|
||||
|
|
@ -159,7 +182,8 @@
|
|||
tr.append($('<td>').attr('class', 'title').text(opt.val()));
|
||||
table.append(tr);
|
||||
if ($('#ap_' + arrAI[0]).length === 0) {
|
||||
div = $('<div>').attr('id', 'ap_' + arrAI[0]).html("<i>" + arrAI[0] + "</i>");
|
||||
div = $('<div>').attr('id', 'ap_' + arrAI[0]);
|
||||
div.append($('<div> ').attr('class', 'underlined').text(arrAI[0]));
|
||||
$('#action_params').append(div);
|
||||
fFetchActionParams(div, arrAI[0]);
|
||||
}
|
||||
|
|
@ -185,7 +209,7 @@
|
|||
}
|
||||
});
|
||||
return $('#but_submit').click(function() {
|
||||
var acts, ap, ep, err;
|
||||
var acts, ap, encryptedParams, ep, err;
|
||||
try {
|
||||
if ($('#select_event option:selected').length === 0) {
|
||||
throw new Error('Please create an Event Poller first!');
|
||||
|
|
@ -197,7 +221,7 @@
|
|||
$("#event_poller_params tr").each(function() {
|
||||
var name, val;
|
||||
val = $('input', this).val();
|
||||
name = $('td:nth-child(2)', this).text();
|
||||
name = $(this).children('.key').text();
|
||||
if (val === '') {
|
||||
throw new Error("Please enter a value for '" + name + "' in the event module!");
|
||||
}
|
||||
|
|
@ -207,8 +231,8 @@
|
|||
throw new Error('Please select at least one action or create one!');
|
||||
}
|
||||
ap = {};
|
||||
$('#action_params div').each(function() {
|
||||
var id, params;
|
||||
$('> div', $('#action_params')).each(function() {
|
||||
var encryptedParams, id, params;
|
||||
id = $(this).attr('id').substring(3);
|
||||
params = {};
|
||||
$('tr', this).each(function() {
|
||||
|
|
@ -220,18 +244,20 @@
|
|||
}
|
||||
return params[key] = val;
|
||||
});
|
||||
return ap[id] = params;
|
||||
encryptedParams = cryptico.encrypt(JSON.stringify(params), strPublicKey);
|
||||
return ap[id] = encryptedParams.cipher;
|
||||
});
|
||||
acts = [];
|
||||
$('#selected_actions .title').each(function() {
|
||||
return acts.push($(this).text());
|
||||
});
|
||||
encryptedParams = cryptico.encrypt(JSON.stringify(ep), strPublicKey);
|
||||
obj = {
|
||||
command: 'forge_rule',
|
||||
payload: {
|
||||
id: $('#input_id').val(),
|
||||
event: $('#select_event option:selected').val(),
|
||||
event_params: ep,
|
||||
event_params: encryptedParams.cipher,
|
||||
conditions: {},
|
||||
actions: acts,
|
||||
action_params: ap
|
||||
|
|
@ -239,6 +265,7 @@
|
|||
};
|
||||
obj.payload = JSON.stringify(obj.payload);
|
||||
return $.post('/usercommand', obj).done(function(data) {
|
||||
console.log('success');
|
||||
$('#info').text(data.message);
|
||||
return $('#info').attr('class', 'success');
|
||||
}).fail(function(err) {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<script src="ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
|
@ -1 +1 @@
|
|||
<script src="ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
|
@ -1 +1 @@
|
|||
<script src="ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
|
@ -1 +1,2 @@
|
|||
<script src="ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/ace-src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/cryptico.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
Action Invoker Name: <input id="input_id" type="text" />
|
||||
<select id="editor_mode">
|
||||
<option value="0">CoffeeScript</option>
|
||||
<option value="1">JavaScript</option>
|
||||
<option>CoffeeScript</option>
|
||||
<option>JavaScript</option>
|
||||
</select> is public: <input type="checkbox" id="is_public" />
|
||||
<table id="editor_table">
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Event Poller Name: <input id="input_id" type="text" />
|
||||
<select id="editor_mode">
|
||||
<option value="0">CoffeeScript</option>
|
||||
<option value="1">JavaScript</option>
|
||||
<option>CoffeeScript</option>
|
||||
<option>JavaScript</option>
|
||||
</select> is public: <input type="checkbox" id="is_public" />
|
||||
<table id="editor_table">
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<b>Rule Name: </b><input id="input_id" type="text" /><br><br>
|
||||
<b>Event: </b><select id="select_event"></select>
|
||||
<div id="event_poller_params"></div>
|
||||
<div id="event_poller_params">
|
||||
<br><div class="underlined">Required user-specific params:</div>
|
||||
</div>
|
||||
<br><br>
|
||||
<b>Actions: </b><select id="select_actions"><option></option></select>
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Forge A Rule</title>
|
||||
{{{head_requires}}}
|
||||
|
||||
<script type = "text/template" id="templ_rule">
|
||||
{
|
||||
"id": "rule_id",
|
||||
"event": "custom",
|
||||
"condition": { "property": "yourValue" },
|
||||
"actions": [
|
||||
{
|
||||
"module": "probinder->newContent",
|
||||
"arguments": {
|
||||
"content": "Rule#2: $X.subject"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{{{div_menubar}}}
|
||||
<div id="mainbody">
|
||||
<div id="pagetitle">Hi {{user.username}}, forge your own rules!</div>
|
||||
<p>
|
||||
<form id="form_rule">
|
||||
<div id="div_left">
|
||||
<input type="hidden" id="command" value="store_rule" />
|
||||
<textarea id="textarea_rule" rows="20" cols="60"> </textarea>
|
||||
<p id="required_params">
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<button id="but_submit">save</button>
|
||||
</p>
|
||||
</div>
|
||||
<div id="div_middle">
|
||||
<p><b>Available Event Modules:</b></p>
|
||||
<ul> </ul>
|
||||
</div>
|
||||
<div id="div_right">
|
||||
<p><b>Available Action Modules:</b></p>
|
||||
<ul> </ul>
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
<div id="info"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$( "#form_rule" ).submit(function( event ) {
|
||||
var arrInputs = $( "#form_rule .inp_param" );
|
||||
console.log(arrInputs);
|
||||
for( var i = 0; i < arrInputs.length; i++) {
|
||||
console.log(arrInputs[i]);
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
$('#but_submit').click(function() {
|
||||
// var req_fields =
|
||||
var obj = {
|
||||
command : 'store_rule',
|
||||
data: $('#textarea_rule').val()
|
||||
};
|
||||
$.post('/usercommand', obj)
|
||||
// $.post('/usercommand', $('form#rules_form').serialize())
|
||||
.done(function(data) {
|
||||
$('#required_params').children().remove();
|
||||
if(data.success) {
|
||||
alert(data.info);
|
||||
} else {
|
||||
// TODO fix, same logic twice
|
||||
console.log(data.actionmodules);
|
||||
console.log(data.eventmodules);
|
||||
for(var el in data.eventmodules) {
|
||||
var oEM = JSON.parse(data.eventmodules[el]);
|
||||
console.log(oEM);
|
||||
$('#required_params').append($('<p>').html($('<b>Event Module "'+el+'" requires parameters:</b>')));
|
||||
for(var eel in oEM){
|
||||
var inp = '<b>' + eel + ': </b><input type="password" id="em_'+el+'_'+eel+'" class="inp_param" />('+oEM[eel].description+')';
|
||||
$('#required_params').append($('<p>').html(inp));
|
||||
}
|
||||
}
|
||||
for(var el in data.actionmodules) {
|
||||
$('#required_params').append($('<p>').html($('<b>Action Module "'+el+'" requires parameters:</b>')));
|
||||
var oAM = JSON.parse(data.actionmodules[el]);
|
||||
console.log(oAM);
|
||||
for(var ael in oAM){
|
||||
var inp = '<b>' + ael + ': </b><input type="password" id="am_'+el+'_'+ael+'" class="inp_param" />('+oAM[ael].description+')';
|
||||
$('#required_params').append($('<p>').html(inp));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function(err) {
|
||||
console.log(err);
|
||||
alert('Posting of rule failed: ' + err.responseText);
|
||||
});
|
||||
});
|
||||
// TODO fix, same logic twice
|
||||
$.post('/usercommand', { command: 'get_eventmodules' })
|
||||
.done(function(data) {
|
||||
for(var mod in data) {
|
||||
var mthds = data[mod].methods;
|
||||
if(mthds) {
|
||||
var arr = mthds.split(',');
|
||||
for(var i = 0; i < arr.length; i++) {
|
||||
$('#div_middle ul').append($('<li>').text(mod + '->' + arr[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
$.post('/usercommand', { command: 'get_actionmodules' })
|
||||
.done(function(data) {
|
||||
for(var mod in data) {
|
||||
var mthds = data[mod].methods;
|
||||
if(mthds) {
|
||||
var arr = mthds.split(',');
|
||||
for(var i = 0; i < arr.length; i++) {
|
||||
$('#div_right ul').append($('<li>').text(mod + '->' + arr[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#textarea_rule').val($('#templ_rule').html());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue