From a09ac6ecb28421917b91ca498a47fd199c6b5af9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 19 May 2021 12:29:20 -0400 Subject: [PATCH] Add more specific IPC helpers Signed-off-by: Sebastian Malton --- src/common/base-store.ts | 18 +++----- src/common/cluster-ipc.ts | 13 +++--- src/common/cluster-store.ts | 24 +++++++--- src/common/ipc/ipc.ts | 45 +++++++------------ src/extensions/extension-discovery.ts | 8 ++-- src/extensions/extension-loader.ts | 8 ++-- src/main/window-manager.ts | 4 +- src/renderer/api/catalog-entity-registry.ts | 4 +- .../cluster-manager/cluster-status.tsx | 4 +- .../command-palette/command-container.tsx | 8 ++-- src/renderer/navigation/events.ts | 8 ++-- 11 files changed, 66 insertions(+), 78 deletions(-) diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 893a09b965c2..842e0304b409 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -22,11 +22,11 @@ import path from "path"; import Config from "conf"; import type { Options as ConfOptions } from "conf/dist/source/types"; -import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron"; +import { app, ipcMain, ipcRenderer, remote } from "electron"; import { IReactionOptions, makeObservable, observable, reaction, runInAction, when } from "mobx"; import { getAppVersion, Singleton, toJS, Disposer } from "./utils"; import logger from "../main/logger"; -import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "./ipc"; +import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc"; import isEqual from "lodash/isEqual"; export interface BaseStoreParams extends ConfOptions { @@ -126,23 +126,17 @@ export abstract class BaseStore extends Singleton { ); if (ipcMain) { - const callback = (event: IpcMainEvent, model: T) => { + this.syncDisposers.push(ipcMainOn(this.syncMainChannel, (event, model: T) => { logger.silly(`[STORE]: SYNC ${this.name} from renderer`, { model }); this.onSync(model); - }; - - subscribeToBroadcast(this.syncMainChannel, callback); - this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncMainChannel, callback)); + })); } if (ipcRenderer) { - const callback = (event: IpcRendererEvent, model: T) => { + this.syncDisposers.push(ipcRendererOn(this.syncRendererChannel, (event, model: T) => { logger.silly(`[STORE]: SYNC ${this.name} from main`, { model }); this.onSyncFromMain(model); - }; - - subscribeToBroadcast(this.syncRendererChannel, callback); - this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncRendererChannel, callback)); + })); } } diff --git a/src/common/cluster-ipc.ts b/src/common/cluster-ipc.ts index 718151c3ed6c..7b62c1415040 100644 --- a/src/common/cluster-ipc.ts +++ b/src/common/cluster-ipc.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { handleRequest } from "./ipc"; import { ClusterId, ClusterStore } from "./cluster-store"; import { appEventBus } from "./event-bus"; import { ResourceApplier } from "../main/resource-applier"; @@ -34,13 +33,13 @@ export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; if (ipcMain) { - handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { + ipcMain.handle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { return ClusterStore.getInstance() .getById(clusterId) ?.activate(force); }); - handleRequest(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { + ipcMain.handle(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { const cluster = ClusterStore.getInstance().getById(clusterId); if (cluster) { @@ -49,13 +48,13 @@ if (ipcMain) { } }); - handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => { + ipcMain.handle(clusterRefreshHandler, (event, clusterId: ClusterId) => { return ClusterStore.getInstance() .getById(clusterId) ?.refresh({ refreshMetadata: true }); }); - handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => { + ipcMain.handle(clusterDisconnectHandler, (event, clusterId: ClusterId) => { appEventBus.emit({name: "cluster", action: "stop"}); const cluster = ClusterStore.getInstance().getById(clusterId); @@ -65,7 +64,7 @@ if (ipcMain) { } }); - handleRequest(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { + ipcMain.handle(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { appEventBus.emit({name: "cluster", action: "kubectl-apply-all"}); const cluster = ClusterStore.getInstance().getById(clusterId); @@ -84,7 +83,7 @@ if (ipcMain) { } }); - handleRequest(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { + ipcMain.handle(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { appEventBus.emit({name: "cluster", action: "kubectl-delete-all"}); const cluster = ClusterStore.getInstance().getById(clusterId); diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index 31ecd1803167..49f4466c6e9d 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -31,7 +31,7 @@ import { appEventBus } from "./event-bus"; import { dumpConfigYaml } from "./kube-helpers"; import { saveToAppFiles } from "./utils/saveToAppFiles"; import type { KubeConfig } from "@kubernetes/client-node"; -import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc"; +import { ipcMainOn, ipcRendererOn, requestMain } from "./ipc"; import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting"; import { disposer, noop, toJS } from "./utils"; @@ -114,6 +114,8 @@ export interface ClusterPrometheusPreferences { } export class ClusterStore extends BaseStore { + private static StateChannel = "cluster:state"; + static get storedKubeConfigFolder(): string { return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs"); } @@ -172,7 +174,7 @@ export class ClusterStore extends BaseStore { } }); } else if (ipcMain) { - handleRequest(ClusterStore.stateRequestChannel, (): clusterStateSync[] => { + ipcMain.handle(ClusterStore.stateRequestChannel, (): clusterStateSync[] => { const clusterStates: clusterStateSync[] = []; this.clustersList.forEach((cluster) => { @@ -193,17 +195,25 @@ export class ClusterStore extends BaseStore { reaction(() => this.connectedClustersList, () => { this.pushState(); }), - () => unsubscribeAllFromBroadcast("cluster:state"), ); } } + handleStateChange = (event: any, clusterId: string, state: ClusterState) => { + logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host} (${webFrame.routingId})`, clusterId, state); + this.getById(clusterId)?.setState(state); + }; + registerIpcListener() { logger.info(`[CLUSTER-STORE] start to listen (${webFrame.routingId})`); - subscribeToBroadcast("cluster:state", (event, clusterId: string, state: ClusterState) => { - logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host} (${webFrame.routingId})`, clusterId, state); - this.getById(clusterId)?.setState(state); - }); + + if (ipcMain) { + this.disposer.push(ipcMainOn(ClusterStore.StateChannel, this.handleStateChange)); + } + + if (ipcRenderer) { + this.disposer.push(ipcRendererOn(ClusterStore.StateChannel, this.handleStateChange)); + } } unregisterIpcListener() { diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index f541e0d27632..074d73176c93 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -26,22 +26,21 @@ import { ipcMain, ipcRenderer, remote, webContents } from "electron"; import { toJS } from "../utils/toJS"; import logger from "../../main/logger"; -import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames"; +import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames"; +import type { Disposer } from "../utils"; const subFramesChannel = "ipc:get-sub-frames"; -export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) { - ipcMain.handle(channel, async (event, ...args) => { - const payload = await listener(event, ...args); - - return sanitizePayload(payload); - }); -} - export async function requestMain(channel: string, ...args: any[]) { return ipcRenderer.invoke(channel, ...args.map(sanitizePayload)); } +export function ipcMainHandle(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) { + ipcMain.handle(channel, async (event, ...args) => { + return sanitizePayload(await listener(event, ...args)); + }); +} + function getSubFrames(): ClusterFrameInfo[] { return Array.from(clusterFrameMap.values()); } @@ -76,34 +75,20 @@ export function broadcastMessage(channel: string, ...args: any[]) { }); } -export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) { - if (ipcRenderer) { - ipcRenderer.on(channel, listener); - } else if (ipcMain) { - ipcMain.on(channel, listener); - } +export function ipcMainOn(channel: string, listener: (event: Electron.IpcMainEvent, ...args: any[]) => any): Disposer { + ipcMain.on(channel, listener); - return listener; + return () => ipcMain.off(channel, listener); } -export function unsubscribeFromBroadcast(channel: string, listener: (...args: any[]) => any) { - if (ipcRenderer) { - ipcRenderer.off(channel, listener); - } else if (ipcMain) { - ipcMain.off(channel, listener); - } -} +export function ipcRendererOn(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer { + ipcRenderer.on(channel, listener); -export function unsubscribeAllFromBroadcast(channel: string) { - if (ipcRenderer) { - ipcRenderer.removeAllListeners(channel); - } else if (ipcMain) { - ipcMain.removeAllListeners(channel); - } + return () => ipcRenderer.off(channel, listener); } export function bindBroadcastHandlers() { - handleRequest(subFramesChannel, () => getSubFrames()); + ipcMainHandle(subFramesChannel, () => getSubFrames()); } /** diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index 8a0929d01678..52e989da5220 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -20,13 +20,13 @@ */ import { watch } from "chokidar"; -import { ipcRenderer } from "electron"; +import { ipcMain, ipcRenderer } from "electron"; import { EventEmitter } from "events"; import fse from "fs-extra"; import { observable, reaction, when, makeObservable } from "mobx"; import os from "os"; import path from "path"; -import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc"; +import { broadcastMessage, ipcRendererOn, requestMain } from "../common/ipc"; import { Singleton, toJS } from "../common/utils"; import logger from "../main/logger"; import { ExtensionInstallationStateStore } from "../renderer/components/+extensions/extension-install.store"; @@ -139,13 +139,13 @@ export class ExtensionDiscovery extends Singleton { }; requestMain(ExtensionDiscovery.extensionDiscoveryChannel).then(onMessage); - subscribeToBroadcast(ExtensionDiscovery.extensionDiscoveryChannel, (_event, message: ExtensionDiscoveryChannelMessage) => { + ipcRendererOn(ExtensionDiscovery.extensionDiscoveryChannel, (_event, message: ExtensionDiscoveryChannelMessage) => { onMessage(message); }); } async initMain() { - handleRequest(ExtensionDiscovery.extensionDiscoveryChannel, () => this.toJSON()); + ipcMain.handle(ExtensionDiscovery.extensionDiscoveryChannel, () => this.toJSON()); reaction(() => this.toJSON(), () => { this.broadcast(); diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index 4607cd0f5427..8a7bb14a7d30 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -25,7 +25,7 @@ import { isEqual } from "lodash"; import { action, computed, makeObservable, observable, reaction, when } from "mobx"; import path from "path"; import { getHostedCluster } from "../common/cluster-store"; -import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc"; +import { broadcastMessage, ipcMainOn, ipcRendererOn, requestMain, ipcMainHandle } from "../common/ipc"; import { Singleton, toJS } from "../common/utils"; import logger from "../main/logger"; import type { InstalledExtension } from "./extension-discovery"; @@ -174,11 +174,11 @@ export class ExtensionLoader extends Singleton { this.isLoaded = true; this.loadOnMain(); - handleRequest(ExtensionLoader.extensionsMainChannel, () => { + ipcMainHandle(ExtensionLoader.extensionsMainChannel, () => { return Array.from(this.toJSON()); }); - subscribeToBroadcast(ExtensionLoader.extensionsRendererChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { + ipcMainOn(ExtensionLoader.extensionsRendererChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { this.syncExtensions(extensions); }); } @@ -199,7 +199,7 @@ export class ExtensionLoader extends Singleton { }; requestMain(ExtensionLoader.extensionsMainChannel).then(extensionListHandler); - subscribeToBroadcast(ExtensionLoader.extensionsMainChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { + ipcRendererOn(ExtensionLoader.extensionsMainChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { extensionListHandler(extensions); }); } diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 4e5588e47a48..3c358a4b1ba0 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -24,7 +24,7 @@ import { makeObservable, observable } from "mobx"; import { app, BrowserWindow, dialog, shell, webContents } from "electron"; import windowStateKeeper from "electron-window-state"; import { appEventBus } from "../common/event-bus"; -import { subscribeToBroadcast } from "../common/ipc"; +import { ipcMainOn } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -141,7 +141,7 @@ export class WindowManager extends Singleton { protected bindEvents() { // track visible cluster from ui - subscribeToBroadcast(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { + ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; }); } diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index 63681106bd4d..acc518fd42b0 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -20,7 +20,7 @@ */ import { computed, observable, makeObservable } from "mobx"; -import { subscribeToBroadcast } from "../../common/ipc"; +import { ipcRendererOn } from "../../common/ipc"; import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog"; import "../../common/catalog-entities"; import { iter } from "../utils"; @@ -34,7 +34,7 @@ export class CatalogEntityRegistry { } init() { - subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => { + ipcRendererOn("catalog:items", (event, items: (CatalogEntityData & CatalogEntityKindData)[]) => { this.rawItems.replace(items); }); } diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 2d4ccf3a388a..63ad3936b22e 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -26,7 +26,7 @@ import React from "react"; import { observer } from "mobx-react"; import { ipcRenderer } from "electron"; import { computed, observable, makeObservable } from "mobx"; -import { requestMain, subscribeToBroadcast } from "../../../common/ipc"; +import { ipcRendererOn, requestMain } from "../../../common/ipc"; import { Icon } from "../icon"; import { Button } from "../button"; import { cssNames, IClassName } from "../../utils"; @@ -59,7 +59,7 @@ export class ClusterStatus extends React.Component { } async componentDidMount() { - subscribeToBroadcast(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => { + ipcRendererOn(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => { this.authOutput.push({ data: res.data.trimRight(), error: res.error, diff --git a/src/renderer/components/command-palette/command-container.tsx b/src/renderer/components/command-palette/command-container.tsx index 6d2ab64cb1b6..45ea0d18fed3 100644 --- a/src/renderer/components/command-palette/command-container.tsx +++ b/src/renderer/components/command-palette/command-container.tsx @@ -26,7 +26,7 @@ import { observer } from "mobx-react"; import React from "react"; import { Dialog } from "../dialog"; import { EventEmitter } from "../../../common/event-emitter"; -import { subscribeToBroadcast } from "../../../common/ipc"; +import { ipcRendererOn } from "../../../common/ipc"; import { CommandDialog } from "./command-dialog"; import type { ClusterId } from "../../../common/cluster-store"; import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; @@ -84,7 +84,7 @@ export class CommandContainer extends React.Component { componentDidMount() { if (this.props.clusterId) { - subscribeToBroadcast(`command-palette:run-action:${this.props.clusterId}`, (event, commandId: string) => { + ipcRendererOn(`command-palette:run-action:${this.props.clusterId}`, (event, commandId: string) => { const command = this.findCommandById(commandId); if (command) { @@ -92,8 +92,8 @@ export class CommandContainer extends React.Component { } }); } else { - subscribeToBroadcast("command-palette:open", () => { - this.commandComponent = ; + ipcRendererOn("command-palette:open", () => { + CommandOverlay.open(); }); } window.addEventListener("keyup", (e) => this.escHandler(e), true); diff --git a/src/renderer/navigation/events.ts b/src/renderer/navigation/events.ts index 0adc53d7aea6..f5a9968f4af7 100644 --- a/src/renderer/navigation/events.ts +++ b/src/renderer/navigation/events.ts @@ -22,7 +22,7 @@ import { ipcRenderer } from "electron"; import { reaction } from "mobx"; import { getMatchedClusterId, navigate } from "./helpers"; -import { broadcastMessage, subscribeToBroadcast } from "../../common/ipc"; +import { broadcastMessage, ipcRendererOn } from "../../common/ipc"; import logger from "../../main/logger"; export const enum IpcRendererNavigationEvents { @@ -45,7 +45,7 @@ export function bindEvents() { } // Reload dashboard window - subscribeToBroadcast(IpcRendererNavigationEvents.RELOAD_PAGE, () => { + ipcRendererOn(IpcRendererNavigationEvents.RELOAD_PAGE, () => { location.reload(); }); } @@ -60,7 +60,7 @@ function bindClusterManagerRouteEvents() { }); // Handle navigation via IPC - subscribeToBroadcast(IpcRendererNavigationEvents.NAVIGATE_IN_APP, (event, url: string) => { + ipcRendererOn(IpcRendererNavigationEvents.NAVIGATE_IN_APP, (event, url: string) => { logger.info(`[IPC]: ${event.type}: ${url}`, { currentLocation: location.href }); navigate(url); }); @@ -68,7 +68,7 @@ function bindClusterManagerRouteEvents() { // Handle cluster-view renderer process events within iframes function bindClusterFrameRouteEvents() { - subscribeToBroadcast(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER, (event, url: string) => { + ipcRendererOn(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER, (event, url: string) => { logger.info(`[IPC]: ${event.type}: ${url}`, { currentLocation: location.href }); navigate(url); });