mirror of
https://github.com/Hopiu/webapi-eca.git
synced 2026-03-16 22:10:31 +00:00
225 lines
6.9 KiB
JavaScript
225 lines
6.9 KiB
JavaScript
'use strict';
|
|
|
|
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;
|
|
for ( var i = 0; i < actions.length; i++ ){
|
|
var arrMod = actions[i].split(' -> ');
|
|
if ( !listActionModules[user][arrMod[0]] ){
|
|
db.getActionInvoker(arrMod[0], function( err, objAM ){
|
|
db.getActionUserParams(arrMod[0], 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][arrMod[0]] = answ.module;
|
|
console.log('loaded ' + user + ': ' + arrMod[0]);
|
|
console.log(listActionModules);
|
|
// }
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.internalEvent = function( evt, data ) {
|
|
try{
|
|
var obj = JSON.parse( data );
|
|
db.getRuleActivatedUsers(obj.id, function ( err, 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 );
|
|
}
|
|
};
|
|
|
|
|
|
function pollQueue() {
|
|
if(isRunning) {
|
|
db.popEvent(function (err, obj) {
|
|
if(!err && obj) {
|
|
processEvent(obj);
|
|
}
|
|
setTimeout(pollQueue, 50); //TODO adapt to load
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
for(var user in actions) {
|
|
for(var i = 0; i < actions[user].length; i++) {
|
|
invokeAction(evt, user, actions[user][i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 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[user][rule].event === evt.event && validConditions(evt.payload, listRules[user][rule])) {
|
|
log.info('EN', 'Rule "' + rule + '" fired');
|
|
var arrAct = listRules[user][rule].actions;
|
|
for(var i = 0; i < arrAct.length; 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.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 ) {
|
|
var actionargs = {},
|
|
arrModule = action.split(' -> ');
|
|
//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;
|
|
}
|
|
console.log('invoking action');
|
|
console.log(arrModule[0]);
|
|
console.log(listActionModules);
|
|
var srvc = listActionModules[user][arrModule[0]];
|
|
console.log(srvc);
|
|
if(srvc && srvc[arrModule[1]]) {
|
|
//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[arrModule[1]]) srvc[arrModule[1]](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();
|
|
};
|