From 9106e6499784af9444ee1c08287a5c957fd49ea5 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Fri, 26 Aug 2022 17:37:56 +0800 Subject: [PATCH 1/9] feat: capture Electron IPC messages for opensumi devtools --- .../browser-preload/index.js | 57 +++++++++++++++++++ .../src/bootstrap/devtools.ts | 33 +++++++++++ .../src/bootstrap/window.ts | 5 ++ 3 files changed, 95 insertions(+) create mode 100644 packages/core-electron-main/src/bootstrap/devtools.ts diff --git a/packages/core-electron-main/browser-preload/index.js b/packages/core-electron-main/browser-preload/index.js index 8557797077..1386b3147b 100644 --- a/packages/core-electron-main/browser-preload/index.js +++ b/packages/core-electron-main/browser-preload/index.js @@ -3,6 +3,63 @@ const os = require('os'); const { ipcRenderer } = require('electron'); +const initForDevtools = () => { + const getCapturer = () => { + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureIpc) { + return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureIpc; + } + return; + }; + + const capture = (message) => { + const capturer = getCapturer(); + if (capturer !== undefined) { + capturer(message); + } + }; + + // ipcRenderer.on + const originalIpcRendererOn = ipcRenderer.on; + ipcRenderer.on = (channel, handler) => { + const proxyHandler = (event, ...args) => { + if (channel !== 'main->browser') { + capture({ ipcMethod: 'ipcRenderer.on', channel, args }); + } + handler(event, ...args); + }; + return originalIpcRendererOn.call(ipcRenderer, channel, proxyHandler); + }; + + // ipcRenderer.send + const originalIpcRendererSend = ipcRenderer.send; + ipcRenderer.send = (channel, ...args) => { + capture({ ipcMethod: 'ipcRenderer.send', channel, args }); + return originalIpcRendererSend.call(ipcRenderer, channel, ...args); + }; + + // ipcRenderer.sendSync + const originalIpcRendererSendSync = ipcRenderer.sendSync; + ipcRenderer.sendSync = (channel, ...args) => { + capture({ ipcMethod: 'ipcRenderer.sendSync', channel, args }); + return originalIpcRendererSendSync.call(ipcRenderer, channel, ...args); + }; + + // ipcRenderer.invoke + const originalIpcRendererInvoke = ipcRenderer.invoke; + ipcRenderer.invoke = (channel, ...args) => { + capture({ ipcMethod: 'ipcRenderer.invoke', channel, args }); + return originalIpcRendererInvoke.call(ipcRenderer, channel, ...args); + }; + + // receive messages that transfered from main process and capture them + ipcRenderer.on('main->browser', (event, message) => { + capture(message); + }); +}; + +// initialize for OpenSumi DevTools +initForDevtools(); + const electronEnv = {}; const urlParams = new URLSearchParams(decodeURIComponent(window.location.search)); diff --git a/packages/core-electron-main/src/bootstrap/devtools.ts b/packages/core-electron-main/src/bootstrap/devtools.ts new file mode 100644 index 0000000000..0028290d0d --- /dev/null +++ b/packages/core-electron-main/src/bootstrap/devtools.ts @@ -0,0 +1,33 @@ +import { ipcMain, BrowserWindow } from 'electron'; + +export const initForDevtools = (mainWindow: BrowserWindow) => { + // `mainWindow.webContents.send` is used to transfer messages to main window + // wherer ipcRenderer.on('main->browser', xxx) is set to receive the messages + // then put them to window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.ipcMessages + + // ipcMain.on + const originalIpcMainOn = ipcMain.on; + ipcMain.on = (channel: any, handler: any) => { + const proxyHandler = (event: any, ...args: any) => { + mainWindow.webContents.send('main->browser', { ipcMethod: 'ipcMain.on', channel, args }); + handler(event, ...args); + // TODO event.returnValue会作为ipcRenderer.sendSync的response, 可捕获 + }; + return originalIpcMainOn.call(ipcMain, channel, proxyHandler); + }; + + // ipcMain.handle + const originalIpcMainHandle = ipcMain.handle; + ipcMain.handle = (channel: any, handler: any) => { + const proxyHandler = (event: any, ...args: any) => { + mainWindow.webContents.send('main->browser', { ipcMethod: 'ipcMain.handle', channel, args }); + handler(event, ...args); + // TODO ipcMain.handle的返回值会作为ipcRenderer.invoke的response, 可捕获 + }; + return originalIpcMainHandle.call(ipcMain, channel, proxyHandler); + }; + + // TODO BrowserWindow.webContents.send + // 这是main进程向renderer进程发送消息的方式, 但BrowserWindow可以是任何实例, + // 所以我不知道怎么处理. 如果可以实现, 注意判断channel是否为'main->browser' +}; diff --git a/packages/core-electron-main/src/bootstrap/window.ts b/packages/core-electron-main/src/bootstrap/window.ts index 05b7308114..13ebb72d20 100644 --- a/packages/core-electron-main/src/bootstrap/window.ts +++ b/packages/core-electron-main/src/bootstrap/window.ts @@ -25,6 +25,7 @@ import { } from '@opensumi/ide-core-common'; import { normalizedIpcHandlerPathAsync } from '@opensumi/ide-core-common/lib/utils/ipc'; +import { initForDevtools } from './devtools'; import { ElectronAppConfig, ICodeWindow, ICodeWindowOptions } from './types'; const DEFAULT_WINDOW_HEIGHT = 700; @@ -94,6 +95,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { ...this.appConfig.overrideBrowserOptions, ...options, }); + + // initialize for OpenSumi DevTools + initForDevtools(this.browser); + if (options) { if (options.extensionDir) { this.extensionDir = options.extensionDir; From 9a2e7f878454aa99d1270b8e9c54f704857427a2 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 27 Aug 2022 13:57:30 +0800 Subject: [PATCH 2/9] refactor: rename rpc capture function --- .../addons/src/browser/chrome-devtools.contribution.ts | 4 ++-- packages/connection/src/common/utils.ts | 4 ++-- tools/electron/src/main/index.ts | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/addons/src/browser/chrome-devtools.contribution.ts b/packages/addons/src/browser/chrome-devtools.contribution.ts index fb43193bea..47c328592f 100644 --- a/packages/addons/src/browser/chrome-devtools.contribution.ts +++ b/packages/addons/src/browser/chrome-devtools.contribution.ts @@ -39,7 +39,7 @@ export class ChromeDevtoolsContribution implements ClientAppContribution { }); // if opensumi devtools has started capturing before this contribution point is registered - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.capture) { + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRpc) { if (!this.interval) { this.startRTTInterval(); } @@ -52,7 +52,7 @@ export class ChromeDevtoolsContribution implements ClientAppContribution { await this.rttService.measure(); const rtt = Date.now() - start; // "if" below is to prevent setting latency after stoping capturing - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.capture) { + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRpc) { window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.latency = rtt; } }, ChromeDevtoolsContribution.INTERVAL); diff --git a/packages/connection/src/common/utils.ts b/packages/connection/src/common/utils.ts index 321715628e..987b2823ed 100644 --- a/packages/connection/src/common/utils.ts +++ b/packages/connection/src/common/utils.ts @@ -37,8 +37,8 @@ export function parse(input: string, reviver?: (this: any, key: string, value: a } export function getCapturer() { - if (typeof window !== 'undefined' && window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.capture) { - return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.capture; + if (typeof window !== 'undefined' && window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRpc) { + return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRpc; } return; } diff --git a/tools/electron/src/main/index.ts b/tools/electron/src/main/index.ts index 537f95710f..77eb06ae89 100644 --- a/tools/electron/src/main/index.ts +++ b/tools/electron/src/main/index.ts @@ -1,6 +1,6 @@ import { join } from 'path'; -import { app } from 'electron'; +import { app, session } from 'electron'; import { URI } from '@opensumi/ide-core-common'; import { ElectronMainApp } from '@opensumi/ide-core-electron-main'; @@ -15,7 +15,7 @@ const getExtensionDir = () => { }; const electronApp = new ElectronMainApp({ - browserNodeIntegrated: false, + browserNodeIntegrated: true, browserUrl: URI.file(join(__dirname, '../browser/index.html')).toString(), modules: [WebviewElectronMainModule], nodeEntry: join(__dirname, '../node/index.js'), @@ -31,4 +31,7 @@ const electronApp = new ElectronMainApp({ electronApp.init().then(() => { electronApp.loadWorkspace(); + + const opensumicrxPath = join(require('os').homedir(), 'Projects/ASOC2022/opensumi/opensumi-devtools/build'); + session.defaultSession.loadExtension(opensumicrxPath); }); From a18d3e8f4f123b29dca0e49b4b219143e235b893 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 27 Aug 2022 15:13:05 +0800 Subject: [PATCH 3/9] chore: restore tools/electron/src/main/index.ts --- tools/electron/src/main/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/electron/src/main/index.ts b/tools/electron/src/main/index.ts index 77eb06ae89..537f95710f 100644 --- a/tools/electron/src/main/index.ts +++ b/tools/electron/src/main/index.ts @@ -1,6 +1,6 @@ import { join } from 'path'; -import { app, session } from 'electron'; +import { app } from 'electron'; import { URI } from '@opensumi/ide-core-common'; import { ElectronMainApp } from '@opensumi/ide-core-electron-main'; @@ -15,7 +15,7 @@ const getExtensionDir = () => { }; const electronApp = new ElectronMainApp({ - browserNodeIntegrated: true, + browserNodeIntegrated: false, browserUrl: URI.file(join(__dirname, '../browser/index.html')).toString(), modules: [WebviewElectronMainModule], nodeEntry: join(__dirname, '../node/index.js'), @@ -31,7 +31,4 @@ const electronApp = new ElectronMainApp({ electronApp.init().then(() => { electronApp.loadWorkspace(); - - const opensumicrxPath = join(require('os').homedir(), 'Projects/ASOC2022/opensumi/opensumi-devtools/build'); - session.defaultSession.loadExtension(opensumicrxPath); }); From 82e764e6b67b9f1b94a4b9073317e44a02ee55b1 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sun, 11 Sep 2022 13:40:33 +0800 Subject: [PATCH 4/9] refactor: use capitalized RPC/IPC rather Ipc/Rpc in variable names --- packages/addons/src/browser/chrome-devtools.contribution.ts | 4 ++-- packages/connection/src/common/utils.ts | 4 ++-- packages/core-electron-main/browser-preload/index.js | 4 ++-- packages/core-electron-main/src/bootstrap/devtools.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/addons/src/browser/chrome-devtools.contribution.ts b/packages/addons/src/browser/chrome-devtools.contribution.ts index 47c328592f..68814d4147 100644 --- a/packages/addons/src/browser/chrome-devtools.contribution.ts +++ b/packages/addons/src/browser/chrome-devtools.contribution.ts @@ -39,7 +39,7 @@ export class ChromeDevtoolsContribution implements ClientAppContribution { }); // if opensumi devtools has started capturing before this contribution point is registered - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRpc) { + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRPC) { if (!this.interval) { this.startRTTInterval(); } @@ -52,7 +52,7 @@ export class ChromeDevtoolsContribution implements ClientAppContribution { await this.rttService.measure(); const rtt = Date.now() - start; // "if" below is to prevent setting latency after stoping capturing - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRpc) { + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRPC) { window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.latency = rtt; } }, ChromeDevtoolsContribution.INTERVAL); diff --git a/packages/connection/src/common/utils.ts b/packages/connection/src/common/utils.ts index 987b2823ed..cdc3dbe7ab 100644 --- a/packages/connection/src/common/utils.ts +++ b/packages/connection/src/common/utils.ts @@ -37,8 +37,8 @@ export function parse(input: string, reviver?: (this: any, key: string, value: a } export function getCapturer() { - if (typeof window !== 'undefined' && window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRpc) { - return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRpc; + if (typeof window !== 'undefined' && window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRPC) { + return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureRPC; } return; } diff --git a/packages/core-electron-main/browser-preload/index.js b/packages/core-electron-main/browser-preload/index.js index 1386b3147b..11e58c1477 100644 --- a/packages/core-electron-main/browser-preload/index.js +++ b/packages/core-electron-main/browser-preload/index.js @@ -5,8 +5,8 @@ const { ipcRenderer } = require('electron'); const initForDevtools = () => { const getCapturer = () => { - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureIpc) { - return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureIpc; + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureIPC) { + return window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.captureIPC; } return; }; diff --git a/packages/core-electron-main/src/bootstrap/devtools.ts b/packages/core-electron-main/src/bootstrap/devtools.ts index 0028290d0d..7f82328334 100644 --- a/packages/core-electron-main/src/bootstrap/devtools.ts +++ b/packages/core-electron-main/src/bootstrap/devtools.ts @@ -3,7 +3,7 @@ import { ipcMain, BrowserWindow } from 'electron'; export const initForDevtools = (mainWindow: BrowserWindow) => { // `mainWindow.webContents.send` is used to transfer messages to main window // wherer ipcRenderer.on('main->browser', xxx) is set to receive the messages - // then put them to window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.ipcMessages + // then put them to window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.IPCMessages // ipcMain.on const originalIpcMainOn = ipcMain.on; From fad552751128735acdc583f9ef832723c5f0a88c Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sun, 11 Sep 2022 16:40:20 +0800 Subject: [PATCH 5/9] feat: provide configuration to enable or disable devtools support --- packages/core-browser/src/bootstrap/app.ts | 17 +++++++++++++---- .../core-electron-main/src/bootstrap/app.ts | 5 +++++ .../core-electron-main/src/bootstrap/types.ts | 6 ++++++ .../core-electron-main/src/bootstrap/window.ts | 6 ++++-- packages/startup/entry/web/app.tsx | 1 + tools/electron/src/browser/index.ts | 1 + tools/electron/src/main/index.ts | 1 + 7 files changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/core-browser/src/bootstrap/app.ts b/packages/core-browser/src/bootstrap/app.ts index 8a3589977a..8b8d317b84 100644 --- a/packages/core-browser/src/bootstrap/app.ts +++ b/packages/core-browser/src/bootstrap/app.ts @@ -97,6 +97,11 @@ export interface IClientAppOpts extends Partial { * 插件开发模式下指定的插件路径 */ extensionDevelopmentPath?: string | string[]; + /** + * 是否开启对 OpenSumi DevTools 的支持 + * 默认值为 false + */ + devtools?: boolean; } export interface LayoutConfig { @@ -146,10 +151,6 @@ export class ClientApp implements IClientApp, IDisposable { stateService: ClientAppStateService; constructor(opts: IClientAppOpts) { - // set a global so the opensumi devtools can identify that - // the current page is powered by opensumi core - window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__ = {}; - const { modules, contributions, @@ -161,8 +162,10 @@ export class ClientApp implements IClientApp, IDisposable { editorBackgroundImage, defaultPreferences, allowSetDocumentTitleFollowWorkspaceDir = true, + devtools = false, // if not set, disable devtools support as default ...restOpts // rest part 为 AppConfig } = opts; + this.initEarlyPreference(opts.workspaceDir || ''); setLanguageId(getPreferenceLanguageId(defaultPreferences)); this.injector = opts.injector || new Injector(); @@ -190,6 +193,12 @@ export class ClientApp implements IClientApp, IDisposable { allowSetDocumentTitleFollowWorkspaceDir, }; + if (devtools) { + // set a global so the opensumi devtools can identify that + // the current page is powered by opensumi core + window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__ = {}; + } + if (this.config.isElectronRenderer && electronEnv.metadata?.extensionDevelopmentHost) { this.config.extensionDevelopmentHost = electronEnv.metadata.extensionDevelopmentHost; } diff --git a/packages/core-electron-main/src/bootstrap/app.ts b/packages/core-electron-main/src/bootstrap/app.ts index 17eac85c92..82163f60bd 100644 --- a/packages/core-electron-main/src/bootstrap/app.ts +++ b/packages/core-electron-main/src/bootstrap/app.ts @@ -100,6 +100,11 @@ export class ElectronMainApp { this.onBeforeReadyContribution(); this.registerMainApis(); this.registerURLHandlers(); + + // if not set, disable devtools support as default + if (this.config.devtools === undefined) { + this.config.devtools = false; + } } async init() { diff --git a/packages/core-electron-main/src/bootstrap/types.ts b/packages/core-electron-main/src/bootstrap/types.ts index b60ef59955..0f2b81deed 100644 --- a/packages/core-electron-main/src/bootstrap/types.ts +++ b/packages/core-electron-main/src/bootstrap/types.ts @@ -80,6 +80,12 @@ export interface ElectronAppConfig { * 如有外部 injector,优先使用外部 */ injector?: Injector; + + /** + * 是否开启对 OpenSumi DevTools 的支持 + * 默认值为 false + */ + devtools?: boolean; } export const ElectronAppConfig = Symbol('ElectronAppConfig'); diff --git a/packages/core-electron-main/src/bootstrap/window.ts b/packages/core-electron-main/src/bootstrap/window.ts index 13ebb72d20..6ff15e9511 100644 --- a/packages/core-electron-main/src/bootstrap/window.ts +++ b/packages/core-electron-main/src/bootstrap/window.ts @@ -96,8 +96,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { ...options, }); - // initialize for OpenSumi DevTools - initForDevtools(this.browser); + if (this.appConfig.devtools) { + // initialize for OpenSumi DevTools + initForDevtools(this.browser); + } if (options) { if (options.extensionDir) { diff --git a/packages/startup/entry/web/app.tsx b/packages/startup/entry/web/app.tsx index c84f85f850..3b4bde7a5f 100644 --- a/packages/startup/entry/web/app.tsx +++ b/packages/startup/entry/web/app.tsx @@ -46,4 +46,5 @@ renderApp({ bottom: '@opensumi/ide-terminal-next', right: '', }, + devtools: true, // 开启 core-browser 对 OpenSumi DevTools 的支持,默认为关闭 }); diff --git a/tools/electron/src/browser/index.ts b/tools/electron/src/browser/index.ts index c132885d61..33ab499f49 100644 --- a/tools/electron/src/browser/index.ts +++ b/tools/electron/src/browser/index.ts @@ -103,4 +103,5 @@ renderApp({ }, modules: [...CommonBrowserModules, ElectronBasicModule], layoutConfig: customLayoutConfig, + devtools: true, // 开启 core-browser 对 OpenSumi DevTools 的支持,默认为关闭 }); diff --git a/tools/electron/src/main/index.ts b/tools/electron/src/main/index.ts index 537f95710f..1457d4cc81 100644 --- a/tools/electron/src/main/index.ts +++ b/tools/electron/src/main/index.ts @@ -27,6 +27,7 @@ const electronApp = new ElectronMainApp({ extensionDir: getExtensionDir(), extensionCandidate: [], overrideWebPreferences: {}, + devtools: true, // 开启 core-electron-main 对 OpenSumi DevTools 的支持,默认为关闭 }); electronApp.init().then(() => { From e4097c0b894016bd6dc88c1889ec52c340bbdee1 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Thu, 15 Sep 2022 20:29:35 +0800 Subject: [PATCH 6/9] feat: toggle devtools support in browser-preload/index.js --- packages/core-electron-main/browser-preload/index.js | 8 ++++---- packages/core-electron-main/src/bootstrap/window.ts | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core-electron-main/browser-preload/index.js b/packages/core-electron-main/browser-preload/index.js index 11e58c1477..f4267c400c 100644 --- a/packages/core-electron-main/browser-preload/index.js +++ b/packages/core-electron-main/browser-preload/index.js @@ -57,9 +57,6 @@ const initForDevtools = () => { }); }; -// initialize for OpenSumi DevTools -initForDevtools(); - const electronEnv = {}; const urlParams = new URLSearchParams(decodeURIComponent(window.location.search)); @@ -89,7 +86,10 @@ electronEnv.currentWebContentsId = webContentsId; electronEnv.onigWasmPath = require.resolve('vscode-oniguruma/release/onig.wasm'); const metaData = JSON.parse(ipcRenderer.sendSync('window-metadata', electronEnv.currentWindowId)); - +// if devtools support enabled +if (metaData.devtools) { + initForDevtools(); +} electronEnv.metadata = metaData; process.env = Object.assign({}, process.env, metaData.env, { WORKSPACE_DIR: metaData.workspace }); diff --git a/packages/core-electron-main/src/bootstrap/window.ts b/packages/core-electron-main/src/bootstrap/window.ts index 6ff15e9511..199e6d5eb8 100644 --- a/packages/core-electron-main/src/bootstrap/window.ts +++ b/packages/core-electron-main/src/bootstrap/window.ts @@ -138,6 +138,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { workerHostEntry: this.appConfig.extensionWorkerEntry, extensionDevelopmentHost: this.appConfig.extensionDevelopmentHost, appPath: app.getAppPath(), + devtools: this.appConfig.devtools, }); } }; From 2122b582b9b66786c4f835b56e5544a31e7e3515 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Thu, 15 Sep 2022 22:23:40 +0800 Subject: [PATCH 7/9] feat: toggle devtools support in chrome-devtools.contribution.ts --- .../browser/chrome-devtools.contribution.ts | 40 +++++++++++-------- packages/core-browser/src/bootstrap/app.ts | 6 +-- .../src/react-providers/config-provider.tsx | 5 +++ 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/packages/addons/src/browser/chrome-devtools.contribution.ts b/packages/addons/src/browser/chrome-devtools.contribution.ts index 68814d4147..e5ab6f90c9 100644 --- a/packages/addons/src/browser/chrome-devtools.contribution.ts +++ b/packages/addons/src/browser/chrome-devtools.contribution.ts @@ -1,5 +1,5 @@ import { Autowired } from '@opensumi/di'; -import { ClientAppContribution } from '@opensumi/ide-core-browser'; +import { AppConfig, ClientAppContribution } from '@opensumi/ide-core-browser'; import { Domain } from '@opensumi/ide-core-common/lib/di-helper'; import { ConnectionRTTBrowserServiceToken, ConnectionRTTBrowserService } from './connection-rtt-service'; @@ -15,6 +15,9 @@ enum DevtoolsCommand { @Domain(ClientAppContribution) export class ChromeDevtoolsContribution implements ClientAppContribution { + @Autowired(AppConfig) + private readonly appConfig: AppConfig; + @Autowired(ConnectionRTTBrowserServiceToken) protected readonly rttService: ConnectionRTTBrowserService; @@ -23,25 +26,28 @@ export class ChromeDevtoolsContribution implements ClientAppContribution { static INTERVAL = 1000; initialize() { - // receive notification from opensumi devtools by custom event - window.addEventListener(DevtoolsEvent.Latency, (event) => { - const { command } = event.detail; - if (command === DevtoolsCommand.Start) { + // only runs when devtools supoprt is enabled + if (this.appConfig.devtools) { + // receive notification from opensumi devtools by custom event + window.addEventListener(DevtoolsEvent.Latency, (event) => { + const { command } = event.detail; + if (command === DevtoolsCommand.Start) { + if (!this.interval) { + this.startRTTInterval(); + } + } else if (command === DevtoolsCommand.Stop) { + if (this.interval) { + global.clearInterval(this.interval); + this.interval = undefined; + } + } + }); + + // if opensumi devtools has started capturing before this contribution point is registered + if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRPC) { if (!this.interval) { this.startRTTInterval(); } - } else if (command === DevtoolsCommand.Stop) { - if (this.interval) { - global.clearInterval(this.interval); - this.interval = undefined; - } - } - }); - - // if opensumi devtools has started capturing before this contribution point is registered - if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureRPC) { - if (!this.interval) { - this.startRTTInterval(); } } } diff --git a/packages/core-browser/src/bootstrap/app.ts b/packages/core-browser/src/bootstrap/app.ts index 8b8d317b84..67c961848b 100644 --- a/packages/core-browser/src/bootstrap/app.ts +++ b/packages/core-browser/src/bootstrap/app.ts @@ -97,11 +97,6 @@ export interface IClientAppOpts extends Partial { * 插件开发模式下指定的插件路径 */ extensionDevelopmentPath?: string | string[]; - /** - * 是否开启对 OpenSumi DevTools 的支持 - * 默认值为 false - */ - devtools?: boolean; } export interface LayoutConfig { @@ -191,6 +186,7 @@ export class ClientApp implements IClientApp, IDisposable { layoutConfig: opts.layoutConfig as LayoutConfig, editorBackgroundImage: opts.editorBackgroundImage || editorBackgroundImage, allowSetDocumentTitleFollowWorkspaceDir, + devtools, }; if (devtools) { diff --git a/packages/core-browser/src/react-providers/config-provider.tsx b/packages/core-browser/src/react-providers/config-provider.tsx index 2a949db2fc..f3080ae745 100644 --- a/packages/core-browser/src/react-providers/config-provider.tsx +++ b/packages/core-browser/src/react-providers/config-provider.tsx @@ -218,6 +218,11 @@ export interface AppConfig { * 这将影响 Terminal 与 Extension 模块与子进程的连接方式 */ isRemote?: boolean; + /** + * 是否开启对 OpenSumi DevTools 的支持 + * 默认值为 false + */ + devtools?: boolean; } export const ConfigContext = React.createContext({ From 00eee424b5eb11f8918499877e59661197a7d6ba Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Fri, 23 Sep 2022 14:56:58 +0800 Subject: [PATCH 8/9] chore: use isUndefined() to test if a variable is not defined --- packages/core-electron-main/src/bootstrap/app.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-electron-main/src/bootstrap/app.ts b/packages/core-electron-main/src/bootstrap/app.ts index 82163f60bd..597f72dfb2 100644 --- a/packages/core-electron-main/src/bootstrap/app.ts +++ b/packages/core-electron-main/src/bootstrap/app.ts @@ -9,6 +9,7 @@ import { IEventBus, EventBusImpl, asExtensionCandidate, + isUndefined, } from '@opensumi/ide-core-common'; import { IElectronMainLifeCycleService } from '@opensumi/ide-core-common/lib/electron'; import { argv } from '@opensumi/ide-core-common/lib/node/cli'; @@ -102,7 +103,7 @@ export class ElectronMainApp { this.registerURLHandlers(); // if not set, disable devtools support as default - if (this.config.devtools === undefined) { + if (isUndefined(this.config.devtools)) { this.config.devtools = false; } } From b3840bc4419595465e913f79b4a96a64e44074e6 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sun, 25 Sep 2022 12:38:38 +0800 Subject: [PATCH 9/9] refactor: do not capture ipcMain messages But capture the return values of ipcRenderer.sendSync and ipcRenderer.invoke --- .../browser-preload/index.js | 28 +++++++++------- .../src/bootstrap/devtools.ts | 33 ------------------- .../src/bootstrap/window.ts | 6 ---- 3 files changed, 16 insertions(+), 51 deletions(-) delete mode 100644 packages/core-electron-main/src/bootstrap/devtools.ts diff --git a/packages/core-electron-main/browser-preload/index.js b/packages/core-electron-main/browser-preload/index.js index f4267c400c..915a4df853 100644 --- a/packages/core-electron-main/browser-preload/index.js +++ b/packages/core-electron-main/browser-preload/index.js @@ -3,6 +3,9 @@ const os = require('os'); const { ipcRenderer } = require('electron'); +// for generating requestId to pair request and response +const uuid = () => Date.now().toString(36) + Math.random().toString(36).substr(2); + const initForDevtools = () => { const getCapturer = () => { if (window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__?.captureIPC) { @@ -22,9 +25,7 @@ const initForDevtools = () => { const originalIpcRendererOn = ipcRenderer.on; ipcRenderer.on = (channel, handler) => { const proxyHandler = (event, ...args) => { - if (channel !== 'main->browser') { - capture({ ipcMethod: 'ipcRenderer.on', channel, args }); - } + capture({ ipcMethod: 'ipcRenderer.on', channel, args }); handler(event, ...args); }; return originalIpcRendererOn.call(ipcRenderer, channel, proxyHandler); @@ -40,21 +41,24 @@ const initForDevtools = () => { // ipcRenderer.sendSync const originalIpcRendererSendSync = ipcRenderer.sendSync; ipcRenderer.sendSync = (channel, ...args) => { - capture({ ipcMethod: 'ipcRenderer.sendSync', channel, args }); - return originalIpcRendererSendSync.call(ipcRenderer, channel, ...args); + const requestId = uuid(); + capture({ ipcMethod: 'ipcRenderer.sendSync', channel, requestId, args }); + const result = originalIpcRendererSendSync.call(ipcRenderer, channel, ...args); + capture({ ipcMethod: 'ipcRenderer.sendSync', channel, requestId, result }); + return result; }; // ipcRenderer.invoke const originalIpcRendererInvoke = ipcRenderer.invoke; ipcRenderer.invoke = (channel, ...args) => { - capture({ ipcMethod: 'ipcRenderer.invoke', channel, args }); - return originalIpcRendererInvoke.call(ipcRenderer, channel, ...args); + const requestId = uuid(); + capture({ ipcMethod: 'ipcRenderer.invoke', channel, requestId, args }); + const resultPromise = originalIpcRendererInvoke.call(ipcRenderer, channel, ...args); + resultPromise.then((result) => { + capture({ ipcMethod: 'ipcRenderer.invoke', channel, requestId, result }); + }); + return resultPromise; }; - - // receive messages that transfered from main process and capture them - ipcRenderer.on('main->browser', (event, message) => { - capture(message); - }); }; const electronEnv = {}; diff --git a/packages/core-electron-main/src/bootstrap/devtools.ts b/packages/core-electron-main/src/bootstrap/devtools.ts deleted file mode 100644 index 7f82328334..0000000000 --- a/packages/core-electron-main/src/bootstrap/devtools.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ipcMain, BrowserWindow } from 'electron'; - -export const initForDevtools = (mainWindow: BrowserWindow) => { - // `mainWindow.webContents.send` is used to transfer messages to main window - // wherer ipcRenderer.on('main->browser', xxx) is set to receive the messages - // then put them to window.__OPENSUMI_DEVTOOLS_GLOBAL_HOOK__.IPCMessages - - // ipcMain.on - const originalIpcMainOn = ipcMain.on; - ipcMain.on = (channel: any, handler: any) => { - const proxyHandler = (event: any, ...args: any) => { - mainWindow.webContents.send('main->browser', { ipcMethod: 'ipcMain.on', channel, args }); - handler(event, ...args); - // TODO event.returnValue会作为ipcRenderer.sendSync的response, 可捕获 - }; - return originalIpcMainOn.call(ipcMain, channel, proxyHandler); - }; - - // ipcMain.handle - const originalIpcMainHandle = ipcMain.handle; - ipcMain.handle = (channel: any, handler: any) => { - const proxyHandler = (event: any, ...args: any) => { - mainWindow.webContents.send('main->browser', { ipcMethod: 'ipcMain.handle', channel, args }); - handler(event, ...args); - // TODO ipcMain.handle的返回值会作为ipcRenderer.invoke的response, 可捕获 - }; - return originalIpcMainHandle.call(ipcMain, channel, proxyHandler); - }; - - // TODO BrowserWindow.webContents.send - // 这是main进程向renderer进程发送消息的方式, 但BrowserWindow可以是任何实例, - // 所以我不知道怎么处理. 如果可以实现, 注意判断channel是否为'main->browser' -}; diff --git a/packages/core-electron-main/src/bootstrap/window.ts b/packages/core-electron-main/src/bootstrap/window.ts index 199e6d5eb8..bdb1e00648 100644 --- a/packages/core-electron-main/src/bootstrap/window.ts +++ b/packages/core-electron-main/src/bootstrap/window.ts @@ -25,7 +25,6 @@ import { } from '@opensumi/ide-core-common'; import { normalizedIpcHandlerPathAsync } from '@opensumi/ide-core-common/lib/utils/ipc'; -import { initForDevtools } from './devtools'; import { ElectronAppConfig, ICodeWindow, ICodeWindowOptions } from './types'; const DEFAULT_WINDOW_HEIGHT = 700; @@ -96,11 +95,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { ...options, }); - if (this.appConfig.devtools) { - // initialize for OpenSumi DevTools - initForDevtools(this.browser); - } - if (options) { if (options.extensionDir) { this.extensionDir = options.extensionDir;