implement recursive connection retry to add more robust internet error handling
This commit is contained in:
@@ -254,7 +254,9 @@ export default function ClaimGiftScreen({
|
||||
}
|
||||
|
||||
if (!initResult) {
|
||||
initResult = await initializeSparkWallet(giftSeed);
|
||||
initResult = await initializeSparkWallet(giftSeed, false, {
|
||||
maxRetries: 4,
|
||||
});
|
||||
}
|
||||
|
||||
if (!initResult) {
|
||||
|
||||
+3
-1
@@ -69,7 +69,9 @@ export default function SelectAltAccountHalfModal(props) {
|
||||
});
|
||||
|
||||
await new Promise(res => setTimeout(res, 800));
|
||||
await initializeSparkWallet(account.mnemoinc);
|
||||
await initializeSparkWallet(account.mnemoinc, false, {
|
||||
maxRetries: 4,
|
||||
});
|
||||
let balance = 0;
|
||||
if (transferType === 'from') {
|
||||
const balanceResponse = await getSparkBalance(account.mnemoinc);
|
||||
|
||||
@@ -25,25 +25,7 @@ export async function initWallet({
|
||||
}) {
|
||||
try {
|
||||
crashlyticsLogReport('Trying to connect to nodes');
|
||||
const [
|
||||
didConnectToSpark,
|
||||
// balance
|
||||
] = await Promise.all([
|
||||
initializeSparkWallet(mnemonic),
|
||||
// handleBalanceCache({
|
||||
// isCheck: false,
|
||||
// mnemonic: mnemonic,
|
||||
// returnBalanceOnly: true,
|
||||
// }),
|
||||
]);
|
||||
|
||||
// if (balance) {
|
||||
// setSparkInformation(prev => ({
|
||||
// ...prev,
|
||||
// didConnect: true,
|
||||
// balance: balance,
|
||||
// }));
|
||||
// }
|
||||
const didConnectToSpark = await initializeSparkWallet(mnemonic);
|
||||
|
||||
if (didConnectToSpark.isConnected) {
|
||||
crashlyticsLogReport('Loading node balances for session');
|
||||
|
||||
@@ -118,47 +118,93 @@ export const clearMnemonicCache = () => {
|
||||
Object.keys(sparkWallet).forEach(key => delete sparkWallet[key]);
|
||||
};
|
||||
|
||||
export const initializeSparkWallet = async (mnemonic, isInitialLoad = true) => {
|
||||
try {
|
||||
const runtime = await selectSparkRuntime(mnemonic, isInitialLoad);
|
||||
export const initializeSparkWallet = async (
|
||||
mnemonic,
|
||||
isInitialLoad = true,
|
||||
options = {},
|
||||
) => {
|
||||
const {
|
||||
maxRetries = 8,
|
||||
retryDelay = 15000, // 15 seconds between retries
|
||||
enableRetry = true,
|
||||
} = options;
|
||||
|
||||
if (runtime === 'webview') {
|
||||
// Use WebView to initialize wallet
|
||||
const response = await sendWebViewRequestGlobal(
|
||||
OPERATION_TYPES.initWallet,
|
||||
{
|
||||
mnemonic,
|
||||
},
|
||||
const attemptInitialization = async (attemptNumber = 0) => {
|
||||
try {
|
||||
const runtime = await selectSparkRuntime(mnemonic, isInitialLoad);
|
||||
|
||||
if (runtime === 'webview') {
|
||||
// Use WebView to initialize wallet
|
||||
const response = await sendWebViewRequestGlobal(
|
||||
OPERATION_TYPES.initWallet,
|
||||
{
|
||||
mnemonic,
|
||||
},
|
||||
);
|
||||
|
||||
if (response?.isConnected) return response;
|
||||
}
|
||||
|
||||
const hash = getMnemonicHash(mnemonic);
|
||||
|
||||
// Early return if already initialized
|
||||
if (sparkWallet[hash]) {
|
||||
return { isConnected: true };
|
||||
}
|
||||
if (initializingWallets[hash]) {
|
||||
await initializingWallets[hash];
|
||||
return { isConnected: true };
|
||||
}
|
||||
initializingWallets[hash] = (async () => {
|
||||
try {
|
||||
const wallet = await initializeWallet(mnemonic);
|
||||
sparkWallet[hash] = wallet;
|
||||
return wallet;
|
||||
} catch (err) {
|
||||
delete initializingWallets[hash]; // cleanup after done
|
||||
delete sparkWallet[hash];
|
||||
throw err;
|
||||
}
|
||||
})();
|
||||
|
||||
await initializingWallets[hash];
|
||||
delete initializingWallets[hash];
|
||||
setForceReactNative(true);
|
||||
|
||||
return { isConnected: true };
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Initialize spark wallet error (attempt ${attemptNumber + 1}/${
|
||||
maxRetries + 1
|
||||
}):`,
|
||||
err,
|
||||
);
|
||||
|
||||
if (response?.isConnected) return response;
|
||||
const hash = getMnemonicHash(mnemonic);
|
||||
delete initializingWallets[hash];
|
||||
delete sparkWallet[hash];
|
||||
|
||||
// If retry is disabled or max retries reached, return error
|
||||
if (!enableRetry || attemptNumber >= maxRetries) {
|
||||
return { isConnected: false, error: err.message };
|
||||
}
|
||||
|
||||
// Log retry attempt
|
||||
console.log(
|
||||
`Wallet failed to connect. Retrying in ${
|
||||
retryDelay / 1000
|
||||
} seconds... (${attemptNumber + 1}/${maxRetries} retries)`,
|
||||
);
|
||||
|
||||
// Wait before retry
|
||||
await new Promise(res => setTimeout(res, retryDelay));
|
||||
|
||||
// Recursive retry
|
||||
return attemptInitialization(attemptNumber + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const hash = getMnemonicHash(mnemonic);
|
||||
|
||||
// Early return if already initialized
|
||||
if (sparkWallet[hash]) {
|
||||
return { isConnected: true };
|
||||
}
|
||||
if (initializingWallets[hash]) {
|
||||
await initializingWallets[hash];
|
||||
return { isConnected: true };
|
||||
}
|
||||
initializingWallets[hash] = (async () => {
|
||||
const wallet = await initializeWallet(mnemonic);
|
||||
sparkWallet[hash] = wallet;
|
||||
|
||||
delete initializingWallets[hash]; // cleanup after done
|
||||
})();
|
||||
|
||||
await initializingWallets[hash];
|
||||
setForceReactNative(true);
|
||||
|
||||
return { isConnected: true };
|
||||
} catch (err) {
|
||||
console.log('Initialize spark wallet error:', err);
|
||||
return { isConnected: false, error: err.message };
|
||||
}
|
||||
return attemptInitialization(0);
|
||||
};
|
||||
|
||||
const initializeWallet = async mnemonic => {
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
incomingSparkTransaction,
|
||||
OPERATION_TYPES,
|
||||
sendWebViewRequestGlobal,
|
||||
setForceReactNative,
|
||||
useWebView,
|
||||
} from './webViewContext';
|
||||
import { useGlobalContextProvider } from './context';
|
||||
@@ -1624,6 +1625,7 @@ const SparkWalletProvider = ({ children }) => {
|
||||
setDidRunNormalConnection(true);
|
||||
// lastConnectedTimeRef.current = Date.now();
|
||||
if (!didWork) {
|
||||
setForceReactNative(true);
|
||||
setSparkInformation(prev => ({ ...prev, didConnect: false }));
|
||||
setSparkConnectionError(error);
|
||||
console.log('Error connecting to spark wallet:', error);
|
||||
|
||||
@@ -704,7 +704,11 @@ export const WebViewProvider = ({ children }) => {
|
||||
}
|
||||
|
||||
// Reject importent messages if app is not connected to the internet
|
||||
if (!internetConnectionRef.current && action !== 'handshake:init') {
|
||||
if (
|
||||
!internetConnectionRef.current &&
|
||||
action !== 'handshake:init' &&
|
||||
action !== 'initializeSparkWallet'
|
||||
) {
|
||||
console.log(
|
||||
'App is not connected to the internet, queueing message:',
|
||||
action,
|
||||
@@ -866,11 +870,11 @@ export const WebViewProvider = ({ children }) => {
|
||||
result,
|
||||
);
|
||||
|
||||
forceReactNativeUse = true;
|
||||
setChangeSparkConnectionState(prev => ({
|
||||
state: true,
|
||||
count: prev.count + 1,
|
||||
}));
|
||||
// forceReactNativeUse = true;
|
||||
// setChangeSparkConnectionState(prev => ({
|
||||
// state: true,
|
||||
// count: prev.count + 1,
|
||||
// }));
|
||||
|
||||
queuedRequests.current.forEach(({ reject }) => {
|
||||
reject({
|
||||
@@ -1091,7 +1095,7 @@ export const WebViewProvider = ({ children }) => {
|
||||
if (!response?.isConnected) throw new Error('Wallet init failed');
|
||||
} catch (err) {
|
||||
console.log('Error re-initializing wallet:', err);
|
||||
forceReactNativeUse = true;
|
||||
// forceReactNativeUse = true;
|
||||
// Reject all queued requests since WebView is now unusable
|
||||
queuedRequests.current.forEach(({ reject }) => {
|
||||
reject({
|
||||
|
||||
Reference in New Issue
Block a user