feat(update-center): 实现集中式软件更新中心功能

新增更新中心模块,支持管理 APM 和传统 deb 软件更新任务
- 添加更新任务队列管理、状态跟踪和日志记录功能
- 实现更新项忽略配置持久化存储
- 新增更新确认对话框和迁移提示
- 优化主窗口关闭时的任务保护机制
- 添加单元测试覆盖核心逻辑
This commit is contained in:
2026-04-09 08:19:51 +08:00
parent 97bb8e5f59
commit 0b17ada45a
37 changed files with 6389 additions and 342 deletions

View File

@@ -0,0 +1,79 @@
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
import type { UpdateCenterItem } from "./types";
export const LEGACY_IGNORE_CONFIG_PATH = "/etc/spark-store/ignored_apps.conf";
const LEGACY_IGNORE_SEPARATOR = "|";
export const createIgnoreKey = (pkgname: string, version: string): string =>
`${pkgname}${LEGACY_IGNORE_SEPARATOR}${version}`;
export const parseIgnoredEntries = (content: string): Set<string> => {
const ignoredEntries = new Set<string>();
for (const line of content.split("\n")) {
const trimmed = line.trim();
if (!trimmed) {
continue;
}
const parts = trimmed.split(LEGACY_IGNORE_SEPARATOR);
if (parts.length !== 2) {
continue;
}
const [pkgname, version] = parts;
if (!pkgname || !version) {
continue;
}
ignoredEntries.add(createIgnoreKey(pkgname, version));
}
return ignoredEntries;
};
export const loadIgnoredEntries = async (
filePath: string,
): Promise<Set<string>> => {
try {
const content = await readFile(filePath, "utf8");
return parseIgnoredEntries(content);
} catch (error) {
if (
typeof error === "object" &&
error !== null &&
"code" in error &&
error.code === "ENOENT"
) {
return new Set<string>();
}
throw error;
}
};
export const saveIgnoredEntries = async (
filePath: string,
ignoredEntries: ReadonlySet<string>,
): Promise<void> => {
const sortedEntries = Array.from(ignoredEntries).sort();
const content =
sortedEntries.length > 0 ? `${sortedEntries.join("\n")}\n` : "";
await mkdir(dirname(filePath), { recursive: true });
await writeFile(filePath, content, "utf8");
};
export const applyIgnoredEntries = (
items: UpdateCenterItem[],
ignoredEntries: ReadonlySet<string>,
): UpdateCenterItem[] =>
items.map((item) => ({
...item,
ignored: ignoredEntries.has(
createIgnoreKey(item.pkgname, item.nextVersion),
),
}));