webapi-eca/js/engine.js
2014-04-05 03:09:40 +02:00

293 lines
8.1 KiB
JavaScript

// Generated by CoffeeScript 1.7.1
/*
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() {
var db, dynmod, exports, isRunning, jsonQuery, listUserRules, pollQueue, processEvent, updateActionModules, validConditions;
db = require('./persistence');
dynmod = require('./dynamic-modules');
jsonQuery = require('js-select');
/*
This is ging to have a structure like:
An object of users with their active rules and the required action modules
"user-1":
"rule-1":
"rule": oRule-1
"actions":
"action-1": oAction-1
"action-2": oAction-2
"rule-2":
"rule": oRule-2
"actions":
"action-1": oAction-1
"user-2":
"rule-3":
"rule": oRule-3
"actions":
"action-3": oAction-3
*/
listUserRules = {};
isRunning = false;
/*
Module call
-----------
Initializes the Engine and starts polling the event queue for new events.
@param {Object} args
*/
exports = module.exports = (function(_this) {
return function(args) {
if (!isRunning) {
isRunning = true;
_this.log = args.logger;
db(args);
dynmod(args);
setTimeout(pollQueue, 10);
return module.exports;
}
};
})(this);
/*
This is a helper function for the unit tests so we can verify that action
modules are loaded correctly
@public getListUserRules ()
*/
exports.getListUserRules = function() {
return listUserRules;
};
/*
An event associated to rules happened and is captured here. Such events
are basically CRUD on rules.
@public internalEvent ( *evt* )
@param {Object} evt
*/
exports.internalEvent = (function(_this) {
return function(evt) {
var oRule, oUser;
if (!listUserRules[evt.user] && evt.event !== 'del') {
listUserRules[evt.user] = {};
}
oUser = listUserRules[evt.user];
oRule = evt.rule;
if (evt.event === 'new' || (evt.event === 'init' && !oUser[oRule.id])) {
oUser[oRule.id] = {
rule: oRule,
actions: {}
};
updateActionModules(oRule.id);
}
if (evt.event === 'del' && oUser) {
delete oUser[evt.ruleId];
}
if (JSON.stringify(oUser) === "{}") {
return delete listUserRules[evt.user];
}
};
})(this);
/*
As soon as changes were made to the rule set we need to ensure that the aprropriate action
invoker modules are loaded, updated or deleted.
@private updateActionModules ( *updatedRuleId* )
@param {Object} updatedRuleId
*/
updateActionModules = function(updatedRuleId) {
var fAddRequired, fRemoveNotRequired, name, oUser, userName, _results;
fRemoveNotRequired = function(oUser) {
var action, fRequired, _results;
fRequired = function(actionName) {
var action, _i, _len, _ref;
_ref = oUser[updatedRuleId].rule.actions;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
if ((action.split(' -> '))[0] === actionName) {
return true;
}
}
return false;
};
_results = [];
for (action in oUser[updatedRuleId].rule.actions) {
if (!fRequired(action)) {
_results.push(delete oUser[updatedRuleId].actions[action]);
} else {
_results.push(void 0);
}
}
return _results;
};
for (name in listUserRules) {
oUser = listUserRules[name];
fRemoveNotRequired(oUser);
}
fAddRequired = function(userName, oUser) {
var fCheckRules, nmRl, oRl, _results;
fCheckRules = function(oMyRule) {
var action, fAddIfNewOrNotExisting, _i, _len, _ref, _results;
fAddIfNewOrNotExisting = function(actionName) {
var moduleName;
moduleName = (actionName.split(' -> '))[0];
if (!oMyRule.actions[moduleName] || oMyRule.rule.id === updatedRuleId) {
return db.actionInvokers.getModule(moduleName, function(err, obj) {
return dynmod.compileString(obj.data, userName, oMyRule.rule.id, moduleName, obj.lang, db.actionInvokers, function(result) {
if (!result.answ === 200) {
this.log.error("EN | Compilation of code failed! " + userName + ", " + oMyRule.rule.id + ", " + moduleName);
}
return oMyRule.actions[moduleName] = result.module;
});
});
}
};
_ref = oMyRule.rule.actions;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
_results.push(fAddIfNewOrNotExisting(action));
}
return _results;
};
_results = [];
for (nmRl in oUser) {
oRl = oUser[nmRl];
_results.push(fCheckRules(oRl));
}
return _results;
};
_results = [];
for (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 prop, _i, _len, _ref;
if (rule.conditions.length === 0) {
return true;
}
_ref = rule.conditions;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prop = _ref[_i];
if (jsonQuery(evt, prop).nodes().length === 0) {
return false;
}
}
return true;
};
/*
Handles retrieved events.
@private processEvent ( *evt* )
@param {Object} evt
*/
processEvent = (function(_this) {
return function(evt) {
var action, arr, fSearchAndInvokeAction, oMyRule, oUser, ruleName, userName, _results;
fSearchAndInvokeAction = function(node, arrPath, evt, depth) {
var err;
if (!node) {
this.log.error("EN | Didn't find property in user rule list: " + arrPath.join(', ' + " at depth " + depth));
return;
}
if (depth === arrPath.length) {
try {
return node(evt.payload);
} catch (_error) {
err = _error;
return this.log.info("EN | ERROR IN ACTION INVOKER: " + err.message);
}
} else {
return fSearchAndInvokeAction(node[arrPath[depth]], arrPath, evt, depth + 1);
}
};
_this.log.info('EN | processing event: ' + evt.event + '(' + evt.eventid + ')');
_results = [];
for (userName in listUserRules) {
oUser = listUserRules[userName];
_results.push((function() {
var _results1;
_results1 = [];
for (ruleName in oUser) {
oMyRule = oUser[ruleName];
if (evt.event === oMyRule.rule.event && validConditions(evt, oMyRule.rule)) {
this.log.info('EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName);
_results1.push((function() {
var _i, _len, _ref, _results2;
_ref = oMyRule.rule.actions;
_results2 = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
arr = action.split(' -> ');
_results2.push(fSearchAndInvokeAction(listUserRules, [userName, ruleName, 'actions', arr[0], arr[1]], evt, 0));
}
return _results2;
})());
} else {
_results1.push(void 0);
}
}
return _results1;
}).call(_this));
}
return _results;
};
})(this);
exports.shutDown = function() {
return isRunning = false;
};
}).call(this);