ironbar/services/gateway/index.js
2018-08-31 04:36:26 -05:00

102 lines
2.8 KiB
JavaScript

const http = require('http');
const debug = require('debug')('truss:gateway');
const {createDispatcher, sendActionToService} = require('@truss/truss');
let listener = require('./listener');
// ---
if (!process.env.SERVICES) {
console.error('$SERVICES must be defined!');
process.exit(1);
}
const services = process.env.SERVICES.split(',');
// get all schemas
const schemas$ = services.map((service) => {
return sendActionToService({type: 'truss/schema'}, service);
});
// build service map
const reduceServiceMap$ = Promise.all(schemas$).then((schemas) => {
return schemas.reduce((l, r, i) => {
for (const type of (r.executors || [])) {
if (l.executors[type]) {
throw new Error(`
Only one executor may be specified per action type! "${services[i]}" tried to
register an executor but "${l.executors[type]}" already registered one for
${type}.
`);
}
l.executors[type] = services[i];
}
for (const type of (r.listeners || [])) {
(l.listeners[type] = l.listeners[type] || []).push(services[i]);
}
for (const hook of (r.hooks || [])) {
(l.hooks[hook] = l.hooks[hook] || []).push(services[i]);
}
return l;
}, {
executors: {},
hooks: {},
listeners: {},
});
});
// hey, listen
const httpServer = http.createServer();
reduceServiceMap$.then((serviceMap) => {
debug(`service map: ${JSON.stringify(serviceMap)}`);
const port = process.env.GATEWAY_PORT || 8000;
httpServer.listen(port);
httpServer.on('listening', () => {
debug(`HTTP listening on port ${port}...`);
})
httpServer.on('request', (req, res) => {
listener(serviceMap, req, res);
});
// hooks
createDispatcher({
'truss/hook-services': ({payload: {hook, args}}) => {
if (!(hook in serviceMap.hooks)) { return []; }
return serviceMap.hooks[hook];
},
'truss/invoke': ({payload: {hook, args}}) => {
if (!(hook in serviceMap.hooks)) { return {}; }
return invokeHook(serviceMap.hooks[hook], hook, args);
},
'truss/invoke-flat': ({payload: {hook, args}}) => {
if (!(hook in serviceMap.hooks)) { return []; }
return invokeHookFlat(serviceMap.hooks[hook], hook, args);
},
}).connect();
}).catch(console.error);
function invokeHookFlat(services, hook, args) {
debug(`invoking hook flat(${hook}(${JSON.stringify(args)}))...`);
const action = {type: 'truss/hook', payload: {hook, args}};
return Promise.all(services.map((service) => {
return sendActionToService(action, service);
}));
}
function invokeHook(services, hook, args) {
debug(`invoking hook ${hook}(${JSON.stringify(args)})...`);
return invokeHookFlat(services, hook, args).then((result) => {
return result.reduce((l, r, i) => (l[services[i]] = r, l), {});
});
}
if (module.hot) {
module.hot.accept('./listener', () => {
listener = require('./listener');
});
}