Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/main/actions/setupIPCForwarding.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
import { ipcMain } from "electron";

export const setupIPCForwardingToBackground = (backgroundWindow) => {
let requestIdCounter = 0;

ipcMain.handle(
"forward-event-from-webapp-to-background-and-await-reply",
async (event, incomingData) => {
return new Promise((resolve) => {
const { actualPayload, eventName } = incomingData;
ipcMain.once(`reply-${eventName}`, (responseEvent, responsePayload) => {
resolve(responsePayload);
});
backgroundWindow.webContents.send(eventName, actualPayload);
// Doing this only for local_sync calls, rest calls are handled by the old code.
const isRPCCall = eventName && eventName.includes('local_sync');

if(isRPCCall) {
// Generate unique ID for this specific request to avoid reply channel collision
const requestId = `${eventName}-${Date.now()}-${++requestIdCounter}`;

// Each request gets its own unique reply channel
ipcMain.once(`reply-${eventName}-${requestId}`, (responseEvent, responsePayload) => {
resolve(responsePayload);
});

// Send requestId so background can reply on the correct channel
backgroundWindow.webContents.send(eventName, { requestId, args: actualPayload });
}
else{
ipcMain.once(`reply-${eventName}`, (responseEvent, responsePayload) => {
resolve(responsePayload);
});

backgroundWindow.webContents.send(eventName, actualPayload);
}
});
}
);
Expand Down
47 changes: 42 additions & 5 deletions src/renderer/lib/RPCServiceOverIPC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { ipcRenderer } from "electron";
* - Requires Arguments and Responses of those methods to be serializable. (limitation imposed by electron IPC)
* - Currently only allows one generic fire-and-forget event channel for the service to send events to the webapp -> relayed over "send-from-background-to-webapp" channel.
*/

/**
* Global registry to track registered channels and their handlers for HMR
* Maps channel name to handler function so we can remove old handlers during reload
* now keeping track of the channelName - handler attached to it
*/
const REGISTERED_CHANNELS = new Map<string, Function>();

export class RPCServiceOverIPC {
private RPC_CHANNEL_PREFIX: string;

Expand All @@ -28,8 +36,27 @@ export class RPCServiceOverIPC {
method: (..._args: any[]) => Promise<any>
) {
const channelName = `${this.RPC_CHANNEL_PREFIX}${exposedMethodName}`;
// console.log("DBG-1: exposing channel", channelName, Date.now());
ipcRenderer.on(channelName, async (_event, args) => {

// if channel is alrady registered, remove old listener first during HMR
if (REGISTERED_CHANNELS.has(channelName)) {
const oldHandler = REGISTERED_CHANNELS.get(channelName);
if (oldHandler) {
ipcRenderer.removeListener(channelName, oldHandler as any);
}
}

// Define the handler function so we can store reference for future removal
const handler = async (_event: any, payload: any) => {
// Support both old format (args only) and new format (with requestId)
let requestId: string | undefined;
let args: any;

if (payload && typeof payload === 'object' && 'requestId' in payload && 'args' in payload) {
requestId = payload.requestId;
args = payload.args;
} else {
args = payload;
}
// console.log(
// "DBG-1: received event on channel",
// channelName,
Expand All @@ -49,7 +76,9 @@ export class RPCServiceOverIPC {
// exposedMethodName,
// Date.now()
// );
ipcRenderer.send(`reply-${channelName}`, {

const replyChannel = requestId ? `reply-${channelName}-${requestId}` : `reply-${channelName}`;
ipcRenderer.send(replyChannel, {
success: true,
data: result,
});
Expand All @@ -59,12 +88,20 @@ export class RPCServiceOverIPC {
// error,
// Date.now()
// );
ipcRenderer.send(`reply-${channelName}`, {

const replyChannel = requestId ? `reply-${channelName}-${requestId}` : `reply-${channelName}`;
ipcRenderer.send(replyChannel, {
success: false,
data: error.message,
});
}
});
};

// Register the new handler
ipcRenderer.on(channelName, handler);

// Store handler reference for future removal during HMR
REGISTERED_CHANNELS.set(channelName, handler);
}

sendServiceEvent(event: any) {
Expand Down