@ch1/rpc
Version:
JavaScript Remote Procedure Call (RPC)
88 lines • 3.54 kB
JavaScript
/**
* Main module "really ties the project together"
*/
import { createUidGenerator, isObject, pnoop, typeError, safeInvoke, throwIfNotFunction, } from './utils';
import { create as createRemote, createRemoteDescFrom } from './remote';
import * as nOp from './response';
import { DEFAULT_ASYNC_TYPE, DEFAULT_MESSAGE, DEFAULT_CREATE_RETRY, DEFAULT_CREATE_RETRY_CURVE, DEFAULT_CREATE_WAIT, } from './constants';
/**
* Where `RemoteType` is the description of the interface you _expect_ to be
* exposed *by the "other side"*
* @param config
* @param remote optional remote to expose *on the "other side"*
*/
export function create(config, remote, remoteDesc) {
remote = validateRemote(remote);
config = validateConfig(config, remote);
const onDestroyDict = Object.create(null);
const local = Object.create(null);
const { callbacks } = config;
const combinedDesc = createRemoteDescFrom(config, remote, remoteDesc);
let destroy = pnoop;
const isReady = nOp
.create(config, callbacks, combinedDesc)
.then(network => {
createRemote(config, callbacks, network.remoteDesc, local);
destroy = network.off;
});
return {
config,
destroy: (reason = '') => {
Object.keys(local).forEach(key => delete local[key]);
flushCallbacks(callbacks, config.functionalState.errorHandlers, reason);
return destroy().then(() => {
destroy = pnoop;
Object.keys(onDestroyDict).forEach(key => {
safeInvoke(onDestroyDict[key], [reason]);
delete onDestroyDict[key];
});
});
},
onDestroy: (callback) => {
const id = Date.now().toString(32) +
Math.floor(Math.random() * 50000).toString(32);
onDestroyDict[id] = callback;
return () => {
delete onDestroyDict[id];
};
},
ready: isReady,
remote: local,
};
}
export function flushCallbacks(callbacks, errorHandlers, reason = '') {
Object.keys(callbacks).forEach(id => {
const cb = callbacks[id];
errorHandlers[cb.type]
? errorHandlers[cb.type](cb.async, new Error('rpc flush ' + reason))
: console.warn('rpc: flush: no error handler registered for ' + cb.type);
delete callbacks[id];
});
}
export function validateRemote(r) {
r = r || Object.create(null);
if (!isObject(r)) {
typeError('validateRemote: remote must be an object');
}
return r;
}
export function validateConfig(c, remote) {
throwIfNotFunction(c.on, 'validateConfig: config requires an on method');
throwIfNotFunction(c.emit, 'validateConfig: config requires an emit method');
c.defaultAsyncType = c.defaultAsyncType || DEFAULT_ASYNC_TYPE;
c.defaultCreateRetry = c.defaultCreateRetry || DEFAULT_CREATE_RETRY;
c.defaultCreateRetryCurve =
c.defaultCreateRetryCurve || DEFAULT_CREATE_RETRY_CURVE;
c.defaultCreateWait = c.defaultCreateWait || DEFAULT_CREATE_WAIT;
c.enableStackTrace = c.enableStackTrace || false;
c.functionalState = nOp.createFunctionalState();
c.callbacks = Object.create(null);
c.maxAckDelay = c.maxAckDelay || 5000;
c.message = c.message || DEFAULT_MESSAGE;
c.uid = createUidGenerator();
c.useAcks = c.useAcks ? Object.create(null) : null;
c.remote = remote;
return Object.freeze(c);
}
export function extend() { }
//# sourceMappingURL=js-rpc.js.map