Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPC周りの呼び出しをdot記法で書けるように #2240

Merged
merged 8 commits into from
Aug 29, 2024
41 changes: 27 additions & 14 deletions src/backend/browser/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,32 @@ import {
// TODO: base pathを設定できるようにするか、ビルド時埋め込みにする
const toStaticPath = (fileName: string) => `/${fileName}`;

// FIXME: asを使わないようオーバーロードにした。オーバーロードも使わない書き方にしたい。
function onReceivedIPCMsg<
T extends {
[K in keyof IpcSOData]: (
event: unknown,
...args: IpcSOData[K]["args"]
) => Promise<IpcSOData[K]["return"]> | IpcSOData[K]["return"];
},
>(listeners: T): void;
function onReceivedIPCMsg(listeners: {
[key: string]: (event: unknown, ...args: unknown[]) => unknown;
}) {
// NOTE: もしブラウザ本体からレンダラへのメッセージを実装するならこんな感じ
window.addEventListener(
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
"message",
({
data,
}: MessageEvent<{
channel: keyof IpcSOData;
args: IpcSOData[keyof IpcSOData]["args"];
}>) => {
listeners[data.channel]?.({}, ...data.args);
},
);
}

/**
* Browser版のSandBox実装
* src/type/preload.tsのSandboxを変更した場合は、interfaceに追従した変更が必要
Expand Down Expand Up @@ -204,20 +230,7 @@ export const api: Sandbox = {
// NOTE: UIの表示状態の制御のためだけなので固定値を返している
return Promise.resolve(true);
},
onReceivedIPCMsg<T extends keyof IpcSOData>(
channel: T,
listener: (_: unknown, ...args: IpcSOData[T]["args"]) => void,
) {
window.addEventListener("message", (event) => {
const data = event.data as {
channel: keyof IpcSOData;
args: IpcSOData[keyof IpcSOData];
};
if (data.channel == channel) {
listener(data.args);
}
});
},
onReceivedIPCMsg,
closeWindow() {
throw new Error(`Not supported on Browser version: closeWindow`);
},
Expand Down
92 changes: 58 additions & 34 deletions src/backend/electron/ipc.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,69 @@
import { ipcMain, IpcMainInvokeEvent, BrowserWindow } from "electron";
import {
BrowserWindow,
ipcMain,
IpcMainInvokeEvent,
IpcRendererEvent,
} from "electron";
import log from "electron-log/main";
import { IpcIHData, IpcSOData } from "@/type/ipc";

export function ipcMainHandle<T extends keyof IpcIHData>(
channel: T,
listener: (
event: IpcMainInvokeEvent,
...args: IpcIHData[T]["args"]
) => IpcIHData[T]["return"] | Promise<IpcIHData[T]["return"]>,
): void;
export function ipcMainHandle(
channel: string,
listener: (event: IpcMainInvokeEvent, ...args: unknown[]) => unknown,
): void {
const errorHandledListener = (
export type IpcRendererInvoke = {
[K in keyof IpcIHData]: (
...args: IpcIHData[K]["args"]
) => Promise<IpcIHData[K]["return"]>;
};

export type IpcMainHandle = {
[K in keyof IpcIHData]: (
event: IpcMainInvokeEvent,
...args: unknown[]
) => {
try {
validateIpcSender(event);
return listener(event, ...args);
} catch (e) {
log.error(e);
}
};
ipcMain.handle(channel, errorHandledListener);
}
...args: IpcIHData[K]["args"]
) => Promise<IpcIHData[K]["return"]> | IpcIHData[K]["return"];
};

export function ipcMainSend<T extends keyof IpcSOData>(
win: BrowserWindow,
channel: T,
...args: IpcSOData[T]["args"]
export type IpcMainSend = {
[K in keyof IpcSOData]: (
win: BrowserWindow,
...args: IpcSOData[K]["args"]
) => void;
};

export type IpcRendererOn = {
[K in keyof IpcSOData]: (
event: IpcRendererEvent,
...args: IpcSOData[K]["args"]
) => Promise<IpcSOData[K]["return"]> | IpcSOData[K]["return"];
};

// FIXME: asを使わないようオーバーロードにした。オーバーロードも使わない書き方にしたい。
export function registerIpcMainHandle<T extends IpcMainHandle>(
listeners: T,
): void;
export function ipcMainSend(
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
win: BrowserWindow,
channel: string,
...args: unknown[]
): void {
win.webContents.send(channel, ...args);
export function registerIpcMainHandle(listeners: {
[key: string]: (event: IpcMainInvokeEvent, ...args: unknown[]) => unknown;
}) {
Object.entries(listeners).forEach(([channel, listener]) => {
const errorHandledListener: typeof listener = (event, ...args) => {
try {
validateIpcSender(event);
return listener(event, ...args);
} catch (e) {
log.error(e);
}
};
ipcMain.handle(channel, errorHandledListener);
});
}

export const ipcMainSendProxy = new Proxy(
{},
{
get:
(_, channel: string) =>
(win: BrowserWindow, ...args: unknown[]) =>
win.webContents.send(channel, ...args),
},
) as IpcMainSend;

/** IPCメッセージの送信元を確認する */
const validateIpcSender = (event: IpcMainInvokeEvent) => {
let isValid: boolean;
Expand Down
Loading
Loading