Skip to content
  • Sponsor
  • Notifications You must be signed in to change notification settings
  • Fork 189
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

LL&C 2: Electric Boogaloo #348

Draft
wants to merge 9 commits into
base: development
Choose a base branch
from
Prev Previous commit
Next Next commit
kill.js: Add support for killing/starting Linux Native, Flatpaks & Snaps
- Raised relaunch delay from 1s to 1.5s for all platforms. It's safer for people with slow computers.

- Implemented detection of whether a Linux binary was launched as a Flatpak, Snap or Native.

- Added support for launching Discord's Linux Flatpaks, Snaps and Native, via their proper launch methods ("flatpak run", "snap run" or directly calling the native binary), along with now using the correct way to "spawn()" binaries on Linux (the old code used shell.openPath which does not work on Linux at all). All launch methods now set the correct "working directory" for the launched binary, to ensure that everything launches properly.

- Improved the GUI's logging messages. Words like "kill" have been replaced with "close", since non-technical users are the primary audience of BetterDiscord-Installer.

- Added detailed comments for future maintainers and contributors.
Arcitec authored and samfundev committed Mar 10, 2024

Verified

This commit was signed with the committer’s verified signature.
commit d9d2171895a591d2c87a8fc2db850913a189f2d9
66 changes: 61 additions & 5 deletions src/renderer/actions/utils/kill.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const {spawn} = require("child_process");
import path from "path";
import findProcess from "find-process";
import kill from "tree-kill";
import {shell} from "electron";
import {remote, shell} from "electron";
import {progress} from "../../stores/installation";
import {log} from "./log";

@@ -12,11 +13,11 @@ export default async function killProcesses(channels, progressPerLoop, shouldRes
if (process.platform === "darwin") processName = platforms[channel]; // Discord Canary and Discord PTB on Mac
else processName = platforms[channel].replace(" ", ""); // DiscordCanary and DiscordPTB on Windows/Linux

log("Attempting to kill " + processName);
log(`Attempting to close ${processName}.`);
try {
const results = await findProcess("name", processName, true);
if (!results || !results.length) {
log(`✅ ${processName} not running`);
log(`✅ ${processName} is not running.`);
progress.set(progress.value + progressPerLoop);
continue;
}
@@ -25,12 +26,67 @@ export default async function killProcesses(channels, progressPerLoop, shouldRes
const discordPid = results.find(p => parentPids.includes(p.pid));
const bin = process.platform === "darwin" ? path.resolve(discordPid.bin, "..", "..", "..") : discordPid.bin;
await new Promise(r => kill(discordPid.pid, r));
if (shouldRestart) setTimeout(() => shell.openPath(bin), 1000);
if (shouldRestart) {
const relaunchAfter = 1500; // 1.5 seconds. Don't reduce this!
if (process.platform === "linux") {
// On Linux, it's impossible to detect any signs of Flatpak or Snap
// runtimes from their process parents, but we can still detect them
// via their very unique binary prefixes. All Flatpaks use "/app"
// as their prefix, as can be seen in the Flatpak source:
// https://github.com/flatpak/flatpak/blob/main/common/flatpak-dir.c
// And Snaps use "/snap". Both Flatpaks and Snaps use those unique
// paths regardless of whether they also exist on the host or not.
//
// Example "bin" paths for Discord in Flatpak:
// - "/app/discord/Discord"
// - "/app/discord-canary/DiscordCanary"
//
// Examples for Snap:
// - "/snap/discord/138/usr/share/discord/Discord"
// - "/snap/discord-canary/358/usr/share/discord-canary/DiscordCanary"
//
// Examples for native Discord:
// - "/usr/lib64/discord/Discord"
// - "/usr/bin/Discord"
//
// The best way to relaunch applications on Linux would be
// to trigger their associated ".desktop" file. Unfortunately,
// each Linux desktop environment handles those differently.
// So we'll have to settle for directly launching native binaries,
// and in case of Flatpaks we'll generate a "flatpak run" cmd,
// and for Snaps we'll handle those via "snap run" instead.
//
// NOTE: "spawn()" is async and detaches the process, which
// ensures it continues running even after BD-Installer quits.
const userHome = remote.app.getPath("home"); // $HOME
const flatpakName = bin.match(/^\/app\/.*?\/(Discord[^\/]*)$/);
const snapName = bin.match(/^\/snap\/(discord[^\/]*)\/.*?\/Discord[^\/]*$/);
if (flatpakName) { // Flatpak.
// NOTE: Flatpak doesn't really need the cwd, but we set it anyway.
setTimeout(() => spawn("flatpak", [ "run", `com.discordapp.${flatpakName[1]}` ], {cwd: userHome}), relaunchAfter);
}
else if (snapName) { // Snap.
// NOTE: Setting the working directory helps with reliably launching,
// otherwise the Snap version can sometimes complain about missing files.
// NOTE: The Snap version needs a longer restart delay, due to Snap's slow
// machinery after a Snap application is closed, before it can start again.
setTimeout(() => spawn("snap", [ "run", snapName[1] ], {cwd: userHome}), relaunchAfter + 2500);
}
else { // Native application.
// NOTE: We set the working directory since it matters for native.
setTimeout(() => spawn(bin, [ ], {cwd: path.join(bin, "..")}), relaunchAfter);
}
}
else { // Windows and Mac.
// Simply trigger the executable via its default system handler.
setTimeout(() => shell.openPath(bin), relaunchAfter);
}
}
progress.set(progress.value + progressPerLoop);
}
catch (err) {
const symbol = shouldRestart ? "⚠️" : "❌";
log(`${symbol} Could not kill ${platforms[channel]}`);
log(`${symbol} Could not close ${platforms[channel]}.`);
log(`${symbol} ${err.message}`);
return err;
}