diff --git a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/handleJoinChannelResult.ts b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/handleJoinChannelResult.ts index 7b5fa7d04..add006c82 100644 --- a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/handleJoinChannelResult.ts +++ b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/handleJoinChannelResult.ts @@ -5,6 +5,7 @@ import { MessageType } from '../../../types/MessageType'; import { ChannelConfig } from '../../../types/ChannelConfig'; import { DEFAULT_SESSION_TIMEOUT_MS } from '../../../config'; import { ConnectionStatus } from '../../../types/ConnectionStatus'; +import { logger } from '../../../utils/logger'; export const handleJoinChannelResults = async ( instance: SocketService, @@ -15,16 +16,26 @@ export const handleJoinChannelResults = async ( const { channelId, isOriginator } = state; if (error === 'error_terminated') { + logger.SocketService( + `handleJoinChannelResults: Channel ${channelId} terminated`, + ); instance.emit(EventType.TERMINATE); return; } if (!result) { + logger.SocketService( + `handleJoinChannelResults: No result for channel ${channelId}`, + ); return; } const { persistence, walletKey } = result; + logger.SocketService( + `handleJoinChannelResults: Channel ${channelId} persistence=${persistence} walletKey=${walletKey}`, + ); + if (persistence) { instance.emit(EventType.CHANNEL_PERSISTENCE); instance.state.keyExchange?.setKeysExchanged(true); diff --git a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.test.ts b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.test.ts index 216d2512e..6f0d41b32 100644 --- a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.test.ts +++ b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.test.ts @@ -1,10 +1,13 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { SocketService } from '../../../SocketService'; import { EventType } from '../../../types/EventType'; import { MessageType } from '../../../types/MessageType'; import { logger } from '../../../utils/logger'; import { resume } from './resume'; +jest.mock('./handleJoinChannelResult', () => ({ + handleJoinChannelResults: jest.fn(), +})); + describe('resume', () => { let instance: SocketService; @@ -45,6 +48,7 @@ describe('resume', () => { }); it('should not connect socket if already connected', () => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion instance.state.socket!.connected = true; resume(instance); @@ -56,11 +60,15 @@ describe('resume', () => { resume(instance); expect(mockConnect).toHaveBeenCalled(); - expect(mockEmit).toHaveBeenCalledWith(EventType.JOIN_CHANNEL, { - channelId: 'sampleChannelId', - clientType: 'wallet', - context: 'someContext_resume', - }); + expect(mockEmit).toHaveBeenCalledWith( + EventType.JOIN_CHANNEL, + { + channelId: 'sampleChannelId', + clientType: 'wallet', + context: 'someContext_resume', + }, + expect.any(Function), + ); }); it('should send READY message if keys have been exchanged and not an originator', () => { diff --git a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.ts b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.ts index 2adde6e03..48504dbcd 100644 --- a/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.ts +++ b/packages/sdk-communication-layer/src/services/SocketService/ConnectionManager/resume.ts @@ -2,6 +2,7 @@ import { logger } from '../../../utils/logger'; import { SocketService } from '../../../SocketService'; import { EventType } from '../../../types/EventType'; import { MessageType } from '../../../types/MessageType'; +import { handleJoinChannelResults } from './handleJoinChannelResult'; /** * Resumes the connection of a SocketService instance. @@ -14,45 +15,64 @@ import { MessageType } from '../../../types/MessageType'; * @param instance The current instance of the SocketService. */ export function resume(instance: SocketService) { + const { state, remote } = instance; + const { socket, channelId, context, keyExchange, isOriginator } = state; + const { isOriginator: remoteIsOriginator } = remote.state; + logger.SocketService( - `[SocketService: resume()] context=${instance.state.context} connected=${ - instance.state.socket?.connected - } manualDisconnect=${instance.state.manualDisconnect} resumed=${ - instance.state.resumed - } keysExchanged=${instance.state.keyExchange?.areKeysExchanged()}`, + `[SocketService: resume()] context=${context} connected=${ + socket?.connected + } manualDisconnect=${state.manualDisconnect} resumed=${ + state.resumed + } keysExchanged=${keyExchange?.areKeysExchanged()}`, ); - if (instance.state.socket?.connected) { + if (socket?.connected) { logger.SocketService(`[SocketService: resume()] already connected.`); + socket.emit(MessageType.PING, { + id: channelId, + clientType: remoteIsOriginator ? 'dapp' : 'wallet', + context: 'on_channel_config', + message: '', + }); } else { - instance.state.socket?.connect(); + socket?.connect(); logger.SocketService( - `[SocketService: resume()] after connecting socket --> connected=${instance.state.socket?.connected}`, + `[SocketService: resume()] after connecting socket --> connected=${socket?.connected}`, ); - // Useful to re-emmit otherwise dapp might sometime loose track of the connection event. - instance.state.socket?.emit(EventType.JOIN_CHANNEL, { - channelId: instance.state.channelId, - context: `${instance.state.context}_resume`, - clientType: instance.remote.state.isOriginator ? 'dapp' : 'wallet', - }); + socket?.emit( + EventType.JOIN_CHANNEL, + { + channelId, + context: `${context}_resume`, + clientType: remoteIsOriginator ? 'dapp' : 'wallet', + }, + async ( + error: string | null, + result?: { ready: boolean; persistence?: boolean; walletKey?: string }, + ) => { + try { + await handleJoinChannelResults(instance, error, result); + } catch (runtimeError) { + console.warn(`Error reconnecting to channel`, runtimeError); + } + }, + ); } // Always try to recover key exchange from both side (wallet / dapp) - if (instance.state.keyExchange?.areKeysExchanged()) { - if (!instance.state.isOriginator) { - // this message will be ignored by the dapp if it has restarted and updated keys. - // Dapp will then init another key exchange. + if (keyExchange?.areKeysExchanged()) { + if (!isOriginator) { instance.sendMessage({ type: MessageType.READY }); } - } else if (!instance.state.isOriginator) { - // Ask to start key exchange - instance.state.keyExchange?.start({ - isOriginator: instance.state.isOriginator ?? false, + } else if (!isOriginator) { + keyExchange?.start({ + isOriginator: isOriginator ?? false, }); } - instance.state.manualDisconnect = false; - instance.state.resumed = true; + state.manualDisconnect = false; + state.resumed = true; } diff --git a/packages/sdk/src/provider/initializeMobileProvider.ts b/packages/sdk/src/provider/initializeMobileProvider.ts index 55434242f..5d80d65fa 100644 --- a/packages/sdk/src/provider/initializeMobileProvider.ts +++ b/packages/sdk/src/provider/initializeMobileProvider.ts @@ -390,11 +390,16 @@ const initializeMobileProvider = async ({ ); } - const rpcResponse = await executeRequest(...args); - logger( - `[initializeMobileProvider: sendRequest()] method=${method} rpcResponse: ${rpcResponse}`, - ); - return rpcResponse; + try { + const rpcResponse = await executeRequest(...args); + logger( + `[initializeMobileProvider: sendRequest()] method=${method} rpcResponse: ${rpcResponse}`, + ); + return rpcResponse; + } catch (error) { + console.error(`[initializeMobileProvider: sendRequest()] error:`, error); + throw error; + } }; // Wrap ethereum.request call to check if the user needs to install MetaMask