'use strict'; module.exports.create = function (conf, deps) { var PromiseA = deps.Promise; function loadService(node) { var path = require('path'); return new PromiseA(function (resolve) { // process.nextTick runs at the end of the current event loop // we actually want time to pass so that potential api traffic can be handled setTimeout(function () { var servicepath = path.join(conf.servicespath, node); var pkg; try { // TODO no package should be named package.json pkg = require(servicepath + '/package.json'); resolve({ pkg: pkg , name: node , service: require(servicepath) }); return; } catch(e) { // TODO report errors to admin console // TODO take sha256sum of e.stack and store in db with tick for updatedAt console.error("[Service] could not require service '" + servicepath + "'"); console.error(e.stack); //services.push({ error: e }); resolve(null); return; } }, 1); }); } function loadServices() { var fs = PromiseA.promisifyAll(require('fs')); // deps : { memstore, sqlstores, clientSqlFactory, systemSqlFactory } // XXX this is a no-no (file system access in a worker, cannot be statically analyzed) // TODO regenerate a static file of all requires on each install // TODO read system config db to find which services auto-start // TODO allow certain apis access to certain services return fs.readdirAsync(conf.servicespath).then(function (nodes) { var promise = PromiseA.resolve(); var services = []; nodes.forEach(function (node) { if (/^\./.test(node)) { // ignore dot files return; } promise = promise.then(function () { return loadService(node).then(function (srv) { if (!srv) { return; } services.push(srv); }); }); }); return promise.then(function () { return services; }); }); } function startService(srv) { return new PromiseA(function (resolve) { // process.nextTick runs at the end of the current event loop // we actually want time to pass so that potential api traffic can be handled setTimeout(function () { try { PromiseA.resolve(srv.service.create(conf, deps)).then(resolve, function (e) { console.error("[Service] couldn't promise service"); console.error(e.stack); resolve(null); }); return; } catch(e) { console.error("[Service] couldn't start service"); console.error(e.stack); resolve(null); return; } }, 1); }); } function startServices(services) { var promise = PromiseA.resolve(); var servicesMap = {}; services.forEach(function (srv) { promise = promise.then(function () { return startService(srv).then(function (service) { if (!service) { // TODO log return null; } srv.service = service; servicesMap[srv.name] = srv; }); }); }); return promise.then(function () { return servicesMap; }); } return loadServices().then(startServices); };