diff --git a/desktop/app/src/RenderHost.tsx b/desktop/app/src/RenderHost.tsx index a8b25f529..3aa8fb17c 100644 --- a/desktop/app/src/RenderHost.tsx +++ b/desktop/app/src/RenderHost.tsx @@ -7,6 +7,22 @@ * @format */ +import {NotificationEvents} from './dispatcher/notifications'; +import {PluginNotification} from './reducers/notifications'; + +// Events that are emitted from the main.ts ovr the IPC process bridge in Electron +type MainProcessEvents = { + 'flipper-protocol-handler': [query: string]; + 'open-flipper-file': [url: string]; + notificationEvent: [ + eventName: NotificationEvents, + pluginNotification: PluginNotification, + arg: null | string | number, + ]; + trackUsage: any[]; + getLaunchTime: [launchStartTime: number]; +}; + /** * Utilities provided by the render host, e.g. Electron, the Browser, etc */ @@ -16,6 +32,10 @@ export interface RenderHost { selectDirectory?(defaultPath?: string): Promise; registerShortcut(shortCut: string, callback: () => void): void; hasFocus(): boolean; + onIpcEvent( + event: Event, + callback: (...arg: MainProcessEvents[Event]) => void, + ): void; } let renderHostInstance: RenderHost | undefined; @@ -41,5 +61,6 @@ if (process.env.NODE_ENV === 'test') { hasFocus() { return true; }, + onIpcEvent() {}, }); } diff --git a/desktop/app/src/dispatcher/application.tsx b/desktop/app/src/dispatcher/application.tsx index 1e7244c04..9f9f04bba 100644 --- a/desktop/app/src/dispatcher/application.tsx +++ b/desktop/app/src/dispatcher/application.tsx @@ -9,7 +9,7 @@ // Fine for app startup. // eslint-disable-next-line flipper/no-electron-remote-imports -import {remote, ipcRenderer, IpcRendererEvent} from 'electron'; +import {remote} from 'electron'; import {Store} from '../reducers/index'; import {Logger} from 'flipper-common'; import { @@ -19,9 +19,12 @@ import { import {tryCatchReportPlatformFailures} from 'flipper-common'; import {handleDeeplink} from '../deeplink'; import {Dialog} from 'flipper-plugin'; +import {getRenderHostInstance} from '../RenderHost'; export default (store: Store, logger: Logger) => { const currentWindow = remote.getCurrentWindow(); + const renderHost = getRenderHostInstance(); + const onFocus = () => { setImmediate(() => { store.dispatch({ @@ -55,28 +58,22 @@ export default (store: Store, logger: Logger) => { }); }); - ipcRenderer.on( - 'flipper-protocol-handler', - (_event: IpcRendererEvent, query: string) => { - handleDeeplink(store, logger, query).catch((e) => { - console.warn('Failed to handle deeplink', query, e); - Dialog.alert({ - title: 'Failed to open deeplink', - type: 'error', - message: `Failed to handle deeplink '${query}': ${ - e.message ?? e.toString() - }`, - }); + renderHost.onIpcEvent('flipper-protocol-handler', (query: string) => { + handleDeeplink(store, logger, query).catch((e) => { + console.warn('Failed to handle deeplink', query, e); + Dialog.alert({ + title: 'Failed to open deeplink', + type: 'error', + message: `Failed to handle deeplink '${query}': ${ + e.message ?? e.toString() + }`, }); - }, - ); + }); + }); - ipcRenderer.on( - 'open-flipper-file', - (_event: IpcRendererEvent, url: string) => { - tryCatchReportPlatformFailures(() => { - return importFileToStore(url, store); - }, `${IMPORT_FLIPPER_TRACE_EVENT}:Deeplink`); - }, - ); + renderHost.onIpcEvent('open-flipper-file', (url: string) => { + tryCatchReportPlatformFailures(() => { + return importFileToStore(url, store); + }, `${IMPORT_FLIPPER_TRACE_EVENT}:Deeplink`); + }); }; diff --git a/desktop/app/src/dispatcher/notifications.tsx b/desktop/app/src/dispatcher/notifications.tsx index 4b96f88e1..614fc0d57 100644 --- a/desktop/app/src/dispatcher/notifications.tsx +++ b/desktop/app/src/dispatcher/notifications.tsx @@ -10,7 +10,7 @@ import {Store} from '../reducers/index'; import {Logger} from 'flipper-common'; import {PluginNotification} from '../reducers/notifications'; -import {ipcRenderer, IpcRendererEvent} from 'electron'; +import {ipcRenderer} from 'electron'; import { updatePluginBlocklist, updateCategoryBlocklist, @@ -19,18 +19,24 @@ import {textContent} from 'flipper-plugin'; import {getPluginTitle} from '../utils/pluginUtils'; import {sideEffect} from '../utils/sideEffect'; import {openNotification} from '../sandy-chrome/notification/Notification'; +import {getRenderHostInstance} from '../RenderHost'; + +export type NotificationEvents = + | 'show' + | 'click' + | 'close' + | 'reply' + | 'action'; -type NotificationEvents = 'show' | 'click' | 'close' | 'reply' | 'action'; const NOTIFICATION_THROTTLE = 5 * 1000; // in milliseconds export default (store: Store, logger: Logger) => { const knownNotifications: Set = new Set(); const lastNotificationTime: Map = new Map(); - ipcRenderer.on( + getRenderHostInstance().onIpcEvent( 'notificationEvent', ( - _event: IpcRendererEvent, eventName: NotificationEvents, pluginNotification: PluginNotification, arg: null | string | number, diff --git a/desktop/app/src/dispatcher/tracking.tsx b/desktop/app/src/dispatcher/tracking.tsx index 44dd36dad..a374b025d 100644 --- a/desktop/app/src/dispatcher/tracking.tsx +++ b/desktop/app/src/dispatcher/tracking.tsx @@ -7,9 +7,6 @@ * @format */ -// Used for PID tracking. -// eslint-disable-next-line flipper/no-electron-remote-imports -import {ipcRenderer} from 'electron'; import {performance} from 'perf_hooks'; import {EventEmitter} from 'events'; @@ -146,16 +143,15 @@ export default (store: Store, logger: Logger) => { ); } - ipcRenderer.on('trackUsage', (event, ...args: any[]) => { + renderHost.onIpcEvent('trackUsage', (...args: any[]) => { let state: State; try { state = store.getState(); } catch (e) { // if trackUsage is called (indirectly) through a reducer, this will utterly die Flipper. Let's prevent that and log an error instead console.error( - 'trackUsage triggered indirectly as side effect of a reducer. Event: ', - event.type, - event, + 'trackUsage triggered indirectly as side effect of a reducer', + e, ); return; } diff --git a/desktop/app/src/init.tsx b/desktop/app/src/init.tsx index 1c4fc2b7f..5c94fc803 100644 --- a/desktop/app/src/init.tsx +++ b/desktop/app/src/init.tsx @@ -297,5 +297,10 @@ function initializeFlipperForElectron() { hasFocus() { return remote.getCurrentWindow().isFocused(); }, + onIpcEvent(event, callback) { + ipcRenderer.on(event, (_ev, ...args: any[]) => { + callback(...(args as any)); + }); + }, }); } diff --git a/desktop/app/src/sandy-chrome/SandyApp.tsx b/desktop/app/src/sandy-chrome/SandyApp.tsx index 4b74e8a80..c5cef45a6 100644 --- a/desktop/app/src/sandy-chrome/SandyApp.tsx +++ b/desktop/app/src/sandy-chrome/SandyApp.tsx @@ -38,6 +38,7 @@ import fbConfig from '../fb-stubs/config'; import {isFBEmployee} from '../utils/fbEmployee'; import {notification} from 'antd'; import isProduction from '../utils/isProduction'; +import {getRenderHostInstance} from '../RenderHost'; export type ToplevelNavItem = | 'appinspect' @@ -214,9 +215,16 @@ function registerStartupTime(logger: Logger) { // track time since launch const [s, ns] = process.hrtime(); const launchEndTime = s * 1e3 + ns / 1e6; - ipcRenderer.on('getLaunchTime', (_: any, launchStartTime: number) => { - logger.track('performance', 'launchTime', launchEndTime - launchStartTime); - }); + getRenderHostInstance().onIpcEvent( + 'getLaunchTime', + (launchStartTime: number) => { + logger.track( + 'performance', + 'launchTime', + launchEndTime - launchStartTime, + ); + }, + ); ipcRenderer.send('getLaunchTime'); ipcRenderer.send('componentDidMount');