mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-09-20 21:50:11 +08:00
refactor(update-center): 消除刷新重试代码重复并加对称设计注释
- updateCenter.ts: 提取 getBackoffDelay,补充与主进程预刷新为对称设计的说明 - index.ts: 提取 getPreRefreshBackoffDelay,对齐命名与注释 - 仅消除重复拼写、补注释,刷新重试功能行为不变 - 超时保护仍只作用于刷新源路径,不波及列表加载与其他 IPC 验证: eslint + vue-tsc 通过,test-build 5.2.1.14-test 通过
This commit is contained in:
@@ -512,6 +512,131 @@ export const loadUpdateCenterItems = async (
|
||||
};
|
||||
};
|
||||
|
||||
// 子进程超时(毫秒):网络慢/镜像源卡死时,避免命令永久挂起
|
||||
const SYSTEM_UPDATE_COMMAND_TIMEOUT_MS = 90_000;
|
||||
|
||||
// 带超时保护的命令执行:超时杀掉子进程并 resolve,防止调用方永久冻结
|
||||
const runCommandWithTimeout = (
|
||||
command: string,
|
||||
args: string[],
|
||||
): Promise<{ code: number; stdout: string; stderr: string }> =>
|
||||
new Promise((resolve) => {
|
||||
const child = spawn(command, args, { shell: false, env: process.env });
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
let settled = false;
|
||||
const timer = setTimeout(() => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
try {
|
||||
child.kill("SIGKILL");
|
||||
} catch {
|
||||
// 忽略杀进程异常
|
||||
}
|
||||
resolve({
|
||||
code: -1,
|
||||
stdout,
|
||||
stderr: `${stderr}\n[timeout] command exceeded ${SYSTEM_UPDATE_COMMAND_TIMEOUT_MS}ms`,
|
||||
});
|
||||
}, SYSTEM_UPDATE_COMMAND_TIMEOUT_MS);
|
||||
const finish = (result: {
|
||||
code: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}): void => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
clearTimeout(timer);
|
||||
resolve(result);
|
||||
};
|
||||
child.stdout?.on("data", (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
child.stderr?.on("data", (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
child.on("error", (err) =>
|
||||
finish({ code: -1, stdout, stderr: err.message }),
|
||||
);
|
||||
child.on("close", (code) => finish({ code: code ?? -1, stdout, stderr }));
|
||||
});
|
||||
|
||||
// 刷新软件源(aptss ssupdate + apm update),提权执行。
|
||||
// 供更新中心 IPC 与“启动后空闲预刷新”复用,单一逻辑来源。
|
||||
export const runSystemUpdateSources = async (
|
||||
storeFilter: StoreFilter = "both",
|
||||
): Promise<{ aptss?: string; apm?: string }> => {
|
||||
console.log(
|
||||
`[UpdateCenter] runSystemUpdateSources called with storeFilter=${storeFilter}`,
|
||||
);
|
||||
|
||||
const results: { aptss?: string; apm?: string } = {};
|
||||
const isSourceEnabled = (
|
||||
filter: StoreFilter,
|
||||
source: "spark" | "apm",
|
||||
): boolean => filter === "both" || filter === source;
|
||||
|
||||
if (isSourceEnabled(storeFilter, "spark")) {
|
||||
const whichResult = await runCommandWithTimeout("which", ["aptss"]);
|
||||
const aptssAvailable =
|
||||
whichResult.code === 0 && whichResult.stdout.trim().length > 0;
|
||||
if (aptssAvailable) {
|
||||
console.log("[UpdateCenter] Running: pkexec shell-caller aptss ssupdate");
|
||||
const superUserCmd = await findExecutable(
|
||||
SUPER_USER_COMMAND_CANDIDATES[0],
|
||||
);
|
||||
if (superUserCmd) {
|
||||
const result = await runCommandWithTimeout(superUserCmd, [
|
||||
SHELL_CALLER_PATH,
|
||||
"aptss",
|
||||
"ssupdate",
|
||||
]);
|
||||
results.aptss =
|
||||
result.code === 0
|
||||
? "ok"
|
||||
: `failed: ${result.stderr.substring(0, 200)}`;
|
||||
console.log("[UpdateCenter] aptss ssupdate result:", results.aptss);
|
||||
} else {
|
||||
results.aptss = "failed: pkexec not found";
|
||||
console.warn("[UpdateCenter] pkexec not found, skipping aptss update");
|
||||
}
|
||||
} else {
|
||||
results.aptss = "skipped: aptss not installed";
|
||||
}
|
||||
}
|
||||
|
||||
if (isSourceEnabled(storeFilter, "apm")) {
|
||||
const whichResult = await runCommandWithTimeout("which", ["apm"]);
|
||||
const apmAvailable =
|
||||
whichResult.code === 0 && whichResult.stdout.trim().length > 0;
|
||||
if (apmAvailable) {
|
||||
console.log("[UpdateCenter] Running: pkexec shell-caller apm update");
|
||||
const superUserCmd = await findExecutable(
|
||||
SUPER_USER_COMMAND_CANDIDATES[0],
|
||||
);
|
||||
if (superUserCmd) {
|
||||
const result = await runCommandWithTimeout(superUserCmd, [
|
||||
SHELL_CALLER_PATH,
|
||||
"apm",
|
||||
"update",
|
||||
]);
|
||||
results.apm =
|
||||
result.code === 0
|
||||
? "ok"
|
||||
: `failed: ${result.stderr.substring(0, 200)}`;
|
||||
console.log("[UpdateCenter] apm update result:", results.apm);
|
||||
} else {
|
||||
results.apm = "failed: pkexec not found";
|
||||
console.warn("[UpdateCenter] pkexec not found, skipping apm update");
|
||||
}
|
||||
} else {
|
||||
results.apm = "skipped: apm not installed";
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
export const registerUpdateCenterIpc = (
|
||||
ipc: Pick<typeof ipcMain, "handle">,
|
||||
service: Pick<
|
||||
@@ -528,111 +653,8 @@ export const registerUpdateCenterIpc = (
|
||||
): void => {
|
||||
ipc.handle(
|
||||
"update-center-run-system-update",
|
||||
async (_event, storeFilter: StoreFilter = "both") => {
|
||||
console.log(
|
||||
`[UpdateCenter] update-center-run-system-update called with storeFilter=${storeFilter}`,
|
||||
);
|
||||
|
||||
const results: { aptss?: string; apm?: string } = {};
|
||||
|
||||
const runCommand = (
|
||||
command: string,
|
||||
args: string[],
|
||||
): Promise<{ code: number; stdout: string; stderr: string }> =>
|
||||
new Promise((resolve) => {
|
||||
const child = spawn(command, args, {
|
||||
shell: false,
|
||||
env: process.env,
|
||||
});
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
child.stdout?.on("data", (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
child.stderr?.on("data", (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
child.on("error", (err) =>
|
||||
resolve({ code: -1, stdout, stderr: err.message }),
|
||||
);
|
||||
child.on("close", (code) =>
|
||||
resolve({ code: code ?? -1, stdout, stderr }),
|
||||
);
|
||||
});
|
||||
|
||||
const isSourceEnabled = (
|
||||
filter: StoreFilter,
|
||||
source: "spark" | "apm",
|
||||
): boolean => filter === "both" || filter === source;
|
||||
|
||||
// aptss update — 需要提权
|
||||
if (isSourceEnabled(storeFilter, "spark")) {
|
||||
const whichResult = await runCommand("which", ["aptss"]);
|
||||
const aptssAvailable =
|
||||
whichResult.code === 0 && whichResult.stdout.trim().length > 0;
|
||||
if (aptssAvailable) {
|
||||
console.log(
|
||||
"[UpdateCenter] Running: pkexec shell-caller aptss ssupdate",
|
||||
);
|
||||
const superUserCmd = await findExecutable(
|
||||
SUPER_USER_COMMAND_CANDIDATES[0],
|
||||
);
|
||||
if (superUserCmd) {
|
||||
const result = await runCommand(superUserCmd, [
|
||||
SHELL_CALLER_PATH,
|
||||
"aptss",
|
||||
"ssupdate",
|
||||
]);
|
||||
results.aptss =
|
||||
result.code === 0
|
||||
? "ok"
|
||||
: `failed: ${result.stderr.substring(0, 200)}`;
|
||||
console.log("[UpdateCenter] aptss ssupdate result:", results.aptss);
|
||||
} else {
|
||||
results.aptss = "failed: pkexec not found";
|
||||
console.warn(
|
||||
"[UpdateCenter] pkexec not found, skipping aptss update",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
results.aptss = "skipped: aptss not installed";
|
||||
}
|
||||
}
|
||||
|
||||
// apm update — 也需要提权
|
||||
if (isSourceEnabled(storeFilter, "apm")) {
|
||||
const whichResult = await runCommand("which", ["apm"]);
|
||||
const apmAvailable =
|
||||
whichResult.code === 0 && whichResult.stdout.trim().length > 0;
|
||||
if (apmAvailable) {
|
||||
console.log("[UpdateCenter] Running: pkexec shell-caller apm update");
|
||||
const superUserCmd = await findExecutable(
|
||||
SUPER_USER_COMMAND_CANDIDATES[0],
|
||||
);
|
||||
if (superUserCmd) {
|
||||
const result = await runCommand(superUserCmd, [
|
||||
SHELL_CALLER_PATH,
|
||||
"apm",
|
||||
"update",
|
||||
]);
|
||||
results.apm =
|
||||
result.code === 0
|
||||
? "ok"
|
||||
: `failed: ${result.stderr.substring(0, 200)}`;
|
||||
console.log("[UpdateCenter] apm update result:", results.apm);
|
||||
} else {
|
||||
results.apm = "failed: pkexec not found";
|
||||
console.warn(
|
||||
"[UpdateCenter] pkexec not found, skipping apm update",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
results.apm = "skipped: apm not installed";
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
async (_event, storeFilter: StoreFilter = "both") =>
|
||||
runSystemUpdateSources(storeFilter),
|
||||
);
|
||||
|
||||
ipc.handle(
|
||||
|
||||
Reference in New Issue
Block a user