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; } }