aboutsummaryrefslogtreecommitdiffstats
path: root/packages/subproviders/src/subproviders/redundant_subprovider.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/subproviders/src/subproviders/redundant_subprovider.ts')
-rw-r--r--packages/subproviders/src/subproviders/redundant_subprovider.ts65
1 files changed, 65 insertions, 0 deletions
diff --git a/packages/subproviders/src/subproviders/redundant_subprovider.ts b/packages/subproviders/src/subproviders/redundant_subprovider.ts
new file mode 100644
index 000000000..37c8bba5a
--- /dev/null
+++ b/packages/subproviders/src/subproviders/redundant_subprovider.ts
@@ -0,0 +1,65 @@
+import { JSONRPCRequestPayload } from '@0xproject/types';
+import { promisify } from '@0xproject/utils';
+import * as _ from 'lodash';
+
+import { Callback } from '../types';
+
+import { Subprovider } from './subprovider';
+
+/**
+ * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface.
+ * It attempts to handle each JSON RPC request by sequentially attempting to receive a valid response from one of a
+ * set of JSON RPC endpoints.
+ */
+export class RedundantSubprovider extends Subprovider {
+ private _subproviders: Subprovider[];
+ private static async _firstSuccessAsync(
+ subproviders: Subprovider[],
+ payload: JSONRPCRequestPayload,
+ next: Callback,
+ ): Promise<any> {
+ let lastErr: Error | undefined;
+ for (const subprovider of subproviders) {
+ try {
+ const data = await promisify(subprovider.handleRequest.bind(subprovider))(payload, next);
+ return data;
+ } catch (err) {
+ lastErr = err;
+ continue;
+ }
+ }
+ if (!_.isUndefined(lastErr)) {
+ throw lastErr;
+ }
+ }
+ /**
+ * Instantiates a new RedundantSubprovider
+ * @param endpoints JSON RPC endpoints to attempt. Attempts are made in the order of the endpoints.
+ */
+ constructor(subproviders: Subprovider[]) {
+ super();
+ this._subproviders = subproviders;
+ }
+ /**
+ * This method conforms to the web3-provider-engine interface.
+ * It is called internally by the ProviderEngine when it is this subproviders
+ * turn to handle a JSON RPC request.
+ * @param payload JSON RPC payload
+ * @param next Callback to call if this subprovider decides not to handle the request
+ * @param end Callback to call if subprovider handled the request and wants to pass back the request.
+ */
+ // tslint:disable-next-line:async-suffix
+ public async handleRequest(
+ payload: JSONRPCRequestPayload,
+ next: Callback,
+ end: (err: Error | null, data?: any) => void,
+ ): Promise<void> {
+ const subprovidersCopy = this._subproviders.slice();
+ try {
+ const data = await RedundantSubprovider._firstSuccessAsync(subprovidersCopy, payload, next);
+ end(null, data);
+ } catch (err) {
+ end(err);
+ }
+ }
+}