truss/comm/dispatcher.js
2019-03-05 19:21:09 -06:00

92 lines
2.5 KiB
JavaScript

import {createDebugAction} from './debug';
import {pack, unpack} from './packer';
import {server as createIpcServer} from './socket.ipc';
import {server as createNetServer} from './socket.net';
import D from 'debug';
const debug = D('truss:comm:dispatcher');
export class Dispatcher {
constructor(actions = (() => ({})), hooks = (() => ({}))) {
this.args = [];
this.lookup = {actions, hooks};
}
connect() {
const server = process.env.TRUSS_IPC ? createIpcServer() : createNetServer();
server.on('connection', (socket) => {
socket.on('error', (error) => { this.handleError(error); });
socket.setEncoding('utf8');
socket.on('data', (chunk) => {
let action = undefined;
try { action = unpack(chunk); }
catch (error) { return this.handleError(error); }
const actions = this.createActions();
if (!(action.type in actions)) {
debug(`discarding ${JSON.stringify(action, null, ' ')}!`);
return;
}
const debugAction = createDebugAction(debug, action);
if (debugAction) {
debug(`dispatching ${JSON.stringify(debugAction, null, ' ')}`);
}
const actionPromise = actions[action.type](action);
Promise.resolve(actionPromise).then((result) => {
if ('undefined' === typeof result) {
debug(`undefined result from ${action.type} not forwarded!`);
}
else {
socket.write(pack(result));
}
socket.end();
}).catch((error) => { this.handleError(error); });
});
});
server.on('listening', () => {
debug(`dispatcher listening...`);
});
server.listen();
return server;
}
createActions() {
const actions = this.lookup.actions(...this.args);
const hooks = this.lookup.hooks(...this.args);
// builtin hook plumbing
actions['@truss/hook'] = (action) => {
if (!(action.payload.hook in hooks)) { return undefined; }
return hooks[action.payload.hook](...action.payload.args);
}
// builtin schema
const originalSchema = actions['@truss/schema'] || (() => ({}));
actions['@truss/schema'] = (action) => {
return {...originalSchema(action), hooks: Object.keys(hooks)};
}
return actions;
}
handleError(error) {
console.error(error);
}
lookupActions(lookup) { this.lookup.actions = lookup; }
lookupHooks(lookup) { this.lookup.hooks = lookup; }
setArgs(...args) { this.args = args; }
}