diff --git a/electron/main/backend/install-manager.ts b/electron/main/backend/install-manager.ts index 5ddc05f0..de169d2e 100644 --- a/electron/main/backend/install-manager.ts +++ b/electron/main/backend/install-manager.ts @@ -6,6 +6,7 @@ import pino from "pino"; import { ChannelPayload } from "../../typedefinition"; import axios from "axios"; +import { findExecutable, SUPER_USER_COMMAND_CANDIDATES } from "./superuser"; const logger = pino({ name: "install-manager" }); @@ -43,42 +44,11 @@ type InstallTask = { }; const SHELL_CALLER_PATH = "/opt/spark-store/extras/shell-caller.sh"; -const SUPER_USER_COMMAND_CANDIDATES = [ - "/usr/bin/pkexec", - "/run/wrappers/bin/pkexec", - "pkexec", -]; export const tasks = new Map(); let idle = true; // Indicates if the installation manager is idle -const findExecutable = async (command: string): Promise => { - if (path.isAbsolute(command)) { - try { - await fs.promises.access(command, fs.constants.X_OK); - return command; - } catch { - return ""; - } - } - - return await new Promise((resolve) => { - const child = spawn("which", [command]); - let stdout = ""; - - child.stdout?.on("data", (data) => { - stdout += data.toString(); - }); - child.on("close", (code) => { - resolve(code === 0 ? stdout.trim() : ""); - }); - child.on("error", () => { - resolve(""); - }); - }); -}; - export const checkSuperUserCommand = async (): Promise => { if (process.getuid?.() === 0) return ""; diff --git a/electron/main/backend/shared-installer.ts b/electron/main/backend/shared-installer.ts index 806d0fa4..99d80353 100644 --- a/electron/main/backend/shared-installer.ts +++ b/electron/main/backend/shared-installer.ts @@ -8,15 +8,11 @@ import * as fs from "node:fs"; import * as path from "node:path"; import axios from "axios"; import pino from "pino"; +import { findExecutable, SUPER_USER_COMMAND_CANDIDATES } from "./superuser"; const logger = pino({ name: "shared-installer" }); export const SHELL_CALLER_PATH = "/opt/spark-store/extras/shell-caller.sh"; -const SUPER_USER_COMMAND_CANDIDATES = [ - "/usr/bin/pkexec", - "/run/wrappers/bin/pkexec", - "pkexec", -]; export interface DownloadOptions { pkgname: string; @@ -363,29 +359,3 @@ export const checkSuperUserCommand = async (): Promise => { logger.error("没有找到提升权限的命令 pkexec!"); return ""; }; - -const findExecutable = async (command: string): Promise => { - if (path.isAbsolute(command)) { - try { - await fs.promises.access(command, fs.constants.X_OK); - return command; - } catch { - return ""; - } - } - - return await new Promise((resolve) => { - const child = spawn("which", [command]); - let stdout = ""; - - child.stdout?.on("data", (data) => { - stdout += data.toString(); - }); - child.on("close", (code) => { - resolve(code === 0 ? stdout.trim() : ""); - }); - child.on("error", () => { - resolve(""); - }); - }); -}; diff --git a/electron/main/backend/superuser.ts b/electron/main/backend/superuser.ts new file mode 100644 index 00000000..98046338 --- /dev/null +++ b/electron/main/backend/superuser.ts @@ -0,0 +1,49 @@ +import { spawn } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; + +export const SUPER_USER_COMMAND_CANDIDATES = [ + "/usr/bin/pkexec", + "/run/wrappers/bin/pkexec", +]; + +const WHICH_TIMEOUT_MS = 5000; + +export const findExecutable = async (command: string): Promise => { + if (path.isAbsolute(command)) { + try { + await fs.promises.access(command, fs.constants.X_OK); + return command; + } catch { + return ""; + } + } + + return await new Promise((resolve) => { + const child = spawn("which", [command]); + let stdout = ""; + let settled = false; + + const timer = setTimeout(() => { + child.kill(); + finish(""); + }, WHICH_TIMEOUT_MS); + + function finish(result: string) { + if (settled) return; + settled = true; + clearTimeout(timer); + resolve(result); + } + + child.stdout?.on("data", (data) => { + stdout += data.toString(); + }); + child.on("close", (code) => { + finish(code === 0 ? stdout.trim() : ""); + }); + child.on("error", () => { + finish(""); + }); + }); +};