mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add IPC capabilities for Extensions (#2775)
* Add IPC capabilities for Extensions Signed-off-by: Sebastian Malton <sebastian@malton.name> * revert onA|D change: Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch to pushing the disposer in the methods Signed-off-by: Sebastian Malton <sebastian@malton.name> * improve documentation, switch to a singleton instead of extension methods Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix build Signed-off-by: Sebastian Malton <sebastian@malton.name> * make exported class abstract, improve guide Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix docs Signed-off-by: Sebastian Malton <sebastian@malton.name> * fix lint Signed-off-by: Sebastian Malton <sebastian@malton.name> * Change guide demo to initialization in constructor Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
e188cf45e6
commit
6be465858b
14 files changed
+375
-52
No files matched your search
+19
-21
@@ -42,35 +42,33 @@ function getSubFrames(): ClusterFrameInfo[] {
|
||||
return toJS(Array.from(clusterFrameMap.values()), { recurseEverything: true });
|
||||
}
|
||||
|
||||
export async function broadcastMessage(channel: string, ...args: any[]) {
|
||||
export function broadcastMessage(channel: string, ...args: any[]) {
|
||||
const views = (webContents || remote?.webContents)?.getAllWebContents();
|
||||
|
||||
if (!views) return;
|
||||
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(channel, ...args);
|
||||
} else if (ipcMain) {
|
||||
ipcMain.emit(channel, ...args);
|
||||
}
|
||||
ipcRenderer?.send(channel, ...args);
|
||||
ipcMain?.emit(channel, ...args);
|
||||
|
||||
for (const view of views) {
|
||||
const type = view.getType();
|
||||
const subFramesP = ipcRenderer
|
||||
? requestMain(subFramesChannel)
|
||||
: Promise.resolve(getSubFrames());
|
||||
|
||||
logger.silly(`[IPC]: broadcasting "${channel}" to ${type}=${view.id}`, { args });
|
||||
view.send(channel, ...args);
|
||||
subFramesP
|
||||
.then(subFrames => {
|
||||
for (const view of views) {
|
||||
try {
|
||||
logger.silly(`[IPC]: broadcasting "${channel}" to ${view.getType()}=${view.id}`, { args });
|
||||
view.send(channel, ...args);
|
||||
|
||||
try {
|
||||
const subFrames: ClusterFrameInfo[] = ipcRenderer
|
||||
? await requestMain(subFramesChannel)
|
||||
: getSubFrames();
|
||||
|
||||
for (const frameInfo of subFrames) {
|
||||
view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args);
|
||||
for (const frameInfo of subFrames) {
|
||||
view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("[IPC]: failed to send IPC message", { error: String(error) });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("[IPC]: failed to send IPC message", { error: String(error) });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) {
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ipcMain } from "electron";
|
||||
import { EventEmitter } from "events";
|
||||
import logger from "../../main/logger";
|
||||
import { Disposer } from "../utils";
|
||||
|
||||
export type HandlerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
|
||||
export type ListenerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
|
||||
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
|
||||
export type Rest<T> = T extends [any, ...infer R] ? R : [];
|
||||
|
||||
@@ -34,22 +36,22 @@ export type Rest<T> = T extends [any, ...infer R] ? R : [];
|
||||
* @param verifier The function to be called to verify that the args are the correct type
|
||||
*/
|
||||
export function onceCorrect<
|
||||
EM extends EventEmitter,
|
||||
L extends (event: HandlerEvent<EM>, ...args: any[]) => any
|
||||
IPC extends EventEmitter,
|
||||
Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any
|
||||
>({
|
||||
source,
|
||||
channel,
|
||||
listener,
|
||||
verifier,
|
||||
}: {
|
||||
source: EM,
|
||||
channel: string | symbol,
|
||||
listener: L,
|
||||
verifier: ListVerifier<Rest<Parameters<L>>>,
|
||||
source: IPC,
|
||||
channel: string,
|
||||
listener: Listener,
|
||||
verifier: ListVerifier<Rest<Parameters<Listener>>>,
|
||||
}): void {
|
||||
function handler(event: HandlerEvent<EM>, ...args: unknown[]): void {
|
||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]): void {
|
||||
if (verifier(args)) {
|
||||
source.removeListener(channel, handler); // remove immediately
|
||||
source.removeListener(channel, wrappedListener); // remove immediately
|
||||
|
||||
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
|
||||
.catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error }));
|
||||
@@ -58,7 +60,7 @@ export function onceCorrect<
|
||||
}
|
||||
}
|
||||
|
||||
source.on(channel, handler);
|
||||
source.on(channel, wrappedListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,25 +70,53 @@ export function onceCorrect<
|
||||
* @param verifier The function to be called to verify that the args are the correct type
|
||||
*/
|
||||
export function onCorrect<
|
||||
EM extends EventEmitter,
|
||||
L extends (event: HandlerEvent<EM>, ...args: any[]) => any
|
||||
IPC extends EventEmitter,
|
||||
Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any
|
||||
>({
|
||||
source,
|
||||
channel,
|
||||
listener,
|
||||
verifier,
|
||||
}: {
|
||||
source: EM,
|
||||
channel: string | symbol,
|
||||
listener: L,
|
||||
verifier: ListVerifier<Rest<Parameters<L>>>,
|
||||
}): void {
|
||||
source.on(channel, (event, ...args: unknown[]) => {
|
||||
source: IPC,
|
||||
channel: string,
|
||||
listener: Listener,
|
||||
verifier: ListVerifier<Rest<Parameters<Listener>>>,
|
||||
}): Disposer {
|
||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]) {
|
||||
if (verifier(args)) {
|
||||
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
|
||||
.catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error }));
|
||||
} else {
|
||||
logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
source.on(channel, wrappedListener);
|
||||
|
||||
return () => source.off(channel, wrappedListener);
|
||||
}
|
||||
|
||||
export function handleCorrect<
|
||||
Handler extends (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any,
|
||||
>({
|
||||
channel,
|
||||
handler,
|
||||
verifier,
|
||||
}: {
|
||||
channel: string,
|
||||
handler: Handler,
|
||||
verifier: ListVerifier<Rest<Parameters<Handler>>>,
|
||||
}): Disposer {
|
||||
function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType<Handler> {
|
||||
if (verifier(args)) {
|
||||
return handler(event, ...args);
|
||||
}
|
||||
|
||||
throw new TypeError(`Invalid args for invoke on channel: ${channel}`);
|
||||
}
|
||||
|
||||
ipcMain.handle(channel, wrappedHandler);
|
||||
|
||||
return () => ipcMain.removeHandler(channel);
|
||||
}
|
||||
Reference in new issue
Block a user