happn-3
Version:
pub/sub api as a service using primus and mongo & redis or nedb, can work as cluster, single process or embedded using nedb
160 lines (118 loc) • 4.14 kB
JavaScript
var async = require('async'),
Promise = require('bluebird');
function ServiceManager() {}
ServiceManager.prototype.initialize = function(config, happn, callback) {
this.happn = happn;
if (!config.services) config.services = {};
if (!config.services.system) config.services.system = {};
if (!config.services.system.config) config.services.system.config = {};
if (config.name) config.services.system.config.name = config.name;
var loadService = function(serviceName, serviceLoaded) {
happn.log.$$TRACE('loadService( ' + serviceName);
if (!config.services[serviceName]) config.services[serviceName] = {};
if (!config.services[serviceName].path)
config.services[serviceName].path = './' + serviceName + '/service.js';
if (!config.services[serviceName].config) config.services[serviceName].config = {};
var ServiceDefinition, serviceInstance, serviceConfig;
serviceConfig = config.services[serviceName];
function doServiceLoaded(e) {
if (e) {
happn.log.error('Failed to instantiate service: ' + serviceName, e);
return serviceLoaded(e);
}
happn.log.info(serviceName + ' service loaded.');
_this.__loaded.push(serviceName);
serviceLoaded();
}
if (!serviceConfig.instance) {
try {
ServiceDefinition = require(serviceConfig.path);
serviceInstance = new ServiceDefinition({
logger: happn.log
});
} catch (e) {
return doServiceLoaded(e);
}
} else serviceInstance = serviceConfig.instance;
serviceInstance.happn = happn;
happn.services[serviceName] = serviceInstance;
if (!serviceConfig.config) serviceConfig.config = {};
if (config.secure) serviceConfig.config.secure = true;
serviceInstance.__happnerSettings = serviceConfig;
doServiceLoaded();
};
var _this = this;
var initializeServices = function(e, serviceNames) {
if (e) return callback(e);
async.eachSeries(
serviceNames,
function(serviceName, serviceInstanceCB) {
var serviceInstance = _this.happn.services[serviceName];
if (typeof serviceInstance.initialize === 'function')
return serviceInstance.initialize(
serviceInstance.__happnerSettings.config,
serviceInstanceCB
);
serviceInstanceCB();
},
callback
);
};
_this.__loaded = [];
var systemServices = [
'utils',
'error',
'log',
'data',
'system',
'cache',
'connect',
'crypto',
'transport',
'session',
'protocol',
'security',
'subscription',
'publisher',
'stats'
];
//these are supplementary services defiend in app-land, will always start after system services
var appServices = [];
Object.keys(config.services).forEach(function(serviceName) {
if (systemServices.indexOf(serviceName) === -1) appServices.push(serviceName);
});
async.eachSeries(systemServices, loadService, function(e) {
if (e) return callback(e);
async.eachSeries(appServices, loadService, function(e) {
initializeServices(e, _this.__loaded); //so that circular dependancies can be met
});
});
};
ServiceManager.prototype.stop = Promise.promisify(function(options, callback) {
var _this = this;
if (typeof options === 'function') {
callback = options;
options = {};
}
if (options.kill && !options.wait) options.wait = 10000;
var kill = function() {
process.exit(options.exitCode || 1);
};
if (options.kill) {
setTimeout(function() {
_this.happn.services.log.error('failed to stop happn, force true');
kill();
}, options.wait);
}
//we stop everything in reverse, that way primus (session service) is able to say goodbye properly before transport service
async.eachSeries(
_this.__loaded.reverse(),
function(serviceName, stopServiceCB) {
var serviceInstance = _this.happn.services[serviceName];
if (serviceInstance.stop) serviceInstance.stop(options, stopServiceCB);
else stopServiceCB();
},
callback
);
});
module.exports = ServiceManager;