Move arrpc server into a worker thread to reduce stutters (#1053)
Co-authored-by: V <vendicated@riseup.net>
This commit is contained in:
@@ -58,6 +58,12 @@ await Promise.all([
|
|||||||
outfile: "dist/js/main.js",
|
outfile: "dist/js/main.js",
|
||||||
footer: { js: "//# sourceURL=VCDMain" }
|
footer: { js: "//# sourceURL=VCDMain" }
|
||||||
}),
|
}),
|
||||||
|
createContext({
|
||||||
|
...NodeCommonOpts,
|
||||||
|
entryPoints: ["src/main/arrpc/worker.ts"],
|
||||||
|
outfile: "dist/js/arRpcWorker.js",
|
||||||
|
footer: { js: "//# sourceURL=VCDArRpcWorker" }
|
||||||
|
}),
|
||||||
createContext({
|
createContext({
|
||||||
...NodeCommonOpts,
|
...NodeCommonOpts,
|
||||||
entryPoints: ["src/preload/index.ts"],
|
entryPoints: ["src/preload/index.ts"],
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Server from "arrpc";
|
|
||||||
import { IpcCommands } from "shared/IpcEvents";
|
|
||||||
|
|
||||||
import { sendRendererCommand } from "./ipcCommands";
|
|
||||||
import { Settings } from "./settings";
|
|
||||||
|
|
||||||
let server: any;
|
|
||||||
|
|
||||||
const inviteCodeRegex = /^(\w|-)+$/;
|
|
||||||
|
|
||||||
export async function initArRPC() {
|
|
||||||
if (server || !Settings.store.arRPC) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
server = await new Server();
|
|
||||||
server.on("activity", (data: any) => sendRendererCommand(IpcCommands.RPC_ACTIVITY, JSON.stringify(data)));
|
|
||||||
server.on("invite", async (invite: string, callback: (valid: boolean) => void) => {
|
|
||||||
invite = String(invite);
|
|
||||||
if (!inviteCodeRegex.test(invite)) return callback(false);
|
|
||||||
|
|
||||||
await sendRendererCommand(IpcCommands.RPC_INVITE, invite).then(callback);
|
|
||||||
});
|
|
||||||
server.on("link", async (data: any, deepCallback: (valid: boolean) => void) => {
|
|
||||||
await sendRendererCommand(IpcCommands.RPC_DEEP_LINK, data).then(deepCallback);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to start arRPC server", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings.addChangeListener("arRPC", initArRPC);
|
|
||||||
83
src/main/arrpc/index.ts
Normal file
83
src/main/arrpc/index.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { resolve } from "path";
|
||||||
|
import { IpcCommands } from "shared/IpcEvents";
|
||||||
|
import { MessageChannel, Worker } from "worker_threads";
|
||||||
|
|
||||||
|
import { sendRendererCommand } from "../ipcCommands";
|
||||||
|
import { Settings } from "../settings";
|
||||||
|
import { ArRpcEvent, ArRpcHostEvent } from "./types";
|
||||||
|
|
||||||
|
let worker: Worker;
|
||||||
|
|
||||||
|
const inviteCodeRegex = /^(\w|-)+$/;
|
||||||
|
|
||||||
|
export async function initArRPC() {
|
||||||
|
if (worker || !Settings.store.arRPC) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { port1: hostPort, port2: workerPort } = new MessageChannel();
|
||||||
|
|
||||||
|
worker = new Worker(resolve(__dirname, "./arRpcWorker.js"), {
|
||||||
|
workerData: {
|
||||||
|
workerPort
|
||||||
|
},
|
||||||
|
transferList: [workerPort]
|
||||||
|
});
|
||||||
|
|
||||||
|
hostPort.on("message", async (e: ArRpcEvent) => {
|
||||||
|
switch (e.type) {
|
||||||
|
case "activity": {
|
||||||
|
sendRendererCommand(IpcCommands.RPC_ACTIVITY, e.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "invite": {
|
||||||
|
const invite = String(e.data);
|
||||||
|
|
||||||
|
const response: ArRpcHostEvent = {
|
||||||
|
type: "ack-invite",
|
||||||
|
nonce: e.nonce,
|
||||||
|
data: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!inviteCodeRegex.test(invite)) {
|
||||||
|
return hostPort.postMessage(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.data = await sendRendererCommand(IpcCommands.RPC_INVITE, invite).catch(() => false);
|
||||||
|
|
||||||
|
hostPort.postMessage(response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "link": {
|
||||||
|
const link = String(e.data);
|
||||||
|
|
||||||
|
const response: ArRpcHostEvent = {
|
||||||
|
type: "ack-link",
|
||||||
|
nonce: e.nonce,
|
||||||
|
data: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!inviteCodeRegex.test(link)) {
|
||||||
|
return hostPort.postMessage(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.data = await sendRendererCommand(IpcCommands.RPC_DEEP_LINK, link).catch(() => false);
|
||||||
|
|
||||||
|
hostPort.postMessage(response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to start arRPC server", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.addChangeListener("arRPC", initArRPC);
|
||||||
37
src/main/arrpc/types.ts
Normal file
37
src/main/arrpc/types.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2025 Vendicated and Vesktop contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type ArRpcEvent = ArRpcActivityEvent | ArRpcInviteEvent | ArRpcLinkEvent;
|
||||||
|
export type ArRpcHostEvent = ArRpcHostAckInviteEvent | ArRpcHostAckLinkEvent;
|
||||||
|
|
||||||
|
export interface ArRpcActivityEvent {
|
||||||
|
type: "activity";
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArRpcInviteEvent {
|
||||||
|
type: "invite";
|
||||||
|
nonce: string;
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArRpcLinkEvent {
|
||||||
|
type: "link";
|
||||||
|
nonce: string;
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArRpcHostAckInviteEvent {
|
||||||
|
type: "ack-invite";
|
||||||
|
nonce: string;
|
||||||
|
data: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArRpcHostAckLinkEvent {
|
||||||
|
type: "ack-link";
|
||||||
|
nonce: string;
|
||||||
|
data: boolean;
|
||||||
|
}
|
||||||
60
src/main/arrpc/worker.ts
Normal file
60
src/main/arrpc/worker.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2025 Vendicated and Vesktop contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Server from "arrpc";
|
||||||
|
import { randomUUID } from "crypto";
|
||||||
|
import { MessagePort, workerData } from "worker_threads";
|
||||||
|
|
||||||
|
import { ArRpcEvent, ArRpcHostEvent } from "./types";
|
||||||
|
|
||||||
|
let server: any;
|
||||||
|
|
||||||
|
type InviteCallback = (valid: boolean) => void;
|
||||||
|
type LinkCallback = InviteCallback;
|
||||||
|
|
||||||
|
const inviteCallbacks = new Map<string, InviteCallback>();
|
||||||
|
const linkCallbacks = new Map<string, LinkCallback>();
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
const { workerPort } = workerData as { workerPort: MessagePort };
|
||||||
|
|
||||||
|
server = await new Server();
|
||||||
|
|
||||||
|
server.on("activity", (data: any) => {
|
||||||
|
const event: ArRpcEvent = {
|
||||||
|
type: "activity",
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
};
|
||||||
|
workerPort.postMessage(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("invite", (invite: string, callback: InviteCallback) => {
|
||||||
|
const nonce = randomUUID();
|
||||||
|
inviteCallbacks.set(nonce, callback);
|
||||||
|
|
||||||
|
const event: ArRpcEvent = {
|
||||||
|
type: "invite",
|
||||||
|
data: invite,
|
||||||
|
nonce
|
||||||
|
};
|
||||||
|
workerPort.postMessage(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
workerPort.on("message", (e: ArRpcHostEvent) => {
|
||||||
|
switch (e.type) {
|
||||||
|
case "ack-invite": {
|
||||||
|
inviteCallbacks.get(e.nonce)?.(e.data);
|
||||||
|
inviteCallbacks.delete(e.nonce);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "ack-link": {
|
||||||
|
linkCallbacks.get(e.nonce)?.(e.data);
|
||||||
|
linkCallbacks.delete(e.nonce);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -49,8 +49,6 @@ export const enum IpcEvents {
|
|||||||
VIRT_MIC_START_SYSTEM = "VCD_VIRT_MIC_START_ALL",
|
VIRT_MIC_START_SYSTEM = "VCD_VIRT_MIC_START_ALL",
|
||||||
VIRT_MIC_STOP = "VCD_VIRT_MIC_STOP",
|
VIRT_MIC_STOP = "VCD_VIRT_MIC_STOP",
|
||||||
|
|
||||||
ARRPC_ACTIVITY = "VCD_ARRPC_ACTIVITY",
|
|
||||||
|
|
||||||
CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE",
|
CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE",
|
||||||
|
|
||||||
DEBUG_LAUNCH_GPU = "VCD_DEBUG_LAUNCH_GPU",
|
DEBUG_LAUNCH_GPU = "VCD_DEBUG_LAUNCH_GPU",
|
||||||
|
|||||||
Reference in New Issue
Block a user