- 任务右键菜单:实现打开输出目录(inputs/outputs/.cache 结构)、
复制资源链接、重新编辑、再次生成、拉取结果、重新下载、收藏、删除记录
- 主进程下载:通过 Electron net 模块绕过 CORS,支持 CDN 媒体文件下载
- sharp 缩略图:替换 nativeImage,支持 4K/8K+ 大尺寸素材的流式处理
- IPC 精简:40+ 冗余通道 → 15 个分组通道,移除未使用的 preload 桥接方法
- 任务存储:新增收藏字段、schema 迁移、task-store 持久化
- 清理废弃模块:canvas-ipc / updater / request / pricing
refactor: IPC/Preload/Services 模块化拆分 — 单一职责 + 向后兼容
主要变更:
- shared/constants/ipc-channels.ts → ipc/ 模块 (base/storage/canvas/updater)
- electron/preload.ts → preload/ 模块 (base/safe-storage/file-storage/canvas)
- electron/main/ipc/canvas-ipc.ts → canvas/ 模块 (types/walk/sidecar/mime/thumbnail)
- electron/main/ipc/storage-ipc.ts → 提取 utils/ (path/download/thumbnail)
- electron/main/updater.ts → updater/ 模块 (provider/platform-updaters)
- src/services/request.ts → request/ 模块 (token/interceptors/methods)
- src/shared/utils/pricing.ts → pricing/ 模块 (types/helpers/format/calculate/fields)
- src/modules/home/center/views/ModelInputForm.tsx → 提取 utils + DependentFormItem
架构优化:
- 所有拆分均保持向后兼容(旧导入路径仍可用)
- TypeScript 编译通过 ✓
- 每个模块单一职责,平均 ~130 行
82 lines
3.2 KiB
TypeScript
82 lines
3.2 KiB
TypeScript
// ============================================================
|
|
// safe-storage-ipc — safeStorage 加密/解密 IPC 处理器
|
|
//
|
|
// 在主进程注册,渲染进程通过 preload 暴露的安全方法调用。
|
|
// 加密后的数据为 Base64 字符串,方便存储在 localStorage。
|
|
//
|
|
// 平台对应:
|
|
// Windows → DPAPI
|
|
// macOS → Keychain
|
|
// Linux → libsecret
|
|
//
|
|
// 注意:
|
|
// - safeStorage 加密绑定当前 OS 用户账户,无法跨用户/跨设备解密
|
|
// - 用户重装 OS 后加密数据将无法恢复(需重新登录)
|
|
// - safeStorage.isEncryptionAvailable() 在部分 Linux 发行版可能返回 false
|
|
// ============================================================
|
|
|
|
import { ipcMain, safeStorage } from 'electron';
|
|
import { BIDIRECTIONAL_STORAGE } from '../../../shared/constants/ipc/storage';
|
|
import { logger } from '../logger';
|
|
|
|
/** 检查 safeStorage 是否可用,不可用时记录警告 */
|
|
function checkAvailability(): boolean {
|
|
if (!safeStorage.isEncryptionAvailable()) {
|
|
logger.warn('safe-storage', 'safeStorage 加密不可用(可能缺少 libsecret 等系统密钥服务)');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 注册 safeStorage IPC 处理器
|
|
* 在 app.whenReady() 中调用
|
|
*/
|
|
export function registerSafeStorageIpcHandlers(): void {
|
|
// ---------- 加密 ----------
|
|
ipcMain.handle(BIDIRECTIONAL_STORAGE.SAFESTORAGE_ENCRYPT, (_event, plaintext: string) => {
|
|
if (typeof plaintext !== 'string' || plaintext.length === 0) {
|
|
logger.warn('safe-storage', '加密参数无效');
|
|
return { success: false, error: '参数无效:需要非空字符串' };
|
|
}
|
|
|
|
if (!checkAvailability()) {
|
|
return { success: false, error: 'safeStorage 不可用' };
|
|
}
|
|
|
|
try {
|
|
const encrypted = safeStorage.encryptString(plaintext);
|
|
const base64 = encrypted.toString('base64');
|
|
return { success: true, data: base64 };
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
logger.error('safe-storage', '加密失败', err instanceof Error ? err : new Error(message));
|
|
return { success: false, error: message };
|
|
}
|
|
});
|
|
|
|
// ---------- 解密 ----------
|
|
ipcMain.handle(BIDIRECTIONAL_STORAGE.SAFESTORAGE_DECRYPT, (_event, encryptedBase64: string) => {
|
|
if (typeof encryptedBase64 !== 'string' || encryptedBase64.length === 0) {
|
|
logger.warn('safe-storage', '解密参数无效');
|
|
return { success: false, error: '参数无效:需要非空字符串' };
|
|
}
|
|
|
|
if (!checkAvailability()) {
|
|
return { success: false, error: 'safeStorage 不可用' };
|
|
}
|
|
|
|
try {
|
|
const buffer = Buffer.from(encryptedBase64, 'base64');
|
|
const plaintext = safeStorage.decryptString(buffer);
|
|
return { success: true, data: plaintext };
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
logger.error('safe-storage', '解密失败', err instanceof Error ? err : new Error(message));
|
|
return { success: false, error: message };
|
|
}
|
|
});
|
|
|
|
logger.info('safe-storage', 'safeStorage IPC 处理器已注册');
|
|
}
|