diff --git a/src/bridge/BridgeSyncContext.js b/src/bridge/BridgeSyncContext.js index 83f71842..dcba6613 100644 --- a/src/bridge/BridgeSyncContext.js +++ b/src/bridge/BridgeSyncContext.js @@ -6,6 +6,7 @@ import invariant from 'invariant' import logger from 'logger' import shuffle from 'lodash/shuffle' +import { timeout } from 'rxjs/operators/timeout' import React, { Component } from 'react' import priorityQueue from 'async/priorityQueue' import { connect } from 'react-redux' @@ -16,7 +17,12 @@ import { setAccountSyncState } from 'actions/bridgeSync' import { bridgeSyncSelector, syncStateLocalSelector } from 'reducers/bridgeSync' import type { BridgeSyncState } from 'reducers/bridgeSync' import { accountsSelector } from 'reducers/accounts' -import { SYNC_BOOT_DELAY, SYNC_ALL_INTERVAL, SYNC_MAX_CONCURRENT } from 'config/constants' +import { + SYNC_BOOT_DELAY, + SYNC_ALL_INTERVAL, + SYNC_MAX_CONCURRENT, + SYNC_TIMEOUT, +} from 'config/constants' import { getBridgeForCurrency } from '.' type BridgeSyncProviderProps = { @@ -73,19 +79,22 @@ class Provider extends Component { this.props.setAccountSyncState(accountId, { pending: true, error: null }) // TODO use Subscription to unsubscribe at relevant time - bridge.synchronize(account).subscribe({ - next: accountUpdater => { - this.props.updateAccountWithUpdater(accountId, accountUpdater) - }, - complete: () => { - this.props.setAccountSyncState(accountId, { pending: false, error: null }) - next() - }, - error: error => { - this.props.setAccountSyncState(accountId, { pending: false, error }) - next() - }, - }) + bridge + .synchronize(account) + .pipe(timeout(SYNC_TIMEOUT)) + .subscribe({ + next: accountUpdater => { + this.props.updateAccountWithUpdater(accountId, accountUpdater) + }, + complete: () => { + this.props.setAccountSyncState(accountId, { pending: false, error: null }) + next() + }, + error: error => { + this.props.setAccountSyncState(accountId, { pending: false, error }) + next() + }, + }) } const syncQueue = priorityQueue(synchronize, SYNC_MAX_CONCURRENT) diff --git a/src/components/Workflow/EnsureGenuine.js b/src/components/Workflow/EnsureGenuine.js index 831d60c8..42cb971d 100644 --- a/src/components/Workflow/EnsureGenuine.js +++ b/src/components/Workflow/EnsureGenuine.js @@ -1,7 +1,9 @@ // @flow +import { timeout } from 'rxjs/operators/timeout' import { PureComponent } from 'react' import isEqual from 'lodash/isEqual' +import { GENUINE_TIMEOUT } from 'config/constants' import type { Device } from 'types/common' import getIsGenuine from 'commands/getIsGenuine' @@ -60,6 +62,7 @@ class EnsureGenuine extends PureComponent { try { const res = await getIsGenuine .send({ devicePath: device.path, targetId: infos.targetId }) + .pipe(timeout(GENUINE_TIMEOUT)) .toPromise() if (this._unmounting) return const isGenuine = res === '0000' diff --git a/src/config/constants.js b/src/config/constants.js index 51a9637b..5e5f8b09 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -20,6 +20,8 @@ export const GET_CALLS_RETRY = intFromEnv('GET_CALLS_RETRY', 2) export const SYNC_MAX_CONCURRENT = intFromEnv('LEDGER_SYNC_MAX_CONCURRENT', 6) export const SYNC_BOOT_DELAY = 2 * 1000 export const SYNC_ALL_INTERVAL = 60 * 1000 +export const GENUINE_TIMEOUT = intFromEnv('GENUINE_TIMEOUT', 60 * 1000) +export const SYNC_TIMEOUT = intFromEnv('SYNC_TIMEOUT', 30 * 1000) export const CHECK_APP_INTERVAL_WHEN_INVALID = 600 export const CHECK_APP_INTERVAL_WHEN_VALID = 1200 diff --git a/static/i18n/en/errors.yml b/static/i18n/en/errors.yml index 8f853eb0..2d542878 100644 --- a/static/i18n/en/errors.yml +++ b/static/i18n/en/errors.yml @@ -3,6 +3,7 @@ RangeError: '{{message}}' Error: '{{message}}' LedgerAPIErrorWithMessage: '{{message}}' TransportStatusError: '{{message}}' +TimeoutError: 'Timeout reached' FeeEstimationFailed: 'fee estimation failed (status: {{status}})' NotEnoughBalance: 'Not enough balance' BtcUnmatchedApp: 'You must open application ‘{{currencyName}}’ on the device'