Files
ele-HeiXiu/electron/preload/file-storage.ts
YoungestSongMo 136a17c0bf feat: 任务列表右键菜单回调 + 主进程下载 + sharp 缩略图 + IPC 精简重构
- 任务右键菜单:实现打开输出目录(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 行
2026-07-03 11:13:36 +08:00

95 lines
4.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// preload/file-storage.ts — 本地存储文件 API主进程 fs 桥接)
//
// 提供文件读写、目录管理、下载等接口
// 渲染进程通过 window.fileStorage 调用
// ============================================================
import { ipcRenderer, contextBridge } from 'electron';
import { BIDIRECTIONAL } from '../../shared/constants/ipc';
/** 本地存储文件 API */
export function exposeFileStorage(): void {
contextBridge.exposeInMainWorld('fileStorage', {
/** 获取 heixiu-data 根目录路径 */
async getDataDir(): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.GET_DATA_DIR);
return r?.success ? r.data : null;
},
/** 写入文件Base64 → 磁盘),返回写入的绝对路径 */
async writeFile(relativePath: string, data: string, encoding?: 'base64' | 'utf8'): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_WRITE, { relativePath, data, encoding });
return r?.success ? r.data : null;
},
/** 读取文件(磁盘 → Base64 */
async readFile(relativePath: string): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_READ, { relativePath });
return r?.success ? r.data : null;
},
/** 删除文件 */
async deleteFile(relativePath: string): Promise<boolean> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_DELETE, { relativePath });
return r?.success ?? false;
},
/** 递归创建目录 */
async makeDir(relativePath: string): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.MAKE_DIR, { relativePath });
return r?.success ? r.data : null;
},
/** 在文件管理器中显示文件(绝对路径) */
async showItemInFolder(filePath: string): Promise<boolean> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.SHOW_ITEM_IN_FOLDER, { filePath });
return r?.success ?? false;
},
/** 获取文件大小(字节) */
async fileSize(relativePath: string): Promise<number | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_SIZE, { relativePath });
return r?.success ? r.data : null;
},
/** 检查文件/目录是否存在 */
async fileExists(relativePath: string): Promise<boolean> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_EXISTS, { relativePath });
return r?.success ? r.data : false;
},
/** 绝对路径文件写入(绕过 heixiu-data 沙箱) */
async writeFileAbsolute(absolutePath: string, data: string, encoding?: 'base64' | 'utf8'): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.FILE_WRITE_ABSOLUTE, { absolutePath, data, encoding });
return r?.success ? r.data : null;
},
/** 绝对路径目录创建(绕过 heixiu-data 沙箱) */
async makeDirAbsolute(absolutePath: string): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.MAKE_DIR_ABSOLUTE, { absolutePath });
return r?.success ? r.data : null;
},
/** 主进程下载文件到绝对路径(绕过浏览器 CORS 限制),失败时 reject 并携带错误信息 */
async downloadToPath(url: string, destPath: string, headers?: Record<string, string>): Promise<string> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.DOWNLOAD_TO_PATH, { url, destPath, headers });
if (r?.success) return r.data;
throw new Error(r?.error || '主进程下载失败');
},
/** 获取系统下载目录路径 */
async getDownloadsPath(): Promise<string | null> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.GET_DOWNLOADS_PATH);
return r?.success ? r.data : null;
},
/** 生成图片缩略图(读取原图 → 缩放 → JPEG 写入目标路径) */
async generateThumbnail(srcPath: string, destPath: string, maxWidth?: number, quality?: number): Promise<string> {
const r = await ipcRenderer.invoke(BIDIRECTIONAL.GENERATE_THUMBNAIL, { srcPath, destPath, maxWidth, quality });
if (r?.success) return r.data;
throw new Error(r?.error || '缩略图生成失败');
},
});
}