From 7e4d1ab681da93fdfde1540901b09bf6c2afa670 Mon Sep 17 00:00:00 2001 From: Iris <244833241+its-iris@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:05:19 +0100 Subject: [PATCH] fix(discord): Fixed memory leak by repeated RPC failures (#4197) --- src/plugins/discord/discord-service.ts | 32 ++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/plugins/discord/discord-service.ts b/src/plugins/discord/discord-service.ts index 728836c0e..9912341a3 100644 --- a/src/plugins/discord/discord-service.ts +++ b/src/plugins/discord/discord-service.ts @@ -22,7 +22,7 @@ export class DiscordService { /** * Discord RPC client instance. */ - rpc = new DiscordClient({ clientId }); + rpc!: DiscordClient; /** * Indicates if the service is ready to send activity updates. */ @@ -62,6 +62,21 @@ export class DiscordService { this.mainWindow = mainWindow; this.autoReconnect = config?.autoReconnect ?? true; // Default autoReconnect to true + this.initializeRpc(); + } + + private initializeRpc() { + if (this.rpc) { + try { + this.rpc.destroy(); + } catch { + // ignored + } + this.rpc.removeAllListeners(); + } + + this.rpc = new DiscordClient({ clientId }); + this.rpc.on('connected', () => { if (dev()) { console.log(LoggerPrefix, t('plugins.discord.backend.connected')); @@ -192,6 +207,7 @@ export class DiscordService { resolve(); }) .catch(() => { + this.initializeRpc(); this.connectRecursive(); }); }, @@ -236,6 +252,9 @@ export class DiscordService { this.resetInfo(); if (this.autoReconnect) { + // For some reason @xhayper/discord-rpc leaves a dangling listener on connection failure + // so we destroy and recreate the RPC client before reconnecting. + this.initializeRpc(); this.connectRecursive(); } else if (showErrorDialog && this.mainWindow) { // connection failed @@ -250,12 +269,11 @@ export class DiscordService { this.autoReconnect = false; this.timerManager.clear(TimerKey.DiscordConnectRetry); this.timerManager.clear(TimerKey.ClearActivity); - if (this.rpc.isConnected) { - try { - this.rpc.destroy(); - } catch { - // ignored - } + try { + this.rpc.removeAllListeners(); + this.rpc.destroy(); + } catch { + // ignored } this.resetInfo(); // Reset internal state }