mirror of
https://github.com/Hopiu/webapi-eca.git
synced 2026-03-16 22:10:31 +00:00
182 lines
5.7 KiB
JavaScript
182 lines
5.7 KiB
JavaScript
/*
|
|
# Module Manager
|
|
> The module manager takes care of the module and rules loading in the initialization
|
|
> phase and on user request.
|
|
|
|
> Event and Action modules are loaded as strings and stored in the database,
|
|
> then compiled into node modules and rules
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var fs = require('fs'),
|
|
path = require('path'),
|
|
log,
|
|
db, funcLoadAction, funcLoadRule;
|
|
|
|
exports = module.exports = function(args) {
|
|
args = args || {};
|
|
log = args.logger;
|
|
return module.exports;
|
|
};
|
|
|
|
exports.addDBLink = function(db_link) {
|
|
db = db_link;
|
|
};
|
|
|
|
exports.requireFromString = function(src, name, dir) {
|
|
if(!dir) dir = __dirname;
|
|
var id = path.resolve(dir, name, name + '.vm');
|
|
var vm = require('vm'),
|
|
// FIXME not log but debug module is required to provide information to the user
|
|
sandbox = {
|
|
id: id, // use this to gather kill info
|
|
needle: require('needle'), //https://github.com/tomas/needle
|
|
log: log,
|
|
exports: {}
|
|
};
|
|
//TODO child_process to run module!
|
|
// Define max runtime per loop as 10 seconds, after that the child will be killed
|
|
// it can still be active after that if there was a timing function or a callback used...
|
|
// kill the child each time? how to determine whether there's still a token in the module?
|
|
try {
|
|
var mod = vm.runInNewContext(src, sandbox, id);
|
|
|
|
} catch (err) {
|
|
log.error('ML', 'Error running module in sandbox: ' + err.message);
|
|
}
|
|
return sandbox.exports;
|
|
};
|
|
|
|
exports.loadModule = function(directory, name, callback) {
|
|
try {
|
|
fs.readFile(path.resolve(__dirname, '..', directory, name, name + '.js'), 'utf8', function (err, data) {
|
|
if (err) {
|
|
log.error('LM', 'Loading module file!');
|
|
return;
|
|
}
|
|
var mod = exports.requireFromString(data, name, directory);
|
|
if(mod && fs.existsSync(path.resolve(__dirname, '..', directory, name, 'credentials.json'))) {
|
|
fs.readFile(path.resolve(__dirname, '..', directory, name, 'credentials.json'), 'utf8', function (err, auth) {
|
|
if (err) {
|
|
log.error('LM', 'Loading credentials file for "' + name + '"!');
|
|
callback(name, data, mod, null);
|
|
return;
|
|
}
|
|
if(mod.loadCredentials) mod.loadCredentials(JSON.parse(auth));
|
|
callback(name, data, mod, auth);
|
|
});
|
|
} else {
|
|
// Hand back the name, the string contents and the compiled module
|
|
callback(name, data, mod, null);
|
|
}
|
|
});
|
|
} catch(err) {
|
|
log.error('LM', 'Failed loading module "' + name + '"');
|
|
}
|
|
};
|
|
|
|
exports.loadModules = function(directory, callback) {
|
|
fs.readdir(path.resolve(__dirname, '..', directory), function (err, list) {
|
|
if (err) {
|
|
log.error('LM', 'loading modules directory: ' + err);
|
|
return;
|
|
}
|
|
log.info('LM', 'Loading ' + list.length + ' modules from "' + directory + '"');
|
|
list.forEach(function (file) {
|
|
fs.stat(path.resolve(__dirname, '..', directory, file), function (err, stat) {
|
|
if (stat && stat.isDirectory()) {
|
|
exports.loadModule(directory, file, callback);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
exports.storeEventModule = function (objUser, obj, answHandler) {
|
|
try {
|
|
// TODO in the future we might want to link the modules close to the user
|
|
// and allow for e.g. private modules
|
|
// we need a child process to run this code and kill it after invocation
|
|
var m = exports.requireFromString(obj.data, obj.id);
|
|
obj.methods = Object.keys(m);
|
|
answHandler.answerSuccess('Thank you for the event module!');
|
|
db.storeEventModule(obj.id, obj);
|
|
} catch (err) {
|
|
answHandler.answerError(err.message);
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
exports.getAllEventModules = function ( objUser, obj, answHandler ) {
|
|
db.getEventModules(function(err, obj) {
|
|
if(err) answHandler.answerError('Failed fetching event modules: ' + err.message);
|
|
else answHandler.answerSuccess(obj);
|
|
});
|
|
};
|
|
|
|
exports.storeActionModule = function (objUser, obj, answHandler) {
|
|
var m = exports.requireFromString(obj.data, obj.id);
|
|
obj.methods = Object.keys(m);
|
|
answHandler.answerSuccess('Thank you for the action module!');
|
|
db.storeActionModule(obj.id, obj);
|
|
};
|
|
|
|
exports.getAllActionModules = function ( objUser, obj, answHandler ) {
|
|
db.getActionModules(function(err, obj) {
|
|
if(err) answHandler.answerError('Failed fetching action modules: ' + err.message);
|
|
else answHandler.answerSuccess(obj);
|
|
});
|
|
};
|
|
|
|
exports.storeRule = function (objUser, obj, answHandler) {
|
|
//TODO fix, twice same logic
|
|
var cbEventModule = function (lstParams) {
|
|
return function(err, data) {
|
|
if(err) {
|
|
err.addInfo = 'fetching event module';
|
|
log.error('MM', err);
|
|
}
|
|
if(!err && data) {
|
|
if(data.params) {
|
|
lstParams.eventmodules[data.id] = data.params;
|
|
}
|
|
}
|
|
if(--semaphore === 0) answHandler.answerSuccess(lstParams);
|
|
};
|
|
};
|
|
var cbActionModule = function (lstParams) {
|
|
return function(err, data) {
|
|
if(err) {
|
|
err.addInfo = 'fetching action module';
|
|
log.error('MM', err);
|
|
}
|
|
if(!err && data) {
|
|
if(data.params) {
|
|
lstParams.actionmodules[data.id] = data.params;
|
|
}
|
|
}
|
|
if(--semaphore === 0) answHandler.answerSuccess(lstParams);
|
|
};
|
|
};
|
|
|
|
var semaphore = 1;
|
|
var lst = {
|
|
eventmodules: {},
|
|
actionmodules: {}
|
|
};
|
|
try {
|
|
var objRule = JSON.parse(obj.data);
|
|
for(var i = 0; i < objRule.actions.length; i++) {
|
|
semaphore++;
|
|
db.getActionModule(objRule.actions[i].module.split('->')[0], cbActionModule(lst));
|
|
}
|
|
db.getEventModule(objRule.event.split('->')[0], cbEventModule(lst));
|
|
db.storeRule(objRule.id, objUser.username, obj.data);
|
|
} catch(err) {
|
|
answHandler.answerError(err.message);
|
|
log.error('MM', err);
|
|
}
|
|
|
|
};
|