998 lines
30 KiB
JavaScript
998 lines
30 KiB
JavaScript
"use strict";
|
||
const electron = require("electron");
|
||
const path = require("path");
|
||
const fsSync = require("fs");
|
||
const Store = require("electron-store");
|
||
const crypto = require("crypto");
|
||
function _interopNamespaceDefault(e) {
|
||
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
||
if (e) {
|
||
for (const k in e) {
|
||
if (k !== "default") {
|
||
const d = Object.getOwnPropertyDescriptor(e, k);
|
||
Object.defineProperty(n, k, d.get ? d : {
|
||
enumerable: true,
|
||
get: () => e[k]
|
||
});
|
||
}
|
||
}
|
||
}
|
||
n.default = e;
|
||
return Object.freeze(n);
|
||
}
|
||
const fsSync__namespace = /* @__PURE__ */ _interopNamespaceDefault(fsSync);
|
||
let store = null;
|
||
function initStore() {
|
||
if (store) {
|
||
console.warn("Store 已经初始化过了");
|
||
return;
|
||
}
|
||
store = new Store({
|
||
// 存储文件名
|
||
name: "asset-pro-config",
|
||
// 默认值
|
||
defaults: {
|
||
settings: {
|
||
count: 0,
|
||
theme: "system"
|
||
},
|
||
windowBounds: {
|
||
width: 1600,
|
||
height: 900
|
||
}
|
||
},
|
||
// Schema 验证(可选但推荐)
|
||
schema: {
|
||
settings: {
|
||
type: "object",
|
||
properties: {
|
||
count: { type: "number", default: 0 },
|
||
theme: {
|
||
type: "string",
|
||
enum: ["light", "dark", "system"],
|
||
default: "system"
|
||
}
|
||
},
|
||
default: {}
|
||
},
|
||
windowBounds: {
|
||
type: "object",
|
||
properties: {
|
||
width: { type: "number", default: 1600 },
|
||
height: { type: "number", default: 900 },
|
||
x: { type: "number" },
|
||
y: { type: "number" }
|
||
},
|
||
default: {}
|
||
}
|
||
}
|
||
});
|
||
console.log("Store 初始化完成,存储路径:", store.path);
|
||
}
|
||
function getStore() {
|
||
if (!store) {
|
||
throw new Error("Store 未初始化,请先调用 initStore()");
|
||
}
|
||
return store;
|
||
}
|
||
function getSettings(key) {
|
||
const s = getStore();
|
||
if (key) {
|
||
return s.get(`settings.${key}`);
|
||
}
|
||
return s.get("settings");
|
||
}
|
||
function saveSettings(key, value) {
|
||
const s = getStore();
|
||
s.set(`settings.${key}`, value);
|
||
}
|
||
function getWindowBounds() {
|
||
const s = getStore();
|
||
const bounds = s.get("windowBounds");
|
||
const newBounds = {
|
||
width: 1600,
|
||
height: 900
|
||
};
|
||
if (bounds.x !== void 0 && bounds.y !== void 0) {
|
||
newBounds.x = bounds.x;
|
||
newBounds.y = bounds.y;
|
||
}
|
||
if (bounds.width !== 1600 || bounds.height !== 900) {
|
||
s.set("windowBounds", newBounds);
|
||
}
|
||
return newBounds;
|
||
}
|
||
function saveWindowBounds(bounds) {
|
||
const s = getStore();
|
||
s.set("windowBounds", bounds);
|
||
}
|
||
class CacheManager {
|
||
constructor() {
|
||
this.cacheDir = "";
|
||
this.metadataMap = /* @__PURE__ */ new Map();
|
||
this.initialized = false;
|
||
}
|
||
/**
|
||
* 初始化缓存管理器
|
||
* 必须在 app.whenReady() 之后调用
|
||
*/
|
||
async init() {
|
||
if (this.initialized) {
|
||
console.warn("CacheManager 已经初始化过了");
|
||
return;
|
||
}
|
||
try {
|
||
const isDev = !electron.app.isPackaged;
|
||
if (isDev) {
|
||
this.cacheDir = path.join(process.cwd(), ".cache");
|
||
} else {
|
||
const exePath = process.execPath;
|
||
const exeDir = path.dirname(exePath);
|
||
this.cacheDir = path.join(exeDir, "cache");
|
||
}
|
||
await fsSync.promises.mkdir(this.cacheDir, { recursive: true });
|
||
await this.loadMetadata();
|
||
this.initialized = true;
|
||
console.log("CacheManager 初始化完成");
|
||
console.log("缓存目录:", this.cacheDir);
|
||
console.log("当前环境:", isDev ? "开发环境" : "生产环境");
|
||
} catch (error) {
|
||
console.error("CacheManager 初始化失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
/**
|
||
* 确保缓存管理器已初始化
|
||
*/
|
||
ensureInitialized() {
|
||
if (!this.initialized) {
|
||
throw new Error("CacheManager 未初始化,请先调用 init()");
|
||
}
|
||
}
|
||
/**
|
||
* 生成缓存键的哈希值(用于文件名)
|
||
*/
|
||
hashKey(key) {
|
||
return crypto.createHash("md5").update(key).digest("hex");
|
||
}
|
||
/**
|
||
* 获取缓存文件路径
|
||
*/
|
||
getCacheFilePath(key, namespace) {
|
||
const hash = this.hashKey(key);
|
||
if (namespace) {
|
||
const namespaceDir = path.join(this.cacheDir, namespace);
|
||
return path.join(namespaceDir, hash);
|
||
}
|
||
return path.join(this.cacheDir, hash);
|
||
}
|
||
/**
|
||
* 获取元数据文件路径
|
||
*/
|
||
getMetadataPath() {
|
||
return path.join(this.cacheDir, "_metadata.json");
|
||
}
|
||
/**
|
||
* 加载元数据
|
||
*/
|
||
async loadMetadata() {
|
||
try {
|
||
const metadataPath = this.getMetadataPath();
|
||
const exists = await fsSync.promises.access(metadataPath).then(() => true).catch(() => false);
|
||
if (exists) {
|
||
const content = await fsSync.promises.readFile(metadataPath, "utf-8");
|
||
const data = JSON.parse(content);
|
||
this.metadataMap = new Map(Object.entries(data));
|
||
console.log(`加载了 ${this.metadataMap.size} 条缓存元数据`);
|
||
}
|
||
} catch (error) {
|
||
console.warn("加载缓存元数据失败:", error);
|
||
this.metadataMap = /* @__PURE__ */ new Map();
|
||
}
|
||
}
|
||
/**
|
||
* 保存元数据
|
||
*/
|
||
async saveMetadata() {
|
||
try {
|
||
const metadataPath = this.getMetadataPath();
|
||
const data = Object.fromEntries(this.metadataMap);
|
||
await fsSync.promises.writeFile(metadataPath, JSON.stringify(data, null, 2), "utf-8");
|
||
} catch (error) {
|
||
console.error("保存缓存元数据失败:", error);
|
||
}
|
||
}
|
||
/**
|
||
* 检查缓存是否过期
|
||
*/
|
||
isExpired(metadata) {
|
||
if (!metadata.ttl) return false;
|
||
const now = Date.now();
|
||
return now - metadata.updatedAt > metadata.ttl;
|
||
}
|
||
/**
|
||
* 设置缓存 (JSON数据)
|
||
*/
|
||
async setJSON(key, data, config) {
|
||
var _a;
|
||
this.ensureInitialized();
|
||
try {
|
||
const namespace = config == null ? void 0 : config.namespace;
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
if (namespace) {
|
||
const namespaceDir = path.join(this.cacheDir, namespace);
|
||
await fsSync.promises.mkdir(namespaceDir, { recursive: true });
|
||
}
|
||
const jsonString = JSON.stringify(data, null, 2);
|
||
await fsSync.promises.writeFile(filePath, jsonString, "utf-8");
|
||
const stats = await fsSync.promises.stat(filePath);
|
||
const metadata = {
|
||
key,
|
||
type: "json",
|
||
createdAt: ((_a = this.metadataMap.get(key)) == null ? void 0 : _a.createdAt) || Date.now(),
|
||
updatedAt: Date.now(),
|
||
size: stats.size,
|
||
ttl: config == null ? void 0 : config.maxAge
|
||
};
|
||
this.metadataMap.set(key, metadata);
|
||
await this.saveMetadata();
|
||
console.log(`缓存已设置: ${key} (${stats.size} bytes)`);
|
||
} catch (error) {
|
||
console.error(`设置缓存失败 [${key}]:`, error);
|
||
throw error;
|
||
}
|
||
}
|
||
/**
|
||
* 获取缓存 (JSON数据)
|
||
*/
|
||
async getJSON(key, config) {
|
||
this.ensureInitialized();
|
||
try {
|
||
const metadata = this.metadataMap.get(key);
|
||
if (!metadata || metadata.type !== "json") {
|
||
console.log(`缓存不存在或类型不匹配: ${key}`);
|
||
return null;
|
||
}
|
||
if (this.isExpired(metadata)) {
|
||
console.log(`缓存已过期: ${key}`);
|
||
await this.delete(key, config == null ? void 0 : config.namespace);
|
||
return null;
|
||
}
|
||
const namespace = config == null ? void 0 : config.namespace;
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
const content = await fsSync.promises.readFile(filePath, "utf-8");
|
||
const data = JSON.parse(content);
|
||
console.log(`读取缓存: ${key}`);
|
||
return data;
|
||
} catch (error) {
|
||
console.error(`读取缓存失败 [${key}]:`, error);
|
||
return null;
|
||
}
|
||
}
|
||
/**
|
||
* 设置缓存 (二进制数据 - 用于图片等)
|
||
*/
|
||
async setBinary(key, buffer, type = "binary", config) {
|
||
var _a;
|
||
this.ensureInitialized();
|
||
try {
|
||
const namespace = config == null ? void 0 : config.namespace;
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
if (namespace) {
|
||
const namespaceDir = path.join(this.cacheDir, namespace);
|
||
await fsSync.promises.mkdir(namespaceDir, { recursive: true });
|
||
}
|
||
await fsSync.promises.writeFile(filePath, buffer);
|
||
const stats = await fsSync.promises.stat(filePath);
|
||
const metadata = {
|
||
key,
|
||
type,
|
||
createdAt: ((_a = this.metadataMap.get(key)) == null ? void 0 : _a.createdAt) || Date.now(),
|
||
updatedAt: Date.now(),
|
||
size: stats.size,
|
||
ttl: config == null ? void 0 : config.maxAge
|
||
};
|
||
this.metadataMap.set(key, metadata);
|
||
await this.saveMetadata();
|
||
console.log(`二进制缓存已设置: ${key} (${stats.size} bytes)`);
|
||
} catch (error) {
|
||
console.error(`设置二进制缓存失败 [${key}]:`, error);
|
||
throw error;
|
||
}
|
||
}
|
||
/**
|
||
* 获取缓存 (二进制数据)
|
||
*/
|
||
async getBinary(key, config) {
|
||
this.ensureInitialized();
|
||
try {
|
||
const metadata = this.metadataMap.get(key);
|
||
if (!metadata || metadata.type !== "binary" && metadata.type !== "image") {
|
||
console.log(`二进制缓存不存在或类型不匹配: ${key}`);
|
||
return null;
|
||
}
|
||
if (this.isExpired(metadata)) {
|
||
console.log(`二进制缓存已过期: ${key}`);
|
||
await this.delete(key, config == null ? void 0 : config.namespace);
|
||
return null;
|
||
}
|
||
const namespace = config == null ? void 0 : config.namespace;
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
const buffer = await fsSync.promises.readFile(filePath);
|
||
console.log(`读取二进制缓存: ${key}`);
|
||
return buffer;
|
||
} catch (error) {
|
||
console.error(`读取二进制缓存失败 [${key}]:`, error);
|
||
return null;
|
||
}
|
||
}
|
||
/**
|
||
* 检查缓存是否存在
|
||
*/
|
||
async has(key, config) {
|
||
this.ensureInitialized();
|
||
try {
|
||
const metadata = this.metadataMap.get(key);
|
||
if (!metadata) return false;
|
||
if (this.isExpired(metadata)) {
|
||
await this.delete(key, config == null ? void 0 : config.namespace);
|
||
return false;
|
||
}
|
||
const namespace = config == null ? void 0 : config.namespace;
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
const exists = await fsSync.promises.access(filePath).then(() => true).catch(() => false);
|
||
return exists;
|
||
} catch (error) {
|
||
console.error(`检查缓存失败 [${key}]:`, error);
|
||
return false;
|
||
}
|
||
}
|
||
/**
|
||
* 删除单个缓存
|
||
*/
|
||
async delete(key, namespace) {
|
||
this.ensureInitialized();
|
||
try {
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
await fsSync.promises.unlink(filePath).catch(() => {
|
||
});
|
||
this.metadataMap.delete(key);
|
||
await this.saveMetadata();
|
||
console.log(`缓存已删除: ${key}`);
|
||
} catch (error) {
|
||
console.error(`删除缓存失败 [${key}]:`, error);
|
||
}
|
||
}
|
||
/**
|
||
* 清空指定命名空间的所有缓存
|
||
*/
|
||
async clearNamespace(namespace) {
|
||
this.ensureInitialized();
|
||
try {
|
||
const namespaceDir = path.join(this.cacheDir, namespace);
|
||
await fsSync.promises.rm(namespaceDir, { recursive: true, force: true });
|
||
const keysToDelete = [];
|
||
this.metadataMap.forEach((metadata, key) => {
|
||
const filePath = this.getCacheFilePath(key, namespace);
|
||
if (filePath.startsWith(namespaceDir)) {
|
||
keysToDelete.push(key);
|
||
}
|
||
});
|
||
keysToDelete.forEach((key) => this.metadataMap.delete(key));
|
||
await this.saveMetadata();
|
||
console.log(`命名空间缓存已清空: ${namespace} (${keysToDelete.length} 项)`);
|
||
} catch (error) {
|
||
console.error(`清空命名空间缓存失败 [${namespace}]:`, error);
|
||
}
|
||
}
|
||
/**
|
||
* 清空所有缓存
|
||
*/
|
||
async clearAll() {
|
||
this.ensureInitialized();
|
||
try {
|
||
const files = await fsSync.promises.readdir(this.cacheDir, { withFileTypes: true });
|
||
for (const file of files) {
|
||
const filePath = path.join(this.cacheDir, file.name);
|
||
if (file.name === "_metadata.json") continue;
|
||
if (file.isDirectory()) {
|
||
await fsSync.promises.rm(filePath, { recursive: true, force: true });
|
||
} else {
|
||
await fsSync.promises.unlink(filePath);
|
||
}
|
||
}
|
||
this.metadataMap.clear();
|
||
await this.saveMetadata();
|
||
console.log("所有缓存已清空");
|
||
} catch (error) {
|
||
console.error("清空所有缓存失败:", error);
|
||
}
|
||
}
|
||
/**
|
||
* 获取缓存统计信息
|
||
*/
|
||
async getStats() {
|
||
this.ensureInitialized();
|
||
let totalSize = 0;
|
||
this.metadataMap.forEach((metadata) => {
|
||
totalSize += metadata.size;
|
||
});
|
||
return {
|
||
totalItems: this.metadataMap.size,
|
||
totalSize,
|
||
cacheDir: this.cacheDir
|
||
};
|
||
}
|
||
/**
|
||
* 获取所有缓存键
|
||
*/
|
||
async getAllKeys() {
|
||
this.ensureInitialized();
|
||
return Array.from(this.metadataMap.keys());
|
||
}
|
||
}
|
||
const cacheManager = new CacheManager();
|
||
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"
|
||
};
|
||
function setupIpcHandlers() {
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.SAVE_FILE,
|
||
async (_event, content, filename = "demo-note.txt") => {
|
||
try {
|
||
const desktopPath = electron.app.getPath("desktop");
|
||
const filePath = path.join(desktopPath, filename);
|
||
await fsSync.promises.writeFile(filePath, content, "utf-8");
|
||
return {
|
||
success: true,
|
||
message: `文件已保存到: ${filePath}`,
|
||
path: filePath
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("保存文件失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `保存失败: ${errorMessage}`,
|
||
path: null
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.READ_FILE,
|
||
async (_event, filename = "demo-note.txt") => {
|
||
try {
|
||
const desktopPath = electron.app.getPath("desktop");
|
||
const filePath = path.join(desktopPath, filename);
|
||
try {
|
||
await fsSync.promises.access(filePath);
|
||
} catch {
|
||
return {
|
||
success: false,
|
||
message: "文件不存在,请先保存一个文件",
|
||
content: null
|
||
};
|
||
}
|
||
const content = await fsSync.promises.readFile(filePath, "utf-8");
|
||
return {
|
||
success: true,
|
||
message: "文件读取成功",
|
||
content
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("读取文件失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `读取失败: ${errorMessage}`,
|
||
content: null
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(IPC_CHANNELS.GET_SETTINGS, async (_event, key) => {
|
||
try {
|
||
const settings = getSettings(key);
|
||
return {
|
||
success: true,
|
||
data: settings
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("获取设置失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
data: null,
|
||
message: errorMessage
|
||
};
|
||
}
|
||
});
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.SAVE_SETTINGS,
|
||
async (_event, key, value) => {
|
||
try {
|
||
saveSettings(key, value);
|
||
return {
|
||
success: true,
|
||
message: "设置已保存"
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("保存设置失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `保存失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_SET_JSON,
|
||
async (_event, key, data, config) => {
|
||
try {
|
||
await cacheManager.setJSON(key, data, config);
|
||
return {
|
||
success: true,
|
||
message: "缓存已设置"
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("设置JSON缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `设置失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_GET_JSON,
|
||
async (_event, key, config) => {
|
||
try {
|
||
const data = await cacheManager.getJSON(key, config);
|
||
return {
|
||
success: true,
|
||
data
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("获取JSON缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
data: null,
|
||
message: errorMessage
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_SET_BINARY,
|
||
async (_event, key, buffer, type = "binary", config) => {
|
||
try {
|
||
await cacheManager.setBinary(key, buffer, type, config);
|
||
return {
|
||
success: true,
|
||
message: "二进制缓存已设置"
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("设置二进制缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `设置失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_GET_BINARY,
|
||
async (_event, key, config) => {
|
||
try {
|
||
const buffer = await cacheManager.getBinary(key, config);
|
||
return {
|
||
success: true,
|
||
data: buffer
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("获取二进制缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
data: null,
|
||
message: errorMessage
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_HAS,
|
||
async (_event, key, config) => {
|
||
try {
|
||
const exists = await cacheManager.has(key, config);
|
||
return {
|
||
success: true,
|
||
exists
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("检查缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
exists: false,
|
||
message: errorMessage
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_DELETE,
|
||
async (_event, key, namespace) => {
|
||
try {
|
||
await cacheManager.delete(key, namespace);
|
||
return {
|
||
success: true,
|
||
message: "缓存已删除"
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("删除缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `删除失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_CLEAR_NAMESPACE,
|
||
async (_event, namespace) => {
|
||
try {
|
||
await cacheManager.clearNamespace(namespace);
|
||
return {
|
||
success: true,
|
||
message: `命名空间 ${namespace} 的缓存已清空`
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("清空命名空间缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `清空失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_CLEAR_ALL,
|
||
async (_event) => {
|
||
try {
|
||
await cacheManager.clearAll();
|
||
return {
|
||
success: true,
|
||
message: "所有缓存已清空"
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("清空所有缓存失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
message: `清空失败: ${errorMessage}`
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(
|
||
IPC_CHANNELS.CACHE_GET_STATS,
|
||
async (_event) => {
|
||
try {
|
||
const stats = await cacheManager.getStats();
|
||
return {
|
||
success: true,
|
||
data: stats
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("获取缓存统计信息失败:", errorMessage);
|
||
return {
|
||
success: false,
|
||
data: null,
|
||
message: errorMessage
|
||
};
|
||
}
|
||
}
|
||
);
|
||
electron.ipcMain.handle(IPC_CHANNELS.WINDOW_MINIMIZE, async (event) => {
|
||
try {
|
||
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
||
if (window) {
|
||
window.minimize();
|
||
return { success: true };
|
||
}
|
||
return { success: false, message: "无法找到窗口" };
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("最小化窗口失败:", errorMessage);
|
||
return { success: false, message: errorMessage };
|
||
}
|
||
});
|
||
electron.ipcMain.handle(IPC_CHANNELS.WINDOW_MAXIMIZE, async (event) => {
|
||
try {
|
||
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
||
if (window) {
|
||
if (window.isMaximized()) {
|
||
window.unmaximize();
|
||
} else {
|
||
window.maximize();
|
||
}
|
||
return { success: true, isMaximized: window.isMaximized() };
|
||
}
|
||
return { success: false, message: "无法找到窗口" };
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("最大化窗口失败:", errorMessage);
|
||
return { success: false, message: errorMessage };
|
||
}
|
||
});
|
||
electron.ipcMain.handle(IPC_CHANNELS.WINDOW_CLOSE, async (event) => {
|
||
try {
|
||
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
||
if (window) {
|
||
window.close();
|
||
return { success: true };
|
||
}
|
||
return { success: false, message: "无法找到窗口" };
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("关闭窗口失败:", errorMessage);
|
||
return { success: false, message: errorMessage };
|
||
}
|
||
});
|
||
electron.ipcMain.handle(IPC_CHANNELS.DIALOG_OPEN_DIRECTORY, async (event) => {
|
||
try {
|
||
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
||
if (!window) return { success: false, message: "无法找到窗口" };
|
||
const result = await electron.dialog.showOpenDialog(window, {
|
||
properties: ["openDirectory", "createDirectory"]
|
||
});
|
||
if (result.canceled) {
|
||
return { success: false, canceled: true };
|
||
}
|
||
return {
|
||
success: true,
|
||
path: result.filePaths[0],
|
||
canceled: false
|
||
};
|
||
} catch (error) {
|
||
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
||
console.error("打开目录失败:", errorMessage);
|
||
return { success: false, message: errorMessage };
|
||
}
|
||
});
|
||
electron.ipcMain.handle(IPC_CHANNELS.GIT_CLONE, async (event, repoUrl, targetDir) => {
|
||
return new Promise((resolve) => {
|
||
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
||
try {
|
||
if (!fsSync__namespace.existsSync(targetDir)) {
|
||
fsSync__namespace.mkdirSync(targetDir, { recursive: true });
|
||
} else {
|
||
const files = fsSync__namespace.readdirSync(targetDir);
|
||
if (files.length > 0) {
|
||
return resolve({
|
||
success: false,
|
||
message: `目标文件夹不为空。请选择一个空文件夹。`
|
||
});
|
||
}
|
||
}
|
||
} catch (err) {
|
||
return resolve({ success: false, message: `检查目录失败: ${err}` });
|
||
}
|
||
console.log(`开始 Git Clone (spawn): ${repoUrl} -> ${targetDir}`);
|
||
const { spawn } = require("child_process");
|
||
const child = spawn("git", ["clone", "--progress", repoUrl, "."], { cwd: targetDir });
|
||
let stdoutData = "";
|
||
let stderrData = "";
|
||
child.stdout.on("data", (data) => {
|
||
const text = data.toString();
|
||
stdoutData += text;
|
||
console.log("Git Stdout:", text);
|
||
});
|
||
child.stderr.on("data", (data) => {
|
||
const text = data.toString();
|
||
stderrData += text;
|
||
if (window) {
|
||
window.webContents.send("git:progress", {
|
||
repoUrl,
|
||
raw: text
|
||
});
|
||
}
|
||
});
|
||
child.on("close", (code) => {
|
||
console.log(`Git clone process exited with code ${code}`);
|
||
if (code === 0) {
|
||
resolve({
|
||
success: true,
|
||
message: "项目克隆成功",
|
||
stdout: stdoutData
|
||
});
|
||
} else {
|
||
resolve({
|
||
success: false,
|
||
message: `Git clone 失败 (Code ${code})`,
|
||
stdout: stderrData
|
||
// git 错误通常在 stderr
|
||
});
|
||
}
|
||
});
|
||
child.on("error", (err) => {
|
||
console.error("Git spawn error:", err);
|
||
resolve({
|
||
success: false,
|
||
message: `启动 Git 进程失败: ${err.message}`
|
||
});
|
||
});
|
||
});
|
||
});
|
||
}
|
||
const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"];
|
||
let mainWindow = null;
|
||
function createWindow() {
|
||
const bounds = getWindowBounds();
|
||
const windowOptions = {
|
||
width: bounds.width,
|
||
height: bounds.height,
|
||
webPreferences: {
|
||
// 安全配置:启用上下文隔离
|
||
contextIsolation: true,
|
||
// 安全配置:禁用 Node.js 集成
|
||
nodeIntegration: false,
|
||
// 预加载脚本路径
|
||
preload: path.join(__dirname, "preload.js"),
|
||
// 启用沙盒模式
|
||
sandbox: false
|
||
// 需要设为 false 才能使用 preload
|
||
},
|
||
// 窗口样式
|
||
title: "AssetPro",
|
||
show: false,
|
||
// 先隐藏,等准备好再显示
|
||
backgroundColor: "#ffffff",
|
||
// 无边框窗口
|
||
frame: false
|
||
};
|
||
if (bounds.x !== void 0 && bounds.y !== void 0) {
|
||
windowOptions.x = bounds.x;
|
||
windowOptions.y = bounds.y;
|
||
} else {
|
||
windowOptions.center = true;
|
||
}
|
||
mainWindow = new electron.BrowserWindow(windowOptions);
|
||
mainWindow.once("ready-to-show", () => {
|
||
mainWindow == null ? void 0 : mainWindow.show();
|
||
});
|
||
setTimeout(() => {
|
||
if (mainWindow && !mainWindow.isVisible()) {
|
||
console.log("超时后强制显示窗口");
|
||
mainWindow.show();
|
||
}
|
||
}, 3e3);
|
||
mainWindow.on("close", () => {
|
||
if (mainWindow) {
|
||
const bounds2 = mainWindow.getBounds();
|
||
saveWindowBounds(bounds2);
|
||
}
|
||
});
|
||
if (VITE_DEV_SERVER_URL) {
|
||
mainWindow.loadURL(VITE_DEV_SERVER_URL);
|
||
} else {
|
||
const fs = require("fs");
|
||
const possiblePaths = [
|
||
path.join(electron.app.getAppPath(), "dist-renderer", "index.html"),
|
||
// asar 内部(主要路径)
|
||
path.join(process.resourcesPath, "dist-renderer", "index.html"),
|
||
// resources/dist-renderer(如果 extraResources 存在)
|
||
path.join(process.resourcesPath, "dist", "index.html")
|
||
// resources/dist(备用)
|
||
];
|
||
console.log("尝试加载页面,检查以下路径:");
|
||
possiblePaths.forEach((p) => {
|
||
const exists = fs.existsSync(p);
|
||
console.log(` ${exists ? "✓" : "✗"} ${p}`);
|
||
});
|
||
console.log("process.resourcesPath:", process.resourcesPath);
|
||
console.log("app.getAppPath():", electron.app.getAppPath());
|
||
let indexPath = null;
|
||
for (const testPath of possiblePaths) {
|
||
if (fs.existsSync(testPath)) {
|
||
indexPath = testPath;
|
||
console.log("找到页面文件:", indexPath);
|
||
break;
|
||
}
|
||
}
|
||
if (!indexPath) {
|
||
console.error("无法找到 index.html 文件!");
|
||
mainWindow.loadURL("data:text/html,<h1>无法找到页面文件</h1><p>请检查控制台输出</p>");
|
||
return;
|
||
}
|
||
mainWindow.loadFile(indexPath).catch((error) => {
|
||
console.error("loadFile 失败:", error);
|
||
let fileUrl = indexPath.replace(/\\/g, "/");
|
||
if (fileUrl.match(/^[A-Z]:/)) {
|
||
fileUrl = `file:///${fileUrl}`;
|
||
} else {
|
||
fileUrl = `file://${fileUrl}`;
|
||
}
|
||
console.log("尝试使用 loadURL:", fileUrl);
|
||
mainWindow.loadURL(fileUrl).catch((urlError) => {
|
||
console.error("loadURL 也失败:", urlError);
|
||
mainWindow.loadURL("data:text/html,<h1>页面加载失败</h1><p>请查看控制台错误信息</p>");
|
||
});
|
||
});
|
||
}
|
||
mainWindow.webContents.on("did-fail-load", (event, errorCode, errorDescription) => {
|
||
console.error("页面加载失败:", errorCode, errorDescription);
|
||
});
|
||
mainWindow.webContents.on("before-input-event", (event, input) => {
|
||
if (input.key === "F12" || input.key === "f12" || input.code === "F12") {
|
||
if (mainWindow) {
|
||
if (mainWindow.webContents.isDevToolsOpened()) {
|
||
mainWindow.webContents.closeDevTools();
|
||
} else {
|
||
mainWindow.webContents.openDevTools();
|
||
}
|
||
}
|
||
event.preventDefault();
|
||
}
|
||
});
|
||
electron.globalShortcut.register("F12", () => {
|
||
if (mainWindow) {
|
||
if (mainWindow.webContents.isDevToolsOpened()) {
|
||
mainWindow.webContents.closeDevTools();
|
||
} else {
|
||
mainWindow.webContents.openDevTools();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
electron.app.whenReady().then(async () => {
|
||
initStore();
|
||
await cacheManager.init();
|
||
setupIpcHandlers();
|
||
createWindow();
|
||
electron.app.on("activate", () => {
|
||
if (electron.BrowserWindow.getAllWindows().length === 0) {
|
||
createWindow();
|
||
}
|
||
});
|
||
});
|
||
electron.app.on("window-all-closed", () => {
|
||
if (process.platform !== "darwin") {
|
||
electron.app.quit();
|
||
}
|
||
});
|
||
electron.app.on("will-quit", () => {
|
||
electron.globalShortcut.unregisterAll();
|
||
});
|