From faabd0cc8b06e32c19ddae3863f29f5b593008ab Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Wed, 13 Mar 2019 20:03:17 +0100 Subject: [PATCH] refactor: add ipcMainUtils.invokeInWebContents / ipcRendererUtils.handle helpers (#17313) --- lib/browser/api/web-contents.js | 3 ++- lib/browser/ipc-main-internal-utils.ts | 20 +++++++++++++++++++- lib/renderer/ipc-renderer-internal-utils.ts | 15 +++++++++++++++ lib/renderer/web-frame-init.ts | 7 ++++--- typings/internal-electron.d.ts | 4 ++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 6b46d39fa1e4..68fc455e3116 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -9,6 +9,7 @@ const { app, ipcMain, session, deprecate } = electron const NavigationController = require('@electron/internal/browser/navigation-controller') const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal') +const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils') const errorUtils = require('@electron/internal/common/error-utils') // session is not used here, the purpose is to make sure session is initalized @@ -193,7 +194,7 @@ const asyncWebFrameMethods = function (requestId, method, callback, ...args) { for (const method of webFrameMethods) { WebContents.prototype[method] = function (...args) { - this._sendInternal('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args) + ipcMainUtils.invokeInWebContents(this, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, ...args) } } diff --git a/lib/browser/ipc-main-internal-utils.ts b/lib/browser/ipc-main-internal-utils.ts index c019e62a50ad..716f268f5d60 100644 --- a/lib/browser/ipc-main-internal-utils.ts +++ b/lib/browser/ipc-main-internal-utils.ts @@ -1,7 +1,7 @@ import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal' import * as errorUtils from '@electron/internal/common/error-utils' -type IPCHandler = (...args: any[]) => any +type IPCHandler = (event: ElectronInternal.IpcMainInternalEvent, ...args: any[]) => any const callHandler = async function (handler: IPCHandler, event: ElectronInternal.IpcMainInternalEvent, args: any[], reply: (args: any[]) => void) { try { @@ -23,3 +23,21 @@ export const handle = function (channel: string, handler: }) }) } + +let nextId = 0 + +export function invokeInWebContents (sender: Electron.WebContentsInternal, command: string, ...args: any[]) { + return new Promise((resolve, reject) => { + const requestId = ++nextId + ipcMainInternal.once(`${command}_RESPONSE_${requestId}`, ( + _event, error: Electron.SerializedError, result: any + ) => { + if (error) { + reject(errorUtils.deserialize(error)) + } else { + resolve(result) + } + }) + sender._sendInternal(command, requestId, ...args) + }) +} diff --git a/lib/renderer/ipc-renderer-internal-utils.ts b/lib/renderer/ipc-renderer-internal-utils.ts index 36005e3896b3..711701ddfe5d 100644 --- a/lib/renderer/ipc-renderer-internal-utils.ts +++ b/lib/renderer/ipc-renderer-internal-utils.ts @@ -1,6 +1,21 @@ import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal' import * as errorUtils from '@electron/internal/common/error-utils' +type IPCHandler = (event: Electron.IpcRendererEvent, ...args: any[]) => any + +export const handle = function (channel: string, handler: T) { + ipcRendererInternal.on(channel, (event, requestId, ...args) => { + new Promise(resolve => resolve(handler(event, ...args)) + ).then(result => { + return [null, result] + }, error => { + return [errorUtils.serialize(error)] + }).then(responseArgs => { + event.sender.send(`${channel}_RESPONSE_${requestId}`, ...responseArgs) + }) + }) +} + let nextId = 0 export function invoke (command: string, ...args: any[]) { diff --git a/lib/renderer/web-frame-init.ts b/lib/renderer/web-frame-init.ts index 2af2dfd7a723..c9ddb8b0c7b1 100644 --- a/lib/renderer/web-frame-init.ts +++ b/lib/renderer/web-frame-init.ts @@ -1,5 +1,6 @@ import { webFrame, WebFrame } from 'electron' import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal' +import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils' import * as errorUtils from '@electron/internal/common/error-utils' // All keys of WebFrame that extend Function @@ -10,13 +11,13 @@ type WebFrameMethod = { export const webFrameInit = () => { // Call webFrame method - ipcRendererInternal.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', ( - _event, method: keyof WebFrameMethod, args: any[] + ipcRendererUtils.handle('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', ( + event, method: keyof WebFrameMethod, ...args: any[] ) => { // The TypeScript compiler cannot handle the sheer number of // call signatures here and simply gives up. Incorrect invocations // will be caught by "keyof WebFrameMethod" though. - (webFrame[method] as any)(...args) + return (webFrame[method] as any)(...args) }) ipcRendererInternal.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', ( diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 0e24770c2b70..b5557764785a 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -55,6 +55,10 @@ declare namespace Electron { sendToAll(webContentsId: number, channel: string, ...args: any[]): void } + interface WebContentsInternal extends Electron.WebContents { + _sendInternal(channel: string, ...args: any[]): void; + } + const deprecate: ElectronInternal.DeprecationUtil; }