mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove old implementation of messaging
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
a8e5777b83
commit
8bc5ef5a27
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
|
||||
export interface Channel<MessageTemplate = void, ReturnTemplate = void> {
|
||||
id: string;
|
||||
_messageTemplate?: MessageTemplate;
|
||||
_returnTemplate?: ReturnTemplate;
|
||||
}
|
||||
|
||||
@ -1,245 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { SendMessageToChannel } from "./message-to-channel-injection-token";
|
||||
import { sendMessageToChannelInjectionToken } from "./message-to-channel-injection-token";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import type { MessageChannel } from "./message-channel-listener-injection-token";
|
||||
import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token";
|
||||
import type { RequestFromChannel } from "./request-from-channel-injection-token";
|
||||
import { requestFromChannelInjectionToken } from "./request-from-channel-injection-token";
|
||||
import type { RequestChannel } from "./request-channel-listener-injection-token";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import { getPromiseStatus } from "@k8slens/test-utils";
|
||||
import { runInAction } from "mobx";
|
||||
import type { RequestChannelHandler } from "../../../main/utils/channel/channel-listeners/listener-tokens";
|
||||
import {
|
||||
getRequestChannelListenerInjectable,
|
||||
requestChannelListenerInjectionToken,
|
||||
} from "../../../main/utils/channel/channel-listeners/listener-tokens";
|
||||
|
||||
type TestMessageChannel = MessageChannel<string>;
|
||||
type TestRequestChannel = RequestChannel<string, string>;
|
||||
|
||||
describe("channel", () => {
|
||||
describe("messaging from main to renderer, given listener for channel in a window and application has started", () => {
|
||||
let messageListenerInWindowMock: jest.Mock;
|
||||
let mainDi: DiContainer;
|
||||
let messageToChannel: SendMessageToChannel;
|
||||
let builder: ApplicationBuilder;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
messageListenerInWindowMock = jest.fn();
|
||||
|
||||
const testChannelListenerInTestWindowInjectable = getInjectable({
|
||||
id: "test-channel-listener-in-test-window",
|
||||
|
||||
instantiate: () => ({
|
||||
channel: testMessageChannel,
|
||||
handler: messageListenerInWindowMock,
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
builder.beforeWindowStart(({ windowDi }) => {
|
||||
runInAction(() => {
|
||||
windowDi.register(testChannelListenerInTestWindowInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
mainDi = builder.mainDi;
|
||||
|
||||
await builder.startHidden();
|
||||
|
||||
messageToChannel = mainDi.inject(sendMessageToChannelInjectionToken);
|
||||
});
|
||||
|
||||
describe("given window is started", () => {
|
||||
let someWindowFake: LensWindow;
|
||||
|
||||
beforeEach(async () => {
|
||||
someWindowFake = builder.applicationWindow.create("some-window");
|
||||
|
||||
await someWindowFake.start();
|
||||
});
|
||||
|
||||
it("when sending message, triggers listener in window", () => {
|
||||
messageToChannel(testMessageChannel, "some-message");
|
||||
|
||||
expect(messageListenerInWindowMock).toHaveBeenCalledWith("some-message");
|
||||
});
|
||||
|
||||
it("given window is hidden, when sending message, does not trigger listener in window", () => {
|
||||
someWindowFake.close();
|
||||
|
||||
messageToChannel(testMessageChannel, "some-message");
|
||||
|
||||
expect(messageListenerInWindowMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("given multiple started windows, when sending message, triggers listeners in all windows", async () => {
|
||||
const someWindowFake = builder.applicationWindow.create("some-window");
|
||||
const someOtherWindowFake = builder.applicationWindow.create("some-other-window");
|
||||
|
||||
await someWindowFake.start();
|
||||
await someOtherWindowFake.start();
|
||||
|
||||
messageToChannel(testMessageChannel, "some-message");
|
||||
|
||||
expect(messageListenerInWindowMock.mock.calls).toEqual([
|
||||
["some-message"],
|
||||
["some-message"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("messaging from renderer to main, given listener for channel in a main and application has started", () => {
|
||||
let messageListenerInMainMock: jest.Mock;
|
||||
let messageToChannel: SendMessageToChannel;
|
||||
|
||||
beforeEach(async () => {
|
||||
const applicationBuilder = getApplicationBuilder();
|
||||
|
||||
messageListenerInMainMock = jest.fn();
|
||||
|
||||
const testChannelListenerInMainInjectable = getInjectable({
|
||||
id: "test-channel-listener-in-main",
|
||||
|
||||
instantiate: () => ({
|
||||
channel: testMessageChannel,
|
||||
handler: messageListenerInMainMock,
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
runInAction(() => {
|
||||
mainDi.register(testChannelListenerInMainInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const windowDi = applicationBuilder.applicationWindow.only.di;
|
||||
|
||||
messageToChannel = windowDi.inject(sendMessageToChannelInjectionToken);
|
||||
});
|
||||
|
||||
it("when sending message, triggers listener in main", () => {
|
||||
messageToChannel(testMessageChannel, "some-message");
|
||||
|
||||
expect(messageListenerInMainMock).toHaveBeenCalledWith("some-message");
|
||||
});
|
||||
});
|
||||
|
||||
describe("requesting from main in renderer, given listener for channel in a main and application has started", () => {
|
||||
let requestListenerInMainMock: AsyncFnMock<RequestChannelHandler<TestRequestChannel>>;
|
||||
let requestFromChannel: RequestFromChannel;
|
||||
|
||||
beforeEach(async () => {
|
||||
const applicationBuilder = getApplicationBuilder();
|
||||
|
||||
requestListenerInMainMock = asyncFn();
|
||||
|
||||
const testChannelListenerInMainInjectable = getRequestChannelListenerInjectable({
|
||||
channel: testRequestChannel,
|
||||
handler: () => requestListenerInMainMock,
|
||||
});
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
runInAction(() => {
|
||||
mainDi.register(testChannelListenerInMainInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const windowDi = applicationBuilder.applicationWindow.only.di;
|
||||
|
||||
requestFromChannel = windowDi.inject(
|
||||
requestFromChannelInjectionToken,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when requesting from channel", () => {
|
||||
let actualPromise: Promise<string>;
|
||||
|
||||
beforeEach(() => {
|
||||
actualPromise = requestFromChannel(testRequestChannel, "some-request");
|
||||
});
|
||||
|
||||
it("triggers listener in main", () => {
|
||||
expect(requestListenerInMainMock).toHaveBeenCalledWith("some-request");
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("when main resolves with response, resolves with response", async () => {
|
||||
await requestListenerInMainMock.resolve("some-response");
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe("some-response");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("when registering multiple handlers for the same channel, throws", async () => {
|
||||
const applicationBuilder = getApplicationBuilder();
|
||||
|
||||
const someChannelListenerInjectable = getInjectable({
|
||||
id: "some-channel-listener",
|
||||
|
||||
instantiate: () => ({
|
||||
channel: testRequestChannel,
|
||||
handler: () => () => "irrelevant",
|
||||
}),
|
||||
|
||||
injectionToken: requestChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
const someOtherChannelListenerInjectable = getInjectable({
|
||||
id: "some-other-channel-listener",
|
||||
|
||||
instantiate: () => ({
|
||||
channel: testRequestChannel,
|
||||
handler: () => () => "irrelevant",
|
||||
}),
|
||||
|
||||
injectionToken: requestChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
runInAction(() => {
|
||||
mainDi.register(someChannelListenerInjectable);
|
||||
mainDi.register(someOtherChannelListenerInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
await expect(applicationBuilder.render()).rejects.toThrow('Tried to register a multiple channel handlers for "some-request-channel-id", only one handler is supported for a request channel.');
|
||||
});
|
||||
});
|
||||
|
||||
const testMessageChannel: TestMessageChannel = {
|
||||
id: "some-message-channel-id",
|
||||
};
|
||||
|
||||
const testRequestChannel: TestRequestChannel = {
|
||||
id: "some-request-channel-id",
|
||||
};
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import type { MessageChannel, MessageChannelListener } from "./message-channel-listener-injection-token";
|
||||
|
||||
export type EnlistMessageChannelListener = (listener: MessageChannelListener<MessageChannel<unknown>>) => Disposer;
|
||||
|
||||
export const enlistMessageChannelListenerInjectionToken = getInjectionToken<EnlistMessageChannelListener>({
|
||||
id: "enlist-message-channel-listener",
|
||||
});
|
||||
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { getStartableStoppable } from "@k8slens/startable-stoppable";
|
||||
import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "./enlist-message-channel-listener-injection-token";
|
||||
import { disposer } from "@k8slens/utilities";
|
||||
|
||||
const listeningOnMessageChannelsInjectable = getInjectable({
|
||||
id: "listening-on-message-channels",
|
||||
|
||||
instantiate: (di) => {
|
||||
const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken);
|
||||
const messageChannelListeners = di.injectMany(messageChannelListenerInjectionToken);
|
||||
|
||||
return getStartableStoppable("listening-on-channels", () => (
|
||||
disposer(messageChannelListeners.map(enlistMessageChannelListener))
|
||||
));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export default listeningOnMessageChannelsInjectable;
|
||||
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainerForInjection } from "@ogre-tools/injectable";
|
||||
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||
|
||||
export interface MessageChannel<Message> {
|
||||
id: string;
|
||||
_messageSignature?: Message; // only used to mark `Message` as used
|
||||
}
|
||||
|
||||
export type MessageChannelHandler<Channel> = Channel extends MessageChannel<infer Message>
|
||||
? (message: Message) => void
|
||||
: never;
|
||||
|
||||
export interface MessageChannelListener<Channel> {
|
||||
channel: Channel;
|
||||
handler: MessageChannelHandler<Channel>;
|
||||
}
|
||||
|
||||
export const messageChannelListenerInjectionToken = getInjectionToken<MessageChannelListener<MessageChannel<unknown>>>(
|
||||
{
|
||||
id: "message-channel-listener",
|
||||
},
|
||||
);
|
||||
|
||||
export interface GetMessageChannelListenerInfo<
|
||||
Channel extends MessageChannel<Message>,
|
||||
Message,
|
||||
> {
|
||||
id: string;
|
||||
channel: Channel;
|
||||
handler: (di: DiContainerForInjection) => MessageChannelHandler<Channel>;
|
||||
causesSideEffects?: boolean;
|
||||
}
|
||||
|
||||
export function getMessageChannelListenerInjectable<
|
||||
Channel extends MessageChannel<Message>,
|
||||
Message,
|
||||
>(info: GetMessageChannelListenerInfo<Channel, Message>) {
|
||||
return getInjectable({
|
||||
id: `${info.channel.id}-listener-${info.id}`,
|
||||
instantiate: (di) => ({
|
||||
channel: info.channel,
|
||||
handler: info.handler(di),
|
||||
}),
|
||||
injectionToken: messageChannelListenerInjectionToken,
|
||||
causesSideEffects: info.causesSideEffects,
|
||||
});
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { MessageChannel } from "./message-channel-listener-injection-token";
|
||||
|
||||
export interface SendMessageToChannel {
|
||||
(channel: MessageChannel<void>): void;
|
||||
<Message>(channel: MessageChannel<Message>, message: Message): void;
|
||||
}
|
||||
|
||||
export type MessageChannelSender<Channel> = Channel extends MessageChannel<void | undefined>
|
||||
? () => void
|
||||
: Channel extends MessageChannel<infer Message>
|
||||
? (message: Message) => void
|
||||
: never;
|
||||
|
||||
export const sendMessageToChannelInjectionToken = getInjectionToken<SendMessageToChannel>({
|
||||
id: "send-message-to-message-channel",
|
||||
});
|
||||
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface RequestChannel<Request, Response> {
|
||||
id: string;
|
||||
_requestSignature?: Request; // used only to mark `Request` as "used"
|
||||
_responseSignature?: Response; // used only to mark `Response` as "used"
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RequestChannel } from "./request-channel-listener-injection-token";
|
||||
|
||||
export interface RequestFromChannel {
|
||||
<Request, Response>(channel: RequestChannel<Request, Response>, request: Request): Promise<Awaited<Response>>;
|
||||
<Response>(channel: RequestChannel<void, Response>): Promise<Awaited<Response>>;
|
||||
}
|
||||
|
||||
export type ChannelRequester<Channel> = Channel extends RequestChannel<infer Request, infer Response>
|
||||
? (req: Request) => Promise<Awaited<Response>>
|
||||
: never;
|
||||
|
||||
export const requestFromChannelInjectionToken = getInjectionToken<RequestFromChannel>({
|
||||
id: "request-from-request-channel",
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IpcMainEvent } from "electron";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
|
||||
const enlistMessageChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-message-channel-listener-for-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeOnCallback = (_: IpcMainEvent, message: unknown) => {
|
||||
handler(message);
|
||||
};
|
||||
|
||||
ipcMain.on(channel.id, nativeOnCallback);
|
||||
|
||||
return () => {
|
||||
ipcMain.off(channel.id, nativeOnCallback);
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: enlistMessageChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default enlistMessageChannelListenerInjectable;
|
||||
@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import type { EnlistMessageChannelListener } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import type { IpcMain, IpcMainEvent } from "electron";
|
||||
|
||||
describe("enlist message channel listener in main", () => {
|
||||
let enlistMessageChannelListener: EnlistMessageChannelListener;
|
||||
let ipcMainStub: IpcMain;
|
||||
let onMock: jest.Mock;
|
||||
let offMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
onMock = jest.fn();
|
||||
offMock = jest.fn();
|
||||
|
||||
ipcMainStub = {
|
||||
on: onMock,
|
||||
off: offMock,
|
||||
} as unknown as IpcMain;
|
||||
|
||||
di.override(ipcMainInjectable, () => ipcMainStub);
|
||||
|
||||
enlistMessageChannelListener = di.inject(
|
||||
enlistMessageChannelListenerInjectionToken,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let handlerMock: jest.Mock;
|
||||
let disposer: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
handlerMock = jest.fn();
|
||||
|
||||
disposer = enlistMessageChannelListener({
|
||||
channel: { id: "some-channel-id" },
|
||||
handler: handlerMock,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call handler yet", () => {
|
||||
expect(handlerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers the listener", () => {
|
||||
expect(onMock).toHaveBeenCalledWith(
|
||||
"some-channel-id",
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not de-register the listener yet", () => {
|
||||
expect(offMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when message arrives", () => {
|
||||
beforeEach(() => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, "some-message");
|
||||
});
|
||||
|
||||
it("calls the handler with the message", () => {
|
||||
expect(handlerMock).toHaveBeenCalledWith("some-message");
|
||||
});
|
||||
|
||||
it("when disposing the listener, de-registers the listener", () => {
|
||||
disposer();
|
||||
|
||||
expect(offMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, 42);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("given boolean as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, true);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("given object as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcMainEvent, { some: "object" });
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith({ some: "object" });
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IpcMainInvokeEvent } from "electron";
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
import type { RequestChannelListener } from "./listener-tokens";
|
||||
import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token";
|
||||
|
||||
export type EnlistRequestChannelListener = <TChannel extends RequestChannel<unknown, unknown>>(listener: RequestChannelListener<TChannel>) => Disposer;
|
||||
|
||||
const enlistRequestChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-request-channel-listener-for-main",
|
||||
|
||||
instantiate: (di): EnlistRequestChannelListener => {
|
||||
const ipcMain = di.inject(ipcMainInjectionToken);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeHandleCallback = (_: IpcMainInvokeEvent, request: unknown) => handler(request);
|
||||
|
||||
ipcMain.handle(channel.id, nativeHandleCallback);
|
||||
|
||||
return () => {
|
||||
ipcMain.off(channel.id, nativeHandleCallback);
|
||||
};
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default enlistRequestChannelListenerInjectable;
|
||||
@ -1,153 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import ipcMainInjectable from "../ipc-main/ipc-main.injectable";
|
||||
import type { IpcMain, IpcMainInvokeEvent } from "electron";
|
||||
import { getPromiseStatus } from "@k8slens/test-utils";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
import type { EnlistRequestChannelListener } from "./enlist-request-channel-listener.injectable";
|
||||
import enlistRequestChannelListenerInjectable from "./enlist-request-channel-listener.injectable";
|
||||
import type { RequestChannelHandler } from "./listener-tokens";
|
||||
|
||||
type TestRequestChannel = RequestChannel<unknown, unknown>;
|
||||
|
||||
const testRequestChannel: TestRequestChannel = {
|
||||
id: "some-channel-id",
|
||||
};
|
||||
|
||||
describe("enlist request channel listener in main", () => {
|
||||
let enlistRequestChannelListener: EnlistRequestChannelListener;
|
||||
let ipcMainStub: IpcMain;
|
||||
let handleMock: jest.Mock;
|
||||
let offMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
handleMock = jest.fn();
|
||||
offMock = jest.fn();
|
||||
|
||||
ipcMainStub = {
|
||||
handle: handleMock,
|
||||
off: offMock,
|
||||
} as unknown as IpcMain;
|
||||
|
||||
di.override(ipcMainInjectable, () => ipcMainStub);
|
||||
|
||||
enlistRequestChannelListener = di.inject(enlistRequestChannelListenerInjectable);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let handlerMock: AsyncFnMock<RequestChannelHandler<TestRequestChannel>>;
|
||||
let disposer: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
handlerMock = asyncFn();
|
||||
|
||||
disposer = enlistRequestChannelListener({
|
||||
channel: testRequestChannel,
|
||||
handler: handlerMock,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call handler yet", () => {
|
||||
expect(handlerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers the listener", () => {
|
||||
expect(handleMock).toHaveBeenCalledWith(
|
||||
"some-channel-id",
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not de-register the listener yet", () => {
|
||||
expect(offMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when request arrives", () => {
|
||||
let actualPromise: Promise<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
actualPromise = handleMock.mock.calls[0][1](
|
||||
{} as IpcMainInvokeEvent,
|
||||
"some-request",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls the handler with the request", () => {
|
||||
expect(handlerMock).toHaveBeenCalledWith("some-request");
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
describe("when handler resolves with response, listener resolves with the response", () => {
|
||||
beforeEach(async () => {
|
||||
await handlerMock.resolve("some-response");
|
||||
});
|
||||
|
||||
it("resolves with the response", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe("some-response");
|
||||
});
|
||||
|
||||
it("when disposing the listener, de-registers the listener", () => {
|
||||
disposer();
|
||||
|
||||
expect(offMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as response, when handler resolves with response, listener resolves with stringified response", async () => {
|
||||
await handlerMock.resolve(42);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(42);
|
||||
});
|
||||
|
||||
it("given boolean as response, when handler resolves with response, listener resolves with stringified response", async () => {
|
||||
await handlerMock.resolve(true);
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(true);
|
||||
});
|
||||
|
||||
it("given object as response, when handler resolves with response, listener resolves with response", async () => {
|
||||
await handlerMock.resolve({ some: "object" });
|
||||
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toEqual({ some: "object" });
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, 42);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("given boolean as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, true);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("given object as request, when request arrives, calls the handler with the request", () => {
|
||||
handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, { some: "object" });
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith({ some: "object" });
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { DiContainerForInjection } from "@ogre-tools/injectable";
|
||||
import { getInjectable, getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
|
||||
export type RequestChannelHandler<Channel> = Channel extends RequestChannel<infer Request, infer Response>
|
||||
? (req: Request) => Promise<Response> | Response
|
||||
: never;
|
||||
|
||||
export interface RequestChannelListener<Channel> {
|
||||
channel: Channel;
|
||||
handler: RequestChannelHandler<Channel>;
|
||||
}
|
||||
|
||||
|
||||
export const requestChannelListenerInjectionToken = getInjectionToken<RequestChannelListener<RequestChannel<unknown, unknown>>>( {
|
||||
id: "request-channel-listener",
|
||||
});
|
||||
|
||||
export interface GetRequestChannelListenerInjectableInfo<
|
||||
Channel extends RequestChannel<Request, Response>,
|
||||
Request,
|
||||
Response,
|
||||
> {
|
||||
channel: Channel;
|
||||
handler: (di: DiContainerForInjection) => RequestChannelHandler<Channel>;
|
||||
}
|
||||
|
||||
export function getRequestChannelListenerInjectable<
|
||||
Channel extends RequestChannel<Request, Response>,
|
||||
Request,
|
||||
Response,
|
||||
>(info: GetRequestChannelListenerInjectableInfo<Channel, Request, Response>) {
|
||||
return getInjectable({
|
||||
id: `${info.channel.id}-listener`,
|
||||
instantiate: (di) => ({
|
||||
channel: info.channel,
|
||||
handler: info.handler(di),
|
||||
}),
|
||||
injectionToken: requestChannelListenerInjectionToken,
|
||||
});
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { disposer } from "@k8slens/utilities";
|
||||
import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token";
|
||||
import { getStartableStoppable } from "@k8slens/startable-stoppable";
|
||||
import enlistRequestChannelListenerInjectable from "./enlist-request-channel-listener.injectable";
|
||||
import { requestChannelListenerInjectionToken } from "./listener-tokens";
|
||||
|
||||
const listeningOnRequestChannelsInjectable = getInjectable({
|
||||
id: "listening-on-request-channels",
|
||||
instantiate: (di) => {
|
||||
const enlistRequestChannelListener = di.inject(enlistRequestChannelListenerInjectable);
|
||||
const requestChannelListeners = di.injectMany(requestChannelListenerInjectionToken);
|
||||
|
||||
return getStartableStoppable("listening-on-request-channels", () => {
|
||||
const seenChannels = new Set<RequestChannel<unknown, unknown>>();
|
||||
|
||||
for (const listener of requestChannelListeners) {
|
||||
if (seenChannels.has(listener.channel)) {
|
||||
throw new Error(`Tried to register a multiple channel handlers for "${listener.channel.id}", only one handler is supported for a request channel.`);
|
||||
}
|
||||
|
||||
seenChannels.add(listener.channel);
|
||||
}
|
||||
|
||||
return disposer(requestChannelListeners.map(enlistRequestChannelListener));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default listeningOnRequestChannelsInjectable;
|
||||
@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "@k8slens/application";
|
||||
import listeningOnMessageChannelsInjectable from "../../../../common/utils/channel/listening-on-message-channels.injectable";
|
||||
import listeningOnRequestChannelsInjectable from "./listening-on-request-channels.injectable";
|
||||
|
||||
const startListeningOnChannelsInjectable = getInjectable({
|
||||
id: "start-listening-on-channels-main",
|
||||
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const listeningOnMessageChannels = di.inject(listeningOnMessageChannelsInjectable);
|
||||
const listeningOnRequestChannels = di.inject(listeningOnRequestChannelsInjectable);
|
||||
|
||||
listeningOnMessageChannels.start();
|
||||
listeningOnRequestChannels.start();
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default startListeningOnChannelsInjectable;
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { SendMessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import getVisibleWindowsInjectable from "../../start-main-application/lens-window/get-visible-windows.injectable";
|
||||
import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
|
||||
|
||||
const messageToChannelInjectable = getInjectable({
|
||||
id: "message-to-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getVisibleWindows = di.inject(getVisibleWindowsInjectable);
|
||||
const clusterFrames = di.inject(clusterFramesInjectable);
|
||||
|
||||
return ((channel, data) => {
|
||||
for (const window of getVisibleWindows()) {
|
||||
window.send({ channel: channel.id, data });
|
||||
|
||||
clusterFrames.forEach(frameInfo => {
|
||||
window.send({ channel: channel.id, data, frameInfo });
|
||||
});
|
||||
}
|
||||
}) as SendMessageToChannel;
|
||||
},
|
||||
|
||||
injectionToken: sendMessageToChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default messageToChannelInjectable;
|
||||
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import getVisibleWindowsInjectable from "../../start-main-application/lens-window/get-visible-windows.injectable";
|
||||
import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
|
||||
import type { MessageChannel } from "../../../common/utils/channel/message-channel-listener-injection-token";
|
||||
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { ClusterFrameInfo } from "../../../common/cluster-frames.injectable";
|
||||
|
||||
describe("message-to-channel", () => {
|
||||
let di: DiContainer;
|
||||
let sendToWindowMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting();
|
||||
|
||||
sendToWindowMock = jest.fn();
|
||||
|
||||
di.override(getVisibleWindowsInjectable, () => () => [
|
||||
{
|
||||
id: "some-window",
|
||||
send: sendToWindowMock,
|
||||
show: () => {},
|
||||
reload: () => {},
|
||||
isStarting: false,
|
||||
start: async () => {},
|
||||
close: () => {},
|
||||
isVisible: true,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-other-window",
|
||||
send: sendToWindowMock,
|
||||
show: () => {},
|
||||
reload: () => {},
|
||||
isStarting: false,
|
||||
start: async () => {},
|
||||
close: () => {},
|
||||
isVisible: true,
|
||||
},
|
||||
]);
|
||||
|
||||
di.override(
|
||||
clusterFramesInjectable,
|
||||
() =>
|
||||
new Map<string, ClusterFrameInfo>([
|
||||
[
|
||||
"some-cluster-id",
|
||||
{ frameId: 42, processId: 84 },
|
||||
],
|
||||
[
|
||||
"some-other-cluster-id",
|
||||
{ frameId: 126, processId: 168 },
|
||||
],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
describe("when sending message", () => {
|
||||
beforeEach(() => {
|
||||
const sendMessageToChannel = di.inject(
|
||||
sendMessageToChannelInjectionToken,
|
||||
);
|
||||
|
||||
sendMessageToChannel(someChannel, 42);
|
||||
});
|
||||
|
||||
it("sends to each window and cluster frames", () => {
|
||||
expect(sendToWindowMock.mock.calls).toEqual([
|
||||
[{ channel: "some-channel-id", data: 42 }],
|
||||
|
||||
[
|
||||
{
|
||||
channel: "some-channel-id",
|
||||
data: 42,
|
||||
frameInfo: { frameId: 42, processId: 84 },
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
{
|
||||
channel: "some-channel-id",
|
||||
data: 42,
|
||||
frameInfo: { frameId: 126, processId: 168 },
|
||||
},
|
||||
],
|
||||
|
||||
[{ channel: "some-channel-id", data: 42 }],
|
||||
|
||||
[
|
||||
{
|
||||
channel: "some-channel-id",
|
||||
data: 42,
|
||||
frameInfo: { frameId: 42, processId: 84 },
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
{
|
||||
channel: "some-channel-id",
|
||||
data: 42,
|
||||
frameInfo: { frameId: 126, processId: 168 },
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const someChannel: MessageChannel<number> = {
|
||||
id: "some-channel-id",
|
||||
};
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import ipcRendererInjectable from "../ipc-renderer.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IpcRendererEvent } from "electron";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
|
||||
const enlistMessageChannelListenerInjectable = getInjectable({
|
||||
id: "enlist-message-channel-listener-for-renderer",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
|
||||
return ({ channel, handler }) => {
|
||||
const nativeCallback = (_: IpcRendererEvent, message: unknown) => {
|
||||
handler(message);
|
||||
};
|
||||
|
||||
ipcRenderer.on(channel.id, nativeCallback);
|
||||
|
||||
return () => {
|
||||
ipcRenderer.off(channel.id, nativeCallback);
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: enlistMessageChannelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default enlistMessageChannelListenerInjectable;
|
||||
@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import type { EnlistMessageChannelListener } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token";
|
||||
import type { IpcRendererEvent, IpcRenderer } from "electron";
|
||||
import ipcRendererInjectable from "../ipc-renderer.injectable";
|
||||
|
||||
describe("enlist message channel listener in renderer", () => {
|
||||
let enlistMessageChannelListener: EnlistMessageChannelListener;
|
||||
let ipcRendererStub: IpcRenderer;
|
||||
let onMock: jest.Mock;
|
||||
let offMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
onMock = jest.fn();
|
||||
offMock = jest.fn();
|
||||
|
||||
ipcRendererStub = {
|
||||
on: onMock,
|
||||
off: offMock,
|
||||
} as unknown as IpcRenderer;
|
||||
|
||||
di.override(ipcRendererInjectable, () => ipcRendererStub);
|
||||
|
||||
enlistMessageChannelListener = di.inject(
|
||||
enlistMessageChannelListenerInjectionToken,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let handlerMock: jest.Mock;
|
||||
let disposer: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
handlerMock = jest.fn();
|
||||
|
||||
disposer = enlistMessageChannelListener({
|
||||
channel: { id: "some-channel-id" },
|
||||
handler: handlerMock,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not call handler yet", () => {
|
||||
expect(handlerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("registers the listener", () => {
|
||||
expect(onMock).toHaveBeenCalledWith(
|
||||
"some-channel-id",
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not de-register the listener yet", () => {
|
||||
expect(offMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when message arrives", () => {
|
||||
beforeEach(() => {
|
||||
onMock.mock.calls[0][1]({} as IpcRendererEvent, "some-message");
|
||||
});
|
||||
|
||||
it("calls the handler with the message", () => {
|
||||
expect(handlerMock).toHaveBeenCalledWith("some-message");
|
||||
});
|
||||
|
||||
it("when disposing the listener, de-registers the listener", () => {
|
||||
disposer();
|
||||
|
||||
expect(offMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
it("given number as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcRendererEvent, 42);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("given boolean as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcRendererEvent, true);
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("given object as message, when message arrives, calls the handler with the message", () => {
|
||||
onMock.mock.calls[0][1]({} as IpcRendererEvent, { some: "object" });
|
||||
|
||||
expect(handlerMock).toHaveBeenCalledWith({ some: "object" });
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsSecondInjectionToken } from "../../../before-frame-starts/tokens";
|
||||
import listeningOnMessageChannelsInjectable from "../../../../common/utils/channel/listening-on-message-channels.injectable";
|
||||
|
||||
const startListeningOfChannelsInjectable = getInjectable({
|
||||
id: "start-listening-of-channels-renderer",
|
||||
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const listeningOfChannels = di.inject(listeningOnMessageChannelsInjectable);
|
||||
|
||||
listeningOfChannels.start();
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsSecondInjectionToken,
|
||||
});
|
||||
|
||||
export default startListeningOfChannelsInjectable;
|
||||
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { SendMessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import sendToMainInjectable from "./send-to-main.injectable";
|
||||
|
||||
const messageToChannelInjectable = getInjectable({
|
||||
id: "message-to-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const sendToMain = di.inject(sendToMainInjectable);
|
||||
|
||||
return ((channel, message) => {
|
||||
sendToMain(channel.id, message);
|
||||
}) as SendMessageToChannel;
|
||||
},
|
||||
|
||||
injectionToken: sendMessageToChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default messageToChannelInjectable;
|
||||
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import ipcRendererInjectable from "./ipc-renderer.injectable";
|
||||
import type { RequestFromChannel } from "../../../common/utils/channel/request-from-channel-injection-token";
|
||||
import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token";
|
||||
|
||||
const requestFromChannelInjectable = getInjectable({
|
||||
id: "request-from-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
|
||||
return ((channel, request) => ipcRenderer.invoke(channel.id, request)) as RequestFromChannel;
|
||||
},
|
||||
|
||||
injectionToken: requestFromChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default requestFromChannelInjectable;
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import ipcRendererInjectable from "./ipc-renderer.injectable";
|
||||
|
||||
const sendToMainInjectable = getInjectable({
|
||||
id: "send-to-main",
|
||||
|
||||
instantiate: (di) => {
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
|
||||
return (channelId: string, message: any) => {
|
||||
ipcRenderer.send(channelId, message);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default sendToMainInjectable;
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import { overrideMessagingFromMainToWindow } from "./override-messaging-from-main-to-window";
|
||||
import { overrideMessagingFromWindowToMain } from "./override-messaging-from-window-to-main";
|
||||
import { overrideRequestingFromWindowToMain } from "./override-requesting-from-window-to-main";
|
||||
|
||||
export interface OverrideChannels {
|
||||
overrideForWindow: (windowDi: DiContainer, windowId: string) => void;
|
||||
sendToWindow: (windowId: string, args: SendToViewArgs) => void;
|
||||
}
|
||||
|
||||
export const overrideChannels = (mainDi: DiContainer): OverrideChannels => {
|
||||
const { overrideEnlistForWindow, sendToWindow } = overrideMessagingFromMainToWindow();
|
||||
const overrideMessagingFromWindowToForWindow = overrideMessagingFromWindowToMain(mainDi);
|
||||
const overrideRequestingFromWindowToMainForWindow = overrideRequestingFromWindowToMain(mainDi);
|
||||
|
||||
return {
|
||||
overrideForWindow: (windowDi, windowId) => {
|
||||
overrideEnlistForWindow(windowDi, windowId);
|
||||
overrideMessagingFromWindowToForWindow(windowDi);
|
||||
overrideRequestingFromWindowToMainForWindow(windowDi);
|
||||
},
|
||||
sendToWindow,
|
||||
};
|
||||
};
|
||||
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token";
|
||||
import enlistMessageChannelListenerInjectableInRenderer from "../../renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getOrInsert, getOrInsertSet } from "@k8slens/utilities";
|
||||
import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
|
||||
import { deserialize, serialize } from "v8";
|
||||
|
||||
type ListenerSet = Set<MessageChannelListener<any>>;
|
||||
type WindowListenerMap = Map<string, ListenerSet>;
|
||||
type ListenerFakeMap = Map<string, WindowListenerMap>;
|
||||
|
||||
export interface OverriddenWindowMessaging {
|
||||
sendToWindow(windowId: string, args: SendToViewArgs): void;
|
||||
overrideEnlistForWindow(windowDi: DiContainer, windowId: string): void;
|
||||
}
|
||||
|
||||
export const overrideMessagingFromMainToWindow = (): OverriddenWindowMessaging => {
|
||||
const messageChannelListenerFakesForRenderer: ListenerFakeMap = new Map();
|
||||
|
||||
const getWindowListeners = (channelId: string, windowId: string) => {
|
||||
const channelListeners = getOrInsert<string, WindowListenerMap>(
|
||||
messageChannelListenerFakesForRenderer,
|
||||
channelId,
|
||||
new Map(),
|
||||
);
|
||||
|
||||
return getOrInsertSet(channelListeners, windowId);
|
||||
};
|
||||
|
||||
return {
|
||||
overrideEnlistForWindow: (windowDi, windowId) => {
|
||||
windowDi.override(
|
||||
enlistMessageChannelListenerInjectableInRenderer,
|
||||
|
||||
() => (listener) => {
|
||||
const windowListeners = getWindowListeners(
|
||||
listener.channel.id,
|
||||
windowId,
|
||||
);
|
||||
|
||||
windowListeners.add(listener);
|
||||
|
||||
return () => {
|
||||
windowListeners.delete(listener);
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
sendToWindow: (windowId, { channel, data, frameInfo }) => {
|
||||
try {
|
||||
data = deserialize(serialize(data));
|
||||
} catch (error) {
|
||||
throw new Error(`Tried to send a message to channel "${channel}" that is not compatible with StructuredClone: ${error}`);
|
||||
}
|
||||
|
||||
const windowListeners = getWindowListeners(channel, windowId);
|
||||
|
||||
if (frameInfo) {
|
||||
throw new Error(
|
||||
`Tried to send message to frame "${frameInfo.frameId}" in process "${frameInfo.processId}" using channel "${channel}" which isn't supported yet.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (windowListeners.size === 0) {
|
||||
throw new Error(
|
||||
`Tried to send message to channel "${channel}" but there where no listeners. Current channels with listeners: "${[
|
||||
...messageChannelListenerFakesForRenderer.keys(),
|
||||
].join('", "')}"`,
|
||||
);
|
||||
}
|
||||
|
||||
windowListeners.forEach((listener) => listener.handler(data));
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { deserialize, serialize } from "v8";
|
||||
import type { MessageChannel, MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token";
|
||||
import enlistMessageChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable";
|
||||
import { getOrInsertSet } from "@k8slens/utilities";
|
||||
import sendToMainInjectable from "../../renderer/utils/channel/send-to-main.injectable";
|
||||
|
||||
export const overrideMessagingFromWindowToMain = (mainDi: DiContainer) => {
|
||||
const messageChannelListenerFakesForMain = new Map<
|
||||
string,
|
||||
Set<MessageChannelListener<MessageChannel<unknown>>>
|
||||
>();
|
||||
|
||||
mainDi.override(
|
||||
enlistMessageChannelListenerInjectableInMain,
|
||||
|
||||
() => (listener) => {
|
||||
const listeners = getOrInsertSet(messageChannelListenerFakesForMain, listener.channel.id);
|
||||
|
||||
listeners.add(listener);
|
||||
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return (windowDi: DiContainer) => {
|
||||
windowDi.override(sendToMainInjectable, () => (channelId, message) => {
|
||||
const listeners = messageChannelListenerFakesForMain.get(channelId);
|
||||
|
||||
if (!listeners || listeners.size === 0) {
|
||||
throw new Error(
|
||||
`Tried to send message to channel "${channelId}" but there where no listeners. Current channels with listeners: "${[
|
||||
...messageChannelListenerFakesForMain.keys(),
|
||||
].join('", "')}"`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
message = deserialize(serialize(message));
|
||||
} catch (error) {
|
||||
throw new Error(`Tried to send a message to channel "${channelId}" that is not compatible with StructuredClone: ${error}`);
|
||||
}
|
||||
|
||||
listeners.forEach((listener) => listener.handler(message));
|
||||
});
|
||||
};
|
||||
};
|
||||
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { deserialize, serialize } from "v8";
|
||||
import type { RequestChannel } from "../../common/utils/channel/request-channel-listener-injection-token";
|
||||
import type { RequestFromChannel } from "../../common/utils/channel/request-from-channel-injection-token";
|
||||
import enlistRequestChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable";
|
||||
import type { RequestChannelListener } from "../../main/utils/channel/channel-listeners/listener-tokens";
|
||||
import requestFromChannelInjectable from "../../renderer/utils/channel/request-from-channel.injectable";
|
||||
|
||||
export const overrideRequestingFromWindowToMain = (mainDi: DiContainer) => {
|
||||
const requestChannelListenerFakesForMain = new Map<
|
||||
string,
|
||||
RequestChannelListener<RequestChannel<unknown, unknown>>
|
||||
>();
|
||||
|
||||
mainDi.override(
|
||||
enlistRequestChannelListenerInjectableInMain,
|
||||
|
||||
() => (listener) => {
|
||||
if (requestChannelListenerFakesForMain.has(listener.channel.id)) {
|
||||
throw new Error(
|
||||
`Tried to enlist listener for channel "${listener.channel.id}", but it was already enlisted`,
|
||||
);
|
||||
}
|
||||
|
||||
requestChannelListenerFakesForMain.set(listener.channel.id, listener);
|
||||
|
||||
return () => {
|
||||
requestChannelListenerFakesForMain.delete(listener.channel.id);
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return (windowDi: DiContainer) => {
|
||||
windowDi.override(
|
||||
requestFromChannelInjectable,
|
||||
|
||||
() => (async (channel, request) => {
|
||||
const requestListener = requestChannelListenerFakesForMain.get(channel.id);
|
||||
|
||||
if (!requestListener) {
|
||||
throw new Error(
|
||||
`Tried to get value from channel "${channel.id}", but no listeners were registered`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
request = deserialize(serialize(request));
|
||||
} catch (error) {
|
||||
throw new Error(`Tried to request from channel "${channel.id}" with data that is not compatible with StructuredClone: ${error}`);
|
||||
}
|
||||
|
||||
return requestListener.handler(request);
|
||||
}) as RequestFromChannel,
|
||||
);
|
||||
};
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user