diff options
Diffstat (limited to 'packages/subproviders/src/subproviders/redundant_subprovider.ts')
-rw-r--r-- | packages/subproviders/src/subproviders/redundant_subprovider.ts | 65 |
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); + } + } +} |