300 lines
8.3 KiB
TypeScript
300 lines
8.3 KiB
TypeScript
/**
|
||
* Electron Preload 脚本
|
||
*
|
||
* 这是渲染进程和主进程之间的安全桥梁
|
||
* 通过 contextBridge 安全地暴露 API 给渲染进程
|
||
*
|
||
* 安全说明:
|
||
* - contextIsolation: true 确保渲染进程无法直接访问 Node.js API
|
||
* - 所有暴露的方法都经过 IPC 通道与主进程通信
|
||
* - 不要在这里导入 electron-store 或其他 Node.js 模块
|
||
*/
|
||
import { contextBridge, ipcRenderer } from 'electron'
|
||
|
||
// IPC 通道名称(与 ipc.ts 保持一致)
|
||
const IPC_CHANNELS = {
|
||
SAVE_FILE: 'file:save',
|
||
READ_FILE: 'file:read',
|
||
GET_SETTINGS: 'settings:get',
|
||
SAVE_SETTINGS: 'settings:save',
|
||
// 缓存操作
|
||
CACHE_SET_JSON: 'cache:setJSON',
|
||
CACHE_GET_JSON: 'cache:getJSON',
|
||
CACHE_SET_BINARY: 'cache:setBinary',
|
||
CACHE_GET_BINARY: 'cache:getBinary',
|
||
CACHE_HAS: 'cache:has',
|
||
CACHE_DELETE: 'cache:delete',
|
||
CACHE_CLEAR_NAMESPACE: 'cache:clearNamespace',
|
||
CACHE_CLEAR_ALL: 'cache:clearAll',
|
||
CACHE_GET_STATS: 'cache:getStats',
|
||
// 窗口操作
|
||
WINDOW_MINIMIZE: 'window:minimize',
|
||
WINDOW_MAXIMIZE: 'window:maximize',
|
||
WINDOW_CLOSE: 'window:close',
|
||
// Git/System 操作
|
||
DIALOG_OPEN_DIRECTORY: 'dialog:openDirectory',
|
||
GIT_CLONE: 'git:clone'
|
||
} as const
|
||
|
||
// API 响应类型定义
|
||
interface FileOperationResult {
|
||
success: boolean
|
||
message: string
|
||
path?: string | null
|
||
content?: string | null
|
||
canceled?: boolean
|
||
}
|
||
|
||
interface GitOperationResult {
|
||
success: boolean
|
||
message: string
|
||
stdout?: string
|
||
}
|
||
|
||
interface SettingsOperationResult {
|
||
success: boolean
|
||
message?: string
|
||
data?: unknown
|
||
}
|
||
|
||
interface CacheOperationResult {
|
||
success: boolean
|
||
message?: string
|
||
data?: any
|
||
exists?: boolean
|
||
}
|
||
|
||
interface WindowOperationResult {
|
||
success: boolean
|
||
message?: string
|
||
isMaximized?: boolean
|
||
}
|
||
|
||
// 暴露给渲染进程的 API 接口
|
||
interface ElectronAPI {
|
||
// 文件操作
|
||
file: {
|
||
save: (content: string, filename?: string) => Promise<FileOperationResult>
|
||
read: (filename?: string) => Promise<FileOperationResult>
|
||
openDirectory: () => Promise<FileOperationResult>
|
||
}
|
||
// Git 操作
|
||
git: {
|
||
clone: (repoUrl: string, targetDir: string) => Promise<GitOperationResult>
|
||
onProgress: (callback: (data: { repoUrl: string; raw: string }) => void) => void
|
||
removeListener: () => void
|
||
}
|
||
// 设置操作
|
||
settings: {
|
||
get: (key?: string) => Promise<SettingsOperationResult>
|
||
save: (key: string, value: unknown) => Promise<SettingsOperationResult>
|
||
}
|
||
// 缓存操作
|
||
cache: {
|
||
setJSON: (key: string, data: any, config?: { maxAge?: number; namespace?: string }) => Promise<CacheOperationResult>
|
||
getJSON: (key: string, config?: { maxAge?: number; namespace?: string }) => Promise<CacheOperationResult>
|
||
setBinary: (key: string, buffer: Buffer, type?: 'binary' | 'image', config?: { maxAge?: number; namespace?: string }) => Promise<CacheOperationResult>
|
||
getBinary: (key: string, config?: { maxAge?: number; namespace?: string }) => Promise<CacheOperationResult>
|
||
has: (key: string, config?: { namespace?: string }) => Promise<CacheOperationResult>
|
||
delete: (key: string, namespace?: string) => Promise<CacheOperationResult>
|
||
clearNamespace: (namespace: string) => Promise<CacheOperationResult>
|
||
clearAll: () => Promise<CacheOperationResult>
|
||
getStats: () => Promise<CacheOperationResult>
|
||
}
|
||
// 窗口操作
|
||
window: {
|
||
minimize: () => Promise<WindowOperationResult>
|
||
maximize: () => Promise<WindowOperationResult>
|
||
close: () => Promise<WindowOperationResult>
|
||
}
|
||
}
|
||
|
||
// 通过 contextBridge 安全地暴露 API
|
||
const electronAPI: ElectronAPI = {
|
||
// ============================================
|
||
// 文件操作 API
|
||
// ============================================
|
||
file: {
|
||
/**
|
||
* 保存文件到桌面
|
||
* @param content - 文件内容
|
||
* @param filename - 文件名(可选,默认为 demo-note.txt)
|
||
*/
|
||
save: (content: string, filename?: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.SAVE_FILE, content, filename)
|
||
},
|
||
|
||
/**
|
||
* 从桌面读取文件
|
||
* @param filename - 文件名(可选,默认为 demo-note.txt)
|
||
*/
|
||
read: (filename?: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.READ_FILE, filename)
|
||
},
|
||
|
||
/**
|
||
* 打开目录选择对话框
|
||
*/
|
||
openDirectory: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.DIALOG_OPEN_DIRECTORY)
|
||
}
|
||
},
|
||
|
||
// ============================================
|
||
// Git 操作 API
|
||
// ============================================
|
||
git: {
|
||
/**
|
||
* 克隆 Git 仓库
|
||
* @param repoUrl - 仓库地址
|
||
* @param targetDir - 目标目录
|
||
*/
|
||
clone: (repoUrl: string, targetDir: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.GIT_CLONE, repoUrl, targetDir)
|
||
},
|
||
/**
|
||
* 监听 Git 进度
|
||
*/
|
||
onProgress: (callback: (data: { repoUrl: string; raw: string }) => void) => {
|
||
// 移除旧的监听器以防止重复 (简化处理,实际应该支持多监听器或由调用者管理)
|
||
ipcRenderer.removeAllListeners('git:progress')
|
||
|
||
ipcRenderer.on('git:progress', (_event, data) => {
|
||
callback(data)
|
||
})
|
||
},
|
||
/**
|
||
* 移除监听器
|
||
*/
|
||
removeListener: () => {
|
||
ipcRenderer.removeAllListeners('git:progress')
|
||
}
|
||
},
|
||
|
||
// ============================================
|
||
// 设置操作 API
|
||
// ============================================
|
||
settings: {
|
||
/**
|
||
* 获取用户设置
|
||
* @param key - 设置键名(可选,不传返回所有设置)
|
||
*/
|
||
get: (key?: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.GET_SETTINGS, key)
|
||
},
|
||
|
||
/**
|
||
* 保存用户设置
|
||
* @param key - 设置键名
|
||
* @param value - 设置值
|
||
*/
|
||
save: (key: string, value: unknown) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.SAVE_SETTINGS, key, value)
|
||
}
|
||
},
|
||
|
||
// ============================================
|
||
// 缓存操作 API
|
||
// ============================================
|
||
cache: {
|
||
/**
|
||
* 设置JSON缓存
|
||
*/
|
||
setJSON: (key: string, data: any, config?: { maxAge?: number; namespace?: string }) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_SET_JSON, key, data, config)
|
||
},
|
||
|
||
/**
|
||
* 获取JSON缓存
|
||
*/
|
||
getJSON: (key: string, config?: { maxAge?: number; namespace?: string }) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_JSON, key, config)
|
||
},
|
||
|
||
/**
|
||
* 设置二进制缓存
|
||
*/
|
||
setBinary: (key: string, buffer: Buffer, type?: 'binary' | 'image', config?: { maxAge?: number; namespace?: string }) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_SET_BINARY, key, buffer, type, config)
|
||
},
|
||
|
||
/**
|
||
* 获取二进制缓存
|
||
*/
|
||
getBinary: (key: string, config?: { maxAge?: number; namespace?: string }) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_BINARY, key, config)
|
||
},
|
||
|
||
/**
|
||
* 检查缓存是否存在
|
||
*/
|
||
has: (key: string, config?: { namespace?: string }) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_HAS, key, config)
|
||
},
|
||
|
||
/**
|
||
* 删除单个缓存
|
||
*/
|
||
delete: (key: string, namespace?: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_DELETE, key, namespace)
|
||
},
|
||
|
||
/**
|
||
* 清空命名空间缓存
|
||
*/
|
||
clearNamespace: (namespace: string) => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_CLEAR_NAMESPACE, namespace)
|
||
},
|
||
|
||
/**
|
||
* 清空所有缓存
|
||
*/
|
||
clearAll: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_CLEAR_ALL)
|
||
},
|
||
|
||
/**
|
||
* 获取缓存统计信息
|
||
*/
|
||
getStats: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.CACHE_GET_STATS)
|
||
}
|
||
},
|
||
|
||
// ============================================
|
||
// 窗口操作 API
|
||
// ============================================
|
||
window: {
|
||
/**
|
||
* 最小化窗口
|
||
*/
|
||
minimize: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_MINIMIZE)
|
||
},
|
||
|
||
/**
|
||
* 最大化/还原窗口
|
||
*/
|
||
maximize: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_MAXIMIZE)
|
||
},
|
||
|
||
/**
|
||
* 关闭窗口
|
||
*/
|
||
close: () => {
|
||
return ipcRenderer.invoke(IPC_CHANNELS.WINDOW_CLOSE)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 暴露 API 到 window.electronAPI
|
||
contextBridge.exposeInMainWorld('electronAPI', electronAPI)
|
||
|
||
// TypeScript 类型声明(供渲染进程使用)
|
||
declare global {
|
||
interface Window {
|
||
electronAPI: ElectronAPI
|
||
}
|
||
}
|