Browse Source

Add more timeout on the sync to avoid issues

master
Gaëtan Renaudeau 7 years ago
parent
commit
3e71c48917
  1. 2
      src/config/constants.js
  2. 1
      src/config/errors.js
  3. 62
      src/helpers/libcore.js
  4. 18
      src/helpers/promise.js
  5. 4
      static/i18n/en/errors.json

2
src/config/constants.js

@ -46,7 +46,7 @@ export const SYNC_ALL_INTERVAL = 120 * 1000
export const SYNC_BOOT_DELAY = 2 * 1000
export const SYNC_PENDING_INTERVAL = 10 * 1000
export const SYNC_MAX_CONCURRENT = intFromEnv('LEDGER_SYNC_MAX_CONCURRENT', 1)
export const SYNC_TIMEOUT = intFromEnv('SYNC_TIMEOUT', 30 * 1000)
export const SYNC_TIMEOUT = intFromEnv('SYNC_TIMEOUT', 60 * 1000)
// Endpoints...

1
src/config/errors.js

@ -12,6 +12,7 @@ export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress')
export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount')
export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine')
export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose')
export const TimeoutTagged = createCustomErrorClass('TimeoutTagged')
// db stuff, no need to translate
export const NoDBPathGiven = createCustomErrorClass('NoDBPathGiven')

62
src/helpers/libcore.js

@ -16,6 +16,7 @@ import { isSegwitPath, isUnsplitPath } from 'helpers/bip32'
import * as accountIdHelper from 'helpers/accountId'
import { createCustomErrorClass, deserializeError } from './errors'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName'
import { timeoutTagged } from './promise'
const NoAddressesFound = createCustomErrorClass('NoAddressesFound')
@ -202,6 +203,7 @@ const coreSyncAccount = (core, account) =>
new Promise((resolve, reject) => {
const eventReceiver = createEventReceiver(core, e => {
const code = e.getCode()
logger.debug(`syncAccountEvent ${code}`, { type: 'libcore-sync' })
if (code === core.EVENT_CODE.UNDEFINED || code === core.EVENT_CODE.SYNCHRONIZATION_FAILED) {
const payload = e.getPayload()
const message = (
@ -270,7 +272,7 @@ async function scanNextAccount(props: {
const shouldSyncAccount = true // TODO: let's sync everytime. maybe in the future we can optimize.
if (shouldSyncAccount) {
await coreSyncAccount(core, njsAccount)
await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount))
}
if (isUnsubscribed()) return []
@ -325,10 +327,10 @@ async function getOrCreateWallet(
): NJSWallet {
const pool = core.getPoolInstance()
try {
const wallet = await pool.getWallet(WALLET_IDENTIFIER)
const wallet = await timeoutTagged('getWallet', 5000, pool.getWallet(WALLET_IDENTIFIER))
return wallet
} catch (err) {
const currency = await pool.getCurrency(currencyId)
const currency = await timeoutTagged('getCurrency', 5000, pool.getCurrency(currencyId))
const splitConfig = isUnsplit ? SPLITTED_CURRENCIES[currencyId] || null : null
const coinType = splitConfig ? splitConfig.coinType : '<coin_type>'
const walletConfig = isSegwit
@ -342,9 +344,11 @@ async function getOrCreateWallet(
}
: undefined
const njsWalletConfig = createWalletConfig(core, walletConfig)
const wallet = await core
.getPoolInstance()
.createWallet(WALLET_IDENTIFIER, currency, njsWalletConfig)
const wallet = await timeoutTagged(
'createWallet',
10000,
core.getPoolInstance().createWallet(WALLET_IDENTIFIER, currency, njsWalletConfig),
)
return wallet
}
}
@ -368,21 +372,33 @@ async function buildAccountRaw({
core: *,
ops: NJSOperation[],
}): Promise<AccountRaw> {
const njsBalance = await njsAccount.getBalance()
const njsBalance = await timeoutTagged('getBalance', 10000, njsAccount.getBalance())
const balance = njsBalance.toLong()
const jsCurrency = getCryptoCurrencyById(currencyId)
const { derivations } = await wallet.getAccountCreationInfo(accountIndex)
const { derivations } = await timeoutTagged(
'getAccountCreationInfo',
10000,
wallet.getAccountCreationInfo(accountIndex),
)
const [walletPath, accountPath] = derivations
// retrieve xpub
const xpub = njsAccount.getRestoreKey()
// blockHeight
const { height: blockHeight } = await njsAccount.getLastBlock()
const { height: blockHeight } = await timeoutTagged(
'getLastBlock',
30000,
njsAccount.getLastBlock(),
)
// get a bunch of fresh addresses
const rawAddresses = await njsAccount.getFreshPublicAddresses()
const rawAddresses = await timeoutTagged(
'getFreshPublicAddresses',
10000,
njsAccount.getFreshPublicAddresses(),
)
const addresses = rawAddresses.map(njsAddress => ({
str: njsAddress.toString(),
@ -500,7 +516,11 @@ export async function syncAccount({
const isUnsplit = isUnsplitPath(freshAddressPath, SPLITTED_CURRENCIES[currencyId])
let njsWallet
try {
njsWallet = await core.getPoolInstance().getWallet(decodedAccountId.walletName)
njsWallet = await timeoutTagged(
'getWallet',
10000,
core.getPoolInstance().getWallet(decodedAccountId.walletName),
)
} catch (e) {
logger.warn(`Have to reimport the account... (${e})`)
njsWallet = await getOrCreateWallet(
@ -514,20 +534,28 @@ export async function syncAccount({
let njsAccount
try {
njsAccount = await njsWallet.getAccount(index)
njsAccount = await timeoutTagged('getAccount', 10000, njsWallet.getAccount(index))
} catch (e) {
logger.warn(`Have to recreate the account... (${e.message})`)
const extendedInfos = await njsWallet.getExtendedKeyAccountCreationInfo(index)
const extendedInfos = await timeoutTagged(
'getEKACI',
10000,
njsWallet.getExtendedKeyAccountCreationInfo(index),
)
extendedInfos.extendedKeys.push(decodedAccountId.xpub)
njsAccount = await njsWallet.newAccountWithExtendedKeyInfo(extendedInfos)
njsAccount = await timeoutTagged(
'newAWEKI',
10000,
njsWallet.newAccountWithExtendedKeyInfo(extendedInfos),
)
}
const unsub = await coreSyncAccount(core, njsAccount)
const unsub = await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount))
unsub()
const query = njsAccount.queryOperations()
const ops = await query.complete().execute()
const njsBalance = await njsAccount.getBalance()
const ops = await timeoutTagged('ops', 30000, query.complete().execute())
const njsBalance = await timeoutTagged('getBalance', 10000, njsAccount.getBalance())
const syncedRawAccount = await buildAccountRaw({
njsAccount,

18
src/helpers/promise.js

@ -2,6 +2,7 @@
// small utilities for Promises
import logger from 'logger'
import { TimeoutTagged } from 'config/errors'
export const delay = (ms: number): Promise<void> => new Promise(f => setTimeout(f, ms))
@ -65,6 +66,23 @@ export function createCancelablePolling(
return { unsubscribe, promise }
}
export const timeoutTagged = <T>(tag: string, delay: number, promise: Promise<T>): Promise<T> =>
new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new TimeoutTagged('timeout', { tag }))
}, delay)
promise.then(
r => {
clearTimeout(timeout)
resolve(r)
},
e => {
clearTimeout(timeout)
reject(e)
},
)
})
export const promisify = (fn: any) => (...args: any) =>
new Promise((resolve, reject) =>
fn(...args, (err: Error, res: any) => {

4
static/i18n/en/errors.json

@ -115,6 +115,10 @@
"title": "Oops, a time out occurred",
"description": "It took too long for the server to respond."
},
"TimeoutTagged": {
"title": "Oops, a time out occurred ({{tag}})",
"description": "It took too long for the server to respond."
},
"TransportError": {
"title": "Something went wrong. Please reconnect your device.",
"description": "{{message}}"

Loading…
Cancel
Save