mirror of
https://github.com/dream-pep/koring-launcher.git
synced 2026-09-12 05:45:18 +08:00
本次提交完成以下变更: 1. 实现完整的更新通道管理功能,支持慢走/跑步两种更新模式,可在设置页切换且配置持久化生效 2. 新增更新调试页面,集成检查更新、版本比对、设置测试版本等调试工具 3. 新增快速打开Chromium DevTools的按钮,方便开发调试 4. 完善自动更新后端逻辑,新增版本比对、测试版本覆盖、通道动态获取等IPC接口 5. 调整GitHub Release构建脚本,修复prerelease版本的命名与发布问题 6. 添加semver依赖与类型定义,完善全量类型声明 7. 更新自动更新文档,补充更新通道相关的设计说明 8. 微调默认配置,添加主题暗黑模式的初始配置
118 lines
4.8 KiB
TypeScript
118 lines
4.8 KiB
TypeScript
import electron from 'electron';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
const { contextBridge, ipcRenderer } = electron;
|
|
|
|
const MIME_MAP: Record<string, string> = {
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.jpeg': 'image/jpeg',
|
|
'.webp': 'image/webp',
|
|
'.gif': 'image/gif',
|
|
'.bmp': 'image/bmp',
|
|
};
|
|
|
|
function getFileAsDataUrl(filePath: string): string | null {
|
|
try {
|
|
const buffer = fs.readFileSync(filePath);
|
|
const ext = path.extname(filePath).toLowerCase();
|
|
const mime = MIME_MAP[ext] || 'image/png';
|
|
return `data:${mime};base64,${buffer.toString('base64')}`;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld('electronAPI', {
|
|
// Generic IPC
|
|
invoke: (channel: string, ...args: unknown[]) =>
|
|
ipcRenderer.invoke(channel, ...args),
|
|
|
|
on: (channel: string, callback: (...args: unknown[]) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => callback(...args);
|
|
ipcRenderer.on(channel, handler);
|
|
return () => ipcRenderer.removeListener(channel, handler);
|
|
},
|
|
|
|
send: (channel: string, ...args: unknown[]) =>
|
|
ipcRenderer.send(channel, ...args),
|
|
|
|
// Window controls
|
|
minimize: () => ipcRenderer.invoke('window:minimize'),
|
|
maximize: () => ipcRenderer.invoke('window:maximize'),
|
|
close: () => ipcRenderer.invoke('window:close'),
|
|
isMaximized: () => ipcRenderer.invoke('window:isMaximized'),
|
|
openDevTools: () => ipcRenderer.invoke('window:openDevTools'),
|
|
onResized: (callback: () => void) => {
|
|
const handler = () => callback();
|
|
ipcRenderer.on('window:resized', handler);
|
|
return () => ipcRenderer.removeListener('window:resized', handler);
|
|
},
|
|
|
|
// Theme
|
|
getTheme: () => ipcRenderer.invoke('window:getTheme'),
|
|
|
|
// Config preloading
|
|
onConfigPreload: (callback: (data: { config: unknown; isFirstLaunch: boolean }) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, data: { config: unknown; isFirstLaunch: boolean }) => callback(data);
|
|
ipcRenderer.on('config:preload', handler);
|
|
return () => ipcRenderer.removeListener('config:preload', handler);
|
|
},
|
|
|
|
// Config changed broadcast (authoritative full config from main process)
|
|
onConfigChanged: (callback: (config: unknown) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, config: unknown) => callback(config);
|
|
ipcRenderer.on('config:changed', handler);
|
|
return () => ipcRenderer.removeListener('config:changed', handler);
|
|
},
|
|
|
|
// Background image — pick file, copy to userData, return base64 data URL
|
|
pickBackgroundImage: async (): Promise<string | null> => {
|
|
const result = await ipcRenderer.invoke('dialog:openFile', {
|
|
filters: [{ name: '图片', extensions: ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp'] }],
|
|
});
|
|
if (!result) return null;
|
|
const { srcPath, ext } = result as { srcPath: string; ext: string };
|
|
// Copy to userData via main process
|
|
const destPath = await ipcRenderer.invoke('background:copyToUserData', srcPath, ext);
|
|
if (!destPath) return null;
|
|
return getFileAsDataUrl(destPath);
|
|
},
|
|
|
|
// Get cached background as base64 data URL
|
|
getBackgroundDataUrl: async (): Promise<string | null> => {
|
|
const filePath = await ipcRenderer.invoke('background:getCachedPath');
|
|
if (!filePath) return null;
|
|
return getFileAsDataUrl(filePath);
|
|
},
|
|
|
|
// Open external URL in system browser
|
|
openExternal: (url: string) => ipcRenderer.invoke('shell:openExternal', url),
|
|
|
|
// Crash monitoring — devtools only
|
|
simulateCrash: () => ipcRenderer.invoke('crash:simulate'),
|
|
testCrashDialog: () => ipcRenderer.invoke('crash:testDialog'),
|
|
|
|
// Config reset
|
|
resetConfig: () => ipcRenderer.invoke('config:reset'),
|
|
|
|
// Auto-update (main process: electron/updater.ts)
|
|
checkForUpdates: (manual = false) => ipcRenderer.invoke('update:check', { manual }),
|
|
downloadUpdate: () => ipcRenderer.invoke('update:download'),
|
|
pauseUpdate: () => ipcRenderer.invoke('update:pause'),
|
|
resumeUpdate: () => ipcRenderer.invoke('update:resume'),
|
|
cancelUpdate: () => ipcRenderer.invoke('update:cancel'),
|
|
quitAndInstall: () => ipcRenderer.invoke('update:quitAndInstall'),
|
|
getUpdateState: () => ipcRenderer.invoke('update:getState'),
|
|
getReleaseNotes: (tag?: string) => ipcRenderer.invoke('update:getReleaseNotes', { tag }),
|
|
getUpdateChannels: () => ipcRenderer.invoke('update:getChannels'),
|
|
setUpdateChannel: (channel: string) => ipcRenderer.invoke('update:setChannel', { channel }),
|
|
setTestVersion: (version: string) => ipcRenderer.invoke('update:setTestVersion', { version }),
|
|
compareVersions: (a: string, b: string) => ipcRenderer.invoke('update:compareVersions', { a, b }),
|
|
onUpdateStatus: (callback: (data: unknown) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, data: unknown) => callback(data);
|
|
ipcRenderer.on('update:status', handler);
|
|
return () => ipcRenderer.removeListener('update:status', handler);
|
|
},
|
|
});
|