UNPKG

@vistadataproject/vista-client

Version:

Updated VISTA RPC Client NodeJS module with Promise-based API

166 lines (138 loc) 4.14 kB
'use strict'; // # RPC // A normalized representation of RPC request, response and ancillary data, as it relates to the VISTAClient. // // The **RPC** class takes care of the low-level RPC format functionality, as well as state and operational // result storage, so that the VISTA Client doesn't have to. const dateFormat = require('dateformat'); const { Encrypt, Format, Parse } = require('@vistadataproject/rpc-utilities'); const { checkForTemplates, renderTemplate } = require('./template'); const { value, identity, copy, diff, } = require('./utils'); const encrypt = (arg) => { const rawValue = value(arg); const deferred = (context = {}) => { const result = renderTemplate(rawValue, context); return Encrypt.encrypt(result); } return checkForTemplates(rawValue) ? deferred : deferred(); }; const NORMALIZER_MAP = { default: identity, unknownType: value, string: value, number: value, reference: identity, encrypt, }; const DEFAULT_STATE = { iterations: 0, start: null, stop: null, }; class RPC { static createFromRaw(raw, options = {}) { const { name, args } = Parse.parseRawRPC(raw); return new RPC({ name, args, raw, options, }); } static create(name, args = [], options = {}) { const normalizedArgs = args.map((arg) => { const { type = 'default' } = arg; const normalizer = NORMALIZER_MAP[type.toString().toLowerCase()] || NORMALIZER_MAP.unknownType; return normalizer(arg); }); const isTemplated = normalizedArgs.some(arg => (checkForTemplates(arg) || typeof arg === 'function')); const raw = !isTemplated ? Format.buildRpcString(name, normalizedArgs) : null; return new RPC({ name, args: normalizedArgs, raw, options, }); } reset() { Object.assign(this, { state: copy(DEFAULT_STATE), results: [], }); } getRequest(context = {}) { const { state } = this; Object.assign(state, { timestamp: dateFormat(new Date(), 'isoUtcDateTime'), start: process.hrtime(), stop: null, iterations: state.iterations + 1, data: this.raw || this.generateRawData(context), }); return state.data; } generateRawData(context) { const { state } = this; state.args = this.args.map(arg => renderTemplate(arg, context)); return Format.buildRpcString(this.name, state.args); } setRawResponse(raw) { const val = Parse.parseRawResults(raw); this._response({ raw, val }); } setResponse(val) { const raw = Format.buildResponseString(val); this._response({ raw, val }); } isComplete() { const { repeat } = this.options; const { iterations } = this.state; return (!repeat || iterations >= repeat); } lastResult() { const { length } = this.results; return (length > 0 ? this.results[length - 1] : null); } popLastResult() { const { length } = this.results; return (length > 0 ? this.results.pop() : null); } constructor({ name, args, raw, options, }) { Object.assign(this, { name, args, raw, options, }); this.reset(); } _response({ raw, val }) { const { state } = this; Object.assign(state, { stop: state.start ? process.hrtime(state.start) : null, }); this.results.push(Object.assign({ name: this.name, args: state.args || this.args, raw: state.data, response: { raw, value: val, }, timestamp: state.timestamp, duration: state.start ? diff(state.stop) : 0.0, iteration: state.iterations, })); } } module.exports = { RPC };