mirror of
https://github.com/dream-pep/koring-launcher.git
synced 2026-09-12 05:45:18 +08:00
feat: 新增自动更新版本引导流程及相关配置调整
- 新增完整的upvp更新引导页面套件,涵盖版本展示、版本检查、测试协议确认与完成页流程 - 新增appVersion配置字段用于记录当前应用版本,调整配置文件存储路径与旧配置迁移逻辑 - 更新路由配置与全局状态管理以支持更新引导流程 - 更新自动更新计划文档与示例配置文件
This commit is contained in:
+18
-4
@@ -9,12 +9,13 @@ const CURRENT_VERSION = 1;
|
||||
|
||||
/**
|
||||
* 配置文件路径:
|
||||
* - 打包后 → 系统用户数据目录(userData),避免安装到 Program Files 等只读目录时写入失败
|
||||
* - 打包后 → 安装目录(可执行文件旁)。默认 per-user 安装(%LOCALAPPDATA%\Programs)可写;
|
||||
* 若当初选择 per-machine 安装(Program Files)会无写权限,属已知限制
|
||||
* - 开发模式 → 项目根目录(与旧行为一致,方便调试)
|
||||
*/
|
||||
export function configPath(): string {
|
||||
if (app.isPackaged) {
|
||||
return path.join(app.getPath('userData'), CONFIG_FILE);
|
||||
return path.join(path.dirname(app.getPath('exe')), CONFIG_FILE);
|
||||
}
|
||||
return path.join(__dirname, '..', CONFIG_FILE);
|
||||
}
|
||||
@@ -130,7 +131,10 @@ export interface UpdateConfig {
|
||||
}
|
||||
|
||||
export interface AppConfig {
|
||||
/** 配置结构版本(迁移用) */
|
||||
version: number;
|
||||
/** 当前应用版本号(app.getVersion(),每次启动刷新;配置文件自述用) */
|
||||
appVersion: string;
|
||||
oobe: boolean;
|
||||
app: AppInfoConfig;
|
||||
theme: ThemeConfig;
|
||||
@@ -148,6 +152,7 @@ export interface AppConfig {
|
||||
|
||||
const DEFAULTS: AppConfig = {
|
||||
version: CURRENT_VERSION,
|
||||
appVersion: '',
|
||||
oobe: true,
|
||||
app: { language: 'zh-CN' },
|
||||
theme: { darkMode: 'auto', parallax: true },
|
||||
@@ -220,12 +225,19 @@ export function loadConfig(): AppConfig {
|
||||
}
|
||||
}
|
||||
|
||||
export function saveConfig(config: AppConfig): void {
|
||||
/**
|
||||
* 保存配置(稀疏:仅写与默认值不同的部分)。
|
||||
* - force=true:全量写入(首次启动使用,保证配置文件在安装目录可见)
|
||||
* - 稀疏结果为空时:保留现有文件不删(重置由 config:reset / factoryReset 显式删除)
|
||||
*/
|
||||
export function saveConfig(config: AppConfig, force = false): void {
|
||||
const filePath = configPath();
|
||||
const sparse = diffValue(config, DEFAULTS) as Record<string, unknown> | undefined;
|
||||
|
||||
if (!sparse || Object.keys(sparse).length === 0) {
|
||||
try { fs.unlinkSync(filePath); } catch {}
|
||||
if (force) {
|
||||
fs.writeFileSync(filePath, yaml.dump(config, { lineWidth: -1 }), 'utf-8');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -256,6 +268,8 @@ function mergeDeep<T>(base: T, patch: unknown): T {
|
||||
export function getConfig(): AppConfig {
|
||||
if (!current) {
|
||||
current = loadConfig();
|
||||
// 注意:不在此处刷新 appVersion —— 升级后保持旧版本号,
|
||||
// 由渲染端 upvp(版本更新引导)流程完成后写入新版本号
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
+14
-19
@@ -17,7 +17,6 @@ import { registerJavaHandlers } from './handlers/java';
|
||||
import { registerUpdateHandlers } from './handlers/update';
|
||||
import { updateService } from './updater';
|
||||
import { saveConfig, configExists, getConfig, flushConfig, configPath } from './config';
|
||||
import { authPath } from './auth';
|
||||
|
||||
const { app } = electron;
|
||||
|
||||
@@ -32,25 +31,20 @@ const win: { mainWindow: electron.BrowserWindow | null; splashWindow: electron.B
|
||||
splashWindow: null,
|
||||
};
|
||||
|
||||
// 迁移旧版「可执行文件旁」存储 → userData(仅打包模式)。
|
||||
// 复制而非移动,避免破坏用户已有文件;userData 已有目标文件则跳过。
|
||||
// 迁移旧版 userData 存储 → 安装目录(仅打包模式;配置已改回存安装目录)。
|
||||
// 复制而非移动,避免破坏用户已有文件;安装目录已有目标文件则跳过。
|
||||
function migrateLegacyFiles(): void {
|
||||
if (!app.isPackaged) return;
|
||||
const exeDir = path.dirname(app.getPath('exe'));
|
||||
const pairs: { name: string; dest: string }[] = [
|
||||
{ name: 'Koring.yml', dest: configPath() },
|
||||
{ name: 'koring-auth.json', dest: authPath() },
|
||||
];
|
||||
for (const { name, dest } of pairs) {
|
||||
if (fs.existsSync(dest)) continue;
|
||||
const src = path.join(exeDir, name);
|
||||
if (!fs.existsSync(src)) continue;
|
||||
try {
|
||||
fs.copyFileSync(src, dest);
|
||||
console.log(`[migrate] copied ${name} → ${dest}`);
|
||||
} catch (e) {
|
||||
console.error(`[migrate] failed to copy ${name}:`, e);
|
||||
}
|
||||
const dest = path.join(exeDir, 'Koring.yml');
|
||||
if (fs.existsSync(dest)) return;
|
||||
const src = path.join(app.getPath('userData'), 'Koring.yml');
|
||||
if (!fs.existsSync(src)) return;
|
||||
try {
|
||||
fs.copyFileSync(src, dest);
|
||||
console.log(`[migrate] copied Koring.yml ${src} → ${dest}`);
|
||||
} catch (e) {
|
||||
console.error(`[migrate] failed to copy Koring.yml:`, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +67,8 @@ function runStartupChecks(): { isFirstLaunch: boolean; config: ReturnType<typeof
|
||||
// 3. Load (or create) config(getConfig 会缓存到主进程内存,成为唯一权威)
|
||||
const config = getConfig();
|
||||
if (isFirstLaunch) {
|
||||
saveConfig(config);
|
||||
// 首次启动:全量写入,确保配置文件在安装目录可见(稀疏保存下全默认不落盘)
|
||||
saveConfig(config, true);
|
||||
}
|
||||
|
||||
return { isFirstLaunch, config };
|
||||
@@ -175,7 +170,7 @@ function registerAllHandlers() {
|
||||
app.whenReady().then(() => {
|
||||
registerAllHandlers();
|
||||
|
||||
// Migrate legacy exe-dir config/auth to userData before anything reads them
|
||||
// Migrate legacy userData config to install dir before anything reads them
|
||||
migrateLegacyFiles();
|
||||
|
||||
// Run startup checks before creating windows
|
||||
|
||||
Reference in New Issue
Block a user