From 7acaae37a969339d1b4971f80d7fd842266bb60b Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 8 Nov 2018 14:57:39 -0800 Subject: feat(instant): Heartbeat for updating account info --- .../src/components/zero_ex_instant_provider.tsx | 13 +++++- packages/instant/src/constants.ts | 1 + packages/instant/src/redux/async_data.ts | 4 +- packages/instant/src/util/hearbeats.ts | 47 ++++++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 packages/instant/src/util/hearbeats.ts (limited to 'packages/instant') diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index fa0588b71..02f14c5b6 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -5,6 +5,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { Provider as ReduxProvider } from 'react-redux'; +import { ACCOUNT_UPDATE_INTERVAL_TIME_MS } from '../constants'; import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; import { asyncData } from '../redux/async_data'; import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; @@ -14,6 +15,7 @@ import { AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; +import { AccountUpdateHeartbeat } from '../util/hearbeats'; import { providerStateFactory } from '../util/provider_state_factory'; fonts.include(); @@ -37,6 +39,7 @@ export interface ZeroExInstantProviderOptionalProps { export class ZeroExInstantProvider extends React.Component { private readonly _store: Store; + private _accountUpdateHeartbeat?: AccountUpdateHeartbeat; // TODO(fragosti): Write tests for this beast once we inject a provider. private static _mergeDefaultStateWithProps( props: ZeroExInstantProviderProps, @@ -93,7 +96,10 @@ export class ZeroExInstantProvider extends React.Component diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 705313ce7..d0a86c780 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -10,6 +10,7 @@ export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction fa export const GWEI_IN_WEI = new BigNumber(1000000000); export const ONE_SECOND_MS = 1000; export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; +export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index 862f60e78..055d3de20 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -34,10 +34,10 @@ export const asyncData = { store.dispatch(actions.setAvailableAssets([])); } }, - fetchAccountInfoAndDispatchToStore: async (store: Store) => { + fetchAccountInfoAndDispatchToStore: async (store: Store, options = { setLoading: true }) => { const { providerState } = store.getState(); const web3Wrapper = providerState.web3Wrapper; - if (providerState.account.state !== AccountState.Loading) { + if (options.setLoading && providerState.account.state !== AccountState.Loading) { store.dispatch(actions.setAccountStateLoading()); } let availableAddresses: string[]; diff --git a/packages/instant/src/util/hearbeats.ts b/packages/instant/src/util/hearbeats.ts new file mode 100644 index 000000000..19b448bef --- /dev/null +++ b/packages/instant/src/util/hearbeats.ts @@ -0,0 +1,47 @@ +import * as _ from 'lodash'; + +import { asyncData } from './../redux/async_data'; +import { Store } from './../redux/store'; + +export class AccountUpdateHeartbeat { + private _intervalId?: number; + private _pendingRequest?: boolean; + private _store?: Store; + + public start(store: Store, intervalTimeMs: number): void { + if (!_.isUndefined(this._intervalId)) { + throw new Error('Heartbeat is running, please stop before restarting'); + } + this._store = store; + // Kick off initial first request + this._performActionAsync(true); + // Set interval for heartbeat + this._intervalId = window.setInterval(this._performActionAsync.bind(this, false), intervalTimeMs); + } + + public stop(): void { + if (!_.isUndefined(this._intervalId)) { + window.clearInterval(this._intervalId); + this._resetState(); + } + } + + private _resetState(): void { + this._intervalId = undefined; + this._pendingRequest = false; + this._store = undefined; + } + + private async _performActionAsync(setLoading: boolean): Promise { + if (this._pendingRequest || _.isUndefined(this._store)) { + return; + } + + this._pendingRequest = true; + try { + await asyncData.fetchAccountInfoAndDispatchToStore(this._store, { setLoading }); + } finally { + this._pendingRequest = false; + } + } +} -- cgit v1.2.3