From f46f3163da92c681cca6fc973a1b2d87afa02a37 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 15 Jan 2025 19:25:06 -0500 Subject: [PATCH] feat: move arrpc server into a worker thread --- scripts/build/build.mts | 6 ++++ src/main/arrpc.ts | 57 +++++++++++++++++++++++------- src/main/arrpcWorker.ts | 42 ++++++++++++++++++++++ src/main/utils/arrpcWorkerTypes.ts | 26 ++++++++++++++ 4 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 src/main/arrpcWorker.ts create mode 100644 src/main/utils/arrpcWorkerTypes.ts diff --git a/scripts/build/build.mts b/scripts/build/build.mts index 243381b..37f49df 100644 --- a/scripts/build/build.mts +++ b/scripts/build/build.mts @@ -57,6 +57,12 @@ await Promise.all([ outfile: "dist/js/main.js", footer: { js: "//# sourceURL=VCDMain" } }), + createContext({ + ...NodeCommonOpts, + entryPoints: ["src/main/arrpcWorker.ts"], + outfile: "dist/js/arrpcWorker.js", + footer: { js: "//# sourceURL=VCDArrpcWorker" } + }), createContext({ ...NodeCommonOpts, entryPoints: ["src/preload/index.ts"], diff --git a/src/main/arrpc.ts b/src/main/arrpc.ts index 1899d9c..c92745a 100644 --- a/src/main/arrpc.ts +++ b/src/main/arrpc.ts @@ -4,31 +4,62 @@ * Copyright (c) 2023 Vendicated and Vencord contributors */ -import Server from "arrpc"; +import { resolve } from "path"; import { IpcEvents } from "shared/IpcEvents"; +import { MessageChannel, Worker } from "worker_threads"; import { mainWin } from "./mainWindow"; import { Settings } from "./settings"; +import { ArrpcEvent, ArrpcHostEvent } from "./utils/arrpcWorkerTypes"; -let server: any; +let worker: any; const inviteCodeRegex = /^(\w|-)+$/; export async function initArRPC() { - if (server || !Settings.store.arRPC) return; + if (worker || !Settings.store.arRPC) return; try { - server = await new Server(); - server.on("activity", (data: any) => mainWin.webContents.send(IpcEvents.ARRPC_ACTIVITY, JSON.stringify(data))); - server.on("invite", (invite: string, callback: (valid: boolean) => void) => { - invite = String(invite); - if (!inviteCodeRegex.test(invite)) return callback(false); + const { port1: hostPort, port2: workerPort } = new MessageChannel(); + worker = new Worker(resolve(__dirname, "./arrpcWorker.js"), { + workerData: { + workerPort + }, + transferList: [workerPort] + }); + hostPort.on("message", (e: ArrpcEvent) => { + switch (e.eventType) { + case IpcEvents.ARRPC_ACTIVITY: { + mainWin.webContents.send(IpcEvents.ARRPC_ACTIVITY, e.data); + break; + } + case "invite": { + const invite = String(e.data); - mainWin.webContents - // Safety: Result of JSON.stringify should always be safe to equal - // Also, just to be super super safe, invite is regex validated above - .executeJavaScript(`Vesktop.openInviteModal(${JSON.stringify(invite)})`) - .then(callback); + if (!inviteCodeRegex.test(invite)) { + const hostEvent: ArrpcHostEvent = { + eventType: "ack-invite", + data: false, + inviteId: e.inviteId + }; + return hostPort.postMessage(hostEvent); + } + + mainWin.webContents + // Safety: Result of JSON.stringify should always be safe to equal + // Also, just to be super super safe, invite is regex validated above + .executeJavaScript(`Vesktop.openInviteModal(${JSON.stringify(invite)})`) + .then(() => { + const hostEvent: ArrpcHostEvent = { + eventType: "ack-invite", + data: true, + inviteId: e.inviteId + }; + hostPort.postMessage(hostEvent); + }); + break; + } + } }); } catch (e) { console.error("Failed to start arRPC server", e); diff --git a/src/main/arrpcWorker.ts b/src/main/arrpcWorker.ts new file mode 100644 index 0000000..d26d6ec --- /dev/null +++ b/src/main/arrpcWorker.ts @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + */ + +import Server from "arrpc"; +import { IpcEvents } from "shared/IpcEvents"; +import { MessagePort, workerData } from "worker_threads"; + +import { ArrpcEvent, ArrpcHostEvent } from "./utils/arrpcWorkerTypes"; + +let server: any; + +type InviteCallback = (valid: boolean) => void; + +let inviteCallbacks: Array = []; + +(async function () { + const { workerPort }: { workerPort: MessagePort } = workerData; + server = await new Server(); + server.on("activity", (data: any) => { + const event: ArrpcEvent = { + eventType: IpcEvents.ARRPC_ACTIVITY, + data: JSON.stringify(data) + }; + workerPort.postMessage(event); + }); + server.on("invite", (invite: string, callback: InviteCallback) => { + const event: ArrpcEvent = { + eventType: "invite", + data: invite, + inviteId: inviteCallbacks.push(callback) - 1 + }; + workerPort.postMessage(event); + }); + + workerPort.on("message", (e: ArrpcHostEvent) => { + inviteCallbacks[e.inviteId](e.data); + inviteCallbacks = [...inviteCallbacks.slice(0, e.inviteId), ...inviteCallbacks.slice(e.inviteId + 1)]; + }); +})(); diff --git a/src/main/utils/arrpcWorkerTypes.ts b/src/main/utils/arrpcWorkerTypes.ts new file mode 100644 index 0000000..5e45173 --- /dev/null +++ b/src/main/utils/arrpcWorkerTypes.ts @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + */ + +import { IpcEvents } from "shared/IpcEvents"; + +export type ArrpcEvent = ArrpcActivityEvent | ArrpcInviteEvent; + +export interface ArrpcActivityEvent { + eventType: IpcEvents.ARRPC_ACTIVITY; + data: string; +} + +export interface ArrpcInviteEvent { + eventType: "invite"; + data: string; + inviteId: number; +} + +export interface ArrpcHostEvent { + eventType: "ack-invite"; + inviteId: number; + data: boolean; +}