From 4c5e396132c9ade24dfbd07f5a34fe39aca5f4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Tue, 13 May 2025 14:16:33 +0200 Subject: [PATCH] Improve Autofill IPC reliability (#14358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Delay IPC server start * Better ipc handling * Rename ready() to listenerReady() --------- Co-authored-by: Daniel García --- apps/desktop/src/autofill/preload.ts | 2 + .../services/desktop-autofill.service.ts | 2 + .../main/autofill/native-autofill.main.ts | 56 +++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/autofill/preload.ts b/apps/desktop/src/autofill/preload.ts index 537a4fdaf4e..13025971820 100644 --- a/apps/desktop/src/autofill/preload.ts +++ b/apps/desktop/src/autofill/preload.ts @@ -9,6 +9,8 @@ export default { runCommand: (params: RunCommandParams): Promise> => ipcRenderer.invoke("autofill.runCommand", params), + listenerReady: () => ipcRenderer.send("autofill.listenerReady"), + listenPasskeyRegistration: ( fn: ( clientId: number, diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index 3b1f7d3605f..464d60eecfd 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -296,6 +296,8 @@ export class DesktopAutofillService implements OnDestroy { await this.adHocSync(); } }); + + ipc.autofill.listenerReady(); } private convertRegistrationRequest( diff --git a/apps/desktop/src/platform/main/autofill/native-autofill.main.ts b/apps/desktop/src/platform/main/autofill/native-autofill.main.ts index ae901d75c1d..d14efefa81f 100644 --- a/apps/desktop/src/platform/main/autofill/native-autofill.main.ts +++ b/apps/desktop/src/platform/main/autofill/native-autofill.main.ts @@ -7,6 +7,11 @@ import { WindowMain } from "../../../main/window.main"; import { CommandDefinition } from "./command"; +type BufferedMessage = { + channel: string; + data: any; +}; + export type RunCommandParams = { namespace: C["namespace"]; command: C["name"]; @@ -17,12 +22,46 @@ export type RunCommandResult = C["output"]; export class NativeAutofillMain { private ipcServer: autofill.IpcServer | null; + private messageBuffer: BufferedMessage[] = []; + private listenerReady = false; constructor( private logService: LogService, private windowMain: WindowMain, ) {} + /** + * Safely sends a message to the renderer, buffering it if the server isn't ready yet + */ + private safeSend(channel: string, data: any) { + if (this.listenerReady && this.windowMain.win?.webContents) { + this.windowMain.win.webContents.send(channel, data); + } else { + this.logService.info( + `Buffering message to ${channel} until server is ready. Call .listenerReady() to flush.`, + ); + this.messageBuffer.push({ channel, data }); + } + } + + /** + * Flushes all buffered messages to the renderer + */ + private flushMessageBuffer() { + if (!this.windowMain.win?.webContents) { + this.logService.error("Cannot flush message buffer - window not available"); + return; + } + + this.logService.info(`Flushing ${this.messageBuffer.length} buffered messages`); + + for (const { channel, data } of this.messageBuffer) { + this.windowMain.win.webContents.send(channel, data); + } + + this.messageBuffer = []; + } + async init() { ipcMain.handle( "autofill.runCommand", @@ -43,7 +82,7 @@ export class NativeAutofillMain { this.ipcServer.completeError(clientId, sequenceNumber, String(error)); return; } - this.windowMain.win.webContents.send("autofill.passkeyRegistration", { + this.safeSend("autofill.passkeyRegistration", { clientId, sequenceNumber, request, @@ -56,7 +95,7 @@ export class NativeAutofillMain { this.ipcServer.completeError(clientId, sequenceNumber, String(error)); return; } - this.windowMain.win.webContents.send("autofill.passkeyAssertion", { + this.safeSend("autofill.passkeyAssertion", { clientId, sequenceNumber, request, @@ -69,7 +108,7 @@ export class NativeAutofillMain { this.ipcServer.completeError(clientId, sequenceNumber, String(error)); return; } - this.windowMain.win.webContents.send("autofill.passkeyAssertionWithoutUserInterface", { + this.safeSend("autofill.passkeyAssertionWithoutUserInterface", { clientId, sequenceNumber, request, @@ -82,8 +121,7 @@ export class NativeAutofillMain { this.ipcServer.completeError(clientId, sequenceNumber, String(error)); return; } - this.logService.info("Received native status", status); - this.windowMain.win.webContents.send("autofill.nativeStatus", { + this.safeSend("autofill.nativeStatus", { clientId, sequenceNumber, status, @@ -91,6 +129,14 @@ export class NativeAutofillMain { }, ); + ipcMain.on("autofill.listenerReady", async () => { + this.listenerReady = true; + this.logService.info( + `Listener is ready, flushing ${this.messageBuffer.length} buffered messages`, + ); + this.flushMessageBuffer(); + }); + ipcMain.on("autofill.completePasskeyRegistration", (event, data) => { this.logService.warning("autofill.completePasskeyRegistration", data); const { clientId, sequenceNumber, response } = data;