UNPKG

orator

Version:

Unopinionated restful web API server container

216 lines (190 loc) 6.7 kB
const libOratorServiceServerBase = require('orator-serviceserver'); // A synthesized response object, for simple IPC. const libOratorServiceServerIPCSynthesizedResponse = require('./Orator-ServiceServer-IPC-SynthesizedResponse.js'); // A simple constrainer for the find-my-way router since we aren't using any kind of headers to pass version or host const libOratorServiceServerIPCCustomConstrainer = require('./Orator-ServiceServer-IPC-RouterConstrainer.js'); // This library is the default router for our services const libFindMyWay = require('find-my-way'); //const libAsync = require('async'); const libAsyncWaterfall = require("async/waterfall"); const libAsyncEachOfSeries = require('async/eachofseries') class OratorServiceServerIPC extends libOratorServiceServerBase { constructor(pOrator) { super(pOrator); this.routerOptions = (this.orator.settings.hasOwnProperty('router_options') && (typeof(this.orator.settings.router_options) == 'object')) ? this.orator.settings.router_options : {}; this.router = libFindMyWay(this.routerOptions); this.router.addConstraintStrategy(libOratorServiceServerIPCCustomConstrainer); this.URL = 'IPC'; this.preBehaviorFunctions = []; this.behaviorMap = {}; this.postBehaviorFunctions = []; } executePreBehaviorFunctions(pRequest, pResponse, fNext) { libAsyncEachOfSeries(this.preBehaviorFunctions, (fBehaviorFunction, pFunctionIndex, fCallback) => { return fBehaviorFunction(pRequest, pResponse, fCallback); }, (pError) => { if (pError) { this.log.error(`IPC Provider preBehaviorFunction ${pFunctionIndex} failed with error: ${pError}`, pError); } return fNext(pError); }); } executePostBehaviorFunctions(pRequest, pResponse, fNext) { libAsyncEachOfSeries(this.postBehaviorFunctions, (fBehaviorFunction, pFunctionIndex, fCallback) => { return fBehaviorFunction(pRequest, pResponse, fCallback); }, (pError) => { if (pError) { this.log.error(`IPC Provider postBehaviorFunction ${pFunctionIndex} failed with error: ${pError}`, pError); } return fNext(pError); }); } /* * Service Route Creation Functions * * These base functions provide basic validation for the routes, but don't actually * do anything with them. The design intent here is to allow derived classes to call * these functions to validate that they conform to expected standards. * * Something like: get (pRoute, ...fRouteProcessingFunctions) { //...now we can do our actual get mapping function!.... } * This pattern and calling super is totally optional, obviously. *************************************************************************/ addRouteProcessor(pMethod, pRoute, pRouteFunctionArray) { // We have a constrainer on IPC so we can control channels eventually, if we like. // For now it just makes sure it was added with an IPC service server. this.router.on(pMethod, pRoute, { constraints: { "ipc": "IPC" } }, (pRequest, pResponse, pParameters) => { libAsyncWaterfall( [ (fStageComplete)=> { // Added to make this mimic what we saw with route parsing in the old restify pRequest.params = pParameters; return fStageComplete(); }, (fStageComplete)=> { return this.executePreBehaviorFunctions(pRequest, pResponse, fStageComplete); }, (fStageComplete)=> { libAsyncEachOfSeries(pRouteFunctionArray, (fBehaviorFunction, pFunctionIndex, fCallback) => { return fBehaviorFunction(pRequest, pResponse, fCallback); }, (pBehaviorFunctionError) => { if (pBehaviorFunctionError) { this.log.error(`IPC Provider behavior function ${pFunctionIndex} failed with error: ${pBehaviorFunctionError}`, pBehaviorFunctionError); return fNext(pError); } }); }, (fStageComplete)=> { return this.executePostBehaviorFunctions(pRequest, pResponse, fStageComplete); } ], (pRequestError)=> { if (pRequestError) { this.log.error(`IPC Provider behavior function ${pFunctionIndex} failed with error: ${pBehaviorFunctionError}`, pBehaviorFunctionError); } }); }); return true; } get(pRoute, ...fRouteProcessingFunctions) { if (!super.get(pRoute, ...fRouteProcessingFunctions)) { this.log.error(`IPC provider failed to map GET route [${pRoute}]!`); return false; } return this.addRouteProcessor('GET', pRoute, Array.from(fRouteProcessingFunctions)); } put(pRoute, ...fRouteProcessingFunctions) { if (!super.get(pRoute, ...fRouteProcessingFunctions)) { this.log.error(`IPC provider failed to map PUT route [${pRoute}]!`); return false; } return true; } post(pRoute, ...fRouteProcessingFunctions) { if (!super.get(pRoute, ...fRouteProcessingFunctions)) { this.log.error(`IPC provider failed to map POST route [${pRoute}]!`); return false; } return true; } del(pRoute, ...fRouteProcessingFunctions) { if (!super.get(pRoute, ...fRouteProcessingFunctions)) { this.log.error(`IPC provider failed to map DEL route [${pRoute}]!`); return false; } return true; } /************************************************************************* * End of Service Route Creation Functions */ // Programmatically invoke a route invoke(pMethod, pRoute, pData, fCallback) { // If the data is skipped and a callback is parameter 3, do the right thing let tmpCallback = (typeof(fCallback) == 'function') ? fCallback : (typeof(pData) == 'function') ? pData : // This is here in case the developer passed no callback and just wants to fire and forget the IPC call which might not be async safe ()=>{}; // Create a bare minimum request object for IPC to pass to our router let tmpRequest = ( { method: pMethod, url: pRoute, guid: this.orator.fable.getUUID() }); // Create a container for the IPC response data to be aggregated to from send() methodds let tmpSynthesizedResponseData = new libOratorServiceServerIPCSynthesizedResponse(this.log, tmpRequest.guid); return this.router.lookup( tmpRequest, tmpSynthesizedResponseData, (pError, pResults)=> { if (pError) { this.log.error(`IPC Request Error Request GUID [${tmpRequest.guid}] handling route [${pRoute}]: ${pError}`, {Error: pError, Route: pRoute, Data: pData}); } // by default, send data back through return tmpCallback(pError, tmpSynthesizedResponseData.responseData, tmpSynthesizedResponseData, pResults); }); } } module.exports = OratorServiceServerIPC;