auto reconnect to the backend

pull/527/head
slowbackspace 5 years ago
parent f8e7320bf2
commit 8d399ff327

@ -1,6 +1,7 @@
/* @flow */
import * as BLOCKCHAIN from 'actions/constants/blockchain';
import * as DiscoveryActions from 'actions/DiscoveryActions';
import * as EthereumBlockchainActions from 'actions/ethereum/BlockchainActions';
import * as RippleBlockchainActions from 'actions/ripple/BlockchainActions';
@ -19,6 +20,10 @@ export type BlockchainAction =
| {
type: typeof BLOCKCHAIN.START_SUBSCRIBE,
shortcut: string,
}
| {
type: typeof BLOCKCHAIN.FAIL_SUBSCRIBE,
shortcut: string,
};
// Conditionally subscribe to blockchain backend
@ -128,6 +133,8 @@ export const onError = (
const network = config.networks.find(c => c.shortcut === shortcut);
if (!network) return;
dispatch(autoReconnect(shortcut));
switch (network.type) {
case 'ethereum':
await dispatch(EthereumBlockchainActions.onError(shortcut));
@ -140,3 +147,28 @@ export const onError = (
break;
}
};
const autoReconnect = (shortcut: string): PromiseAction<void> => async (
dispatch: Dispatch,
getState: GetState
): Promise<void> => {
const MAX_ATTEMPTS = 4;
let blockchain = getState().blockchain.find(b => b.shortcut === shortcut);
// try to automatically reconnect and wait after each attemp (5s * #attempt) untill max number of attemps is reached
for (let i = 0; i < MAX_ATTEMPTS; i++) {
const waitTime = 5000 * (i + 1); /// 5s * #attempt
if (!blockchain || blockchain.connected) {
break;
}
blockchain = getState().blockchain.find(b => b.shortcut === shortcut);
// reconnect with 7s timeout
// eslint-disable-next-line no-await-in-loop
await dispatch(DiscoveryActions.reconnect(shortcut, 7000));
// wait before next try
// eslint-disable-next-line no-await-in-loop
await new Promise(resolve => setTimeout(resolve, waitTime));
}
};

@ -1,6 +1,7 @@
/* @flow */
import TrezorConnect, { UI } from 'trezor-connect';
import * as BLOCKCHAIN_ACTION from 'actions/constants/blockchain';
import * as DISCOVERY from 'actions/constants/discovery';
import * as ACCOUNT from 'actions/constants/account';
import * as NOTIFICATION from 'actions/constants/notification';
@ -325,11 +326,27 @@ const finish = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction
});
};
export const reconnect = (network: string): PromiseAction<void> => async (
export const reconnect = (network: string, timeout: number = 30): PromiseAction<void> => async (
dispatch: Dispatch
): Promise<void> => {
await dispatch(BlockchainActions.subscribe(network));
dispatch(restore());
// Runs two promises.
// First promise is a subscribe action which will never resolve in case of completely lost connection to the backend
// That's why there is a second promise that rejects after the specified timeout.
return Promise.race([
dispatch(BlockchainActions.subscribe(network)),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)),
])
.catch(() => {
// catch error from first promises that rejects (most likely timeout)
dispatch({
type: BLOCKCHAIN_ACTION.FAIL_SUBSCRIBE,
shortcut: network,
});
})
.then(() => {
// dispatch restore when subscribe promise resolves
dispatch(restore());
});
};
// Called after DEVICE.CONNECT ('trezor-connect') or CONNECT.AUTH_DEVICE actions in WalletService

@ -1,5 +1,6 @@
/* @flow */
export const START_SUBSCRIBE: 'blockchain__start_subscribe' = 'blockchain__start_subscribe';
export const FAIL_SUBSCRIBE: 'blockchain__fail_subscribe' = 'blockchain__fail_subscribe';
export const READY: 'blockchain__ready' = 'blockchain__ready';
export const UPDATE_FEE: 'blockchain__update_fee' = 'blockchain__update_fee';

@ -48,6 +48,30 @@ const onStartSubscribe = (state: State, shortcut: string): State => {
]);
};
const onFailSubscribe = (state: State, shortcut: string): State => {
const network = state.find(b => b.shortcut === shortcut);
if (network) {
const others = state.filter(b => b !== network);
return others.concat([
{
...network,
connecting: false,
},
]);
}
return state.concat([
{
shortcut,
connected: false,
connecting: false,
block: 0,
feeTimestamp: 0,
feeLevels: [],
},
]);
};
const onConnect = (state: State, action: BlockchainConnect): State => {
const shortcut = action.payload.coin.shortcut.toLowerCase();
const network = state.find(b => b.shortcut === shortcut);
@ -136,6 +160,8 @@ export default (state: State = initialState, action: Action): State => {
switch (action.type) {
case BLOCKCHAIN_ACTION.START_SUBSCRIBE:
return onStartSubscribe(state, action.shortcut);
case BLOCKCHAIN_ACTION.FAIL_SUBSCRIBE:
return onFailSubscribe(state, action.shortcut);
case BLOCKCHAIN_EVENT.CONNECT:
return onConnect(state, action);
case BLOCKCHAIN_EVENT.ERROR:

Loading…
Cancel
Save