feat(instant): Heartbeat for updating account info
This commit is contained in:
		@@ -5,6 +5,7 @@ import * as _ from 'lodash';
 | 
				
			|||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
import { Provider as ReduxProvider } from 'react-redux';
 | 
					import { Provider as ReduxProvider } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ACCOUNT_UPDATE_INTERVAL_TIME_MS } from '../constants';
 | 
				
			||||||
import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
 | 
					import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
 | 
				
			||||||
import { asyncData } from '../redux/async_data';
 | 
					import { asyncData } from '../redux/async_data';
 | 
				
			||||||
import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
 | 
					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 { assetUtils } from '../util/asset';
 | 
				
			||||||
import { errorFlasher } from '../util/error_flasher';
 | 
					import { errorFlasher } from '../util/error_flasher';
 | 
				
			||||||
import { gasPriceEstimator } from '../util/gas_price_estimator';
 | 
					import { gasPriceEstimator } from '../util/gas_price_estimator';
 | 
				
			||||||
 | 
					import { AccountUpdateHeartbeat } from '../util/hearbeats';
 | 
				
			||||||
import { providerStateFactory } from '../util/provider_state_factory';
 | 
					import { providerStateFactory } from '../util/provider_state_factory';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fonts.include();
 | 
					fonts.include();
 | 
				
			||||||
@@ -37,6 +39,7 @@ export interface ZeroExInstantProviderOptionalProps {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
 | 
					export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
 | 
				
			||||||
    private readonly _store: Store;
 | 
					    private readonly _store: Store;
 | 
				
			||||||
 | 
					    private _accountUpdateHeartbeat?: AccountUpdateHeartbeat;
 | 
				
			||||||
    // TODO(fragosti): Write tests for this beast once we inject a provider.
 | 
					    // TODO(fragosti): Write tests for this beast once we inject a provider.
 | 
				
			||||||
    private static _mergeDefaultStateWithProps(
 | 
					    private static _mergeDefaultStateWithProps(
 | 
				
			||||||
        props: ZeroExInstantProviderProps,
 | 
					        props: ZeroExInstantProviderProps,
 | 
				
			||||||
@@ -93,7 +96,10 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
 | 
				
			|||||||
            asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
 | 
					            asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // tslint:disable-next-line:no-floating-promises
 | 
					        // tslint:disable-next-line:no-floating-promises
 | 
				
			||||||
        asyncData.fetchAccountInfoAndDispatchToStore(this._store);
 | 
					        // asyncData.fetchAccountInfoAndDispatchToStore(this._store);
 | 
				
			||||||
 | 
					        this._accountUpdateHeartbeat = new AccountUpdateHeartbeat();
 | 
				
			||||||
 | 
					        this._accountUpdateHeartbeat.start(this._store, ACCOUNT_UPDATE_INTERVAL_TIME_MS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // warm up the gas price estimator cache just in case we can't
 | 
					        // warm up the gas price estimator cache just in case we can't
 | 
				
			||||||
        // grab the gas price estimate when submitting the transaction
 | 
					        // grab the gas price estimate when submitting the transaction
 | 
				
			||||||
        // tslint:disable-next-line:no-floating-promises
 | 
					        // tslint:disable-next-line:no-floating-promises
 | 
				
			||||||
@@ -101,6 +107,11 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
 | 
				
			|||||||
        // tslint:disable-next-line:no-floating-promises
 | 
					        // tslint:disable-next-line:no-floating-promises
 | 
				
			||||||
        this._flashErrorIfWrongNetwork();
 | 
					        this._flashErrorIfWrongNetwork();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    public componentWillUnmount(): void {
 | 
				
			||||||
 | 
					        if (this._accountUpdateHeartbeat) {
 | 
				
			||||||
 | 
					            this._accountUpdateHeartbeat.stop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    public render(): React.ReactNode {
 | 
					    public render(): React.ReactNode {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <ReduxProvider store={this._store}>
 | 
					            <ReduxProvider store={this._store}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 GWEI_IN_WEI = new BigNumber(1000000000);
 | 
				
			||||||
export const ONE_SECOND_MS = 1000;
 | 
					export const ONE_SECOND_MS = 1000;
 | 
				
			||||||
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
 | 
					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_GAS_PRICE = GWEI_IN_WEI.mul(6);
 | 
				
			||||||
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
 | 
					export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
 | 
				
			||||||
export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
 | 
					export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,10 +34,10 @@ export const asyncData = {
 | 
				
			|||||||
            store.dispatch(actions.setAvailableAssets([]));
 | 
					            store.dispatch(actions.setAvailableAssets([]));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    fetchAccountInfoAndDispatchToStore: async (store: Store) => {
 | 
					    fetchAccountInfoAndDispatchToStore: async (store: Store, options = { setLoading: true }) => {
 | 
				
			||||||
        const { providerState } = store.getState();
 | 
					        const { providerState } = store.getState();
 | 
				
			||||||
        const web3Wrapper = providerState.web3Wrapper;
 | 
					        const web3Wrapper = providerState.web3Wrapper;
 | 
				
			||||||
        if (providerState.account.state !== AccountState.Loading) {
 | 
					        if (options.setLoading && providerState.account.state !== AccountState.Loading) {
 | 
				
			||||||
            store.dispatch(actions.setAccountStateLoading());
 | 
					            store.dispatch(actions.setAccountStateLoading());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let availableAddresses: string[];
 | 
					        let availableAddresses: string[];
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								packages/instant/src/util/hearbeats.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								packages/instant/src/util/hearbeats.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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<void> {
 | 
				
			||||||
 | 
					        if (this._pendingRequest || _.isUndefined(this._store)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._pendingRequest = true;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            await asyncData.fetchAccountInfoAndDispatchToStore(this._store, { setLoading });
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            this._pendingRequest = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user