Initial clean project import
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
import archiver from "archiver";
|
||||
import axios from "axios";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import yauzl from "yauzl";
|
||||
|
||||
const getZipFileContent = async (path: string, pathInZip: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// console.log('getZipFileContent', path, pathInZip)
|
||||
yauzl.open(path, {lazyEntries: true}, (err: any, zipfile: any) => {
|
||||
if (err) {
|
||||
// console.log('getZipFileContent err', err)
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
zipfile.on("error", function (err: any) {
|
||||
// console.log('getZipFileContent error', err)
|
||||
reject(err);
|
||||
});
|
||||
zipfile.on("end", function () {
|
||||
// console.log('getZipFileContent end')
|
||||
reject("FileNotFound");
|
||||
});
|
||||
zipfile.on("entry", function (entry: any) {
|
||||
// console.log('getZipFileContent entry', entry.fileName)
|
||||
if (entry.fileName === pathInZip) {
|
||||
zipfile.openReadStream(entry, function (err: any, readStream: any) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
let chunks: any[] = [];
|
||||
readStream.on("data", function (chunk: any) {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
readStream.on("end", function () {
|
||||
const bytes = Buffer.concat(chunks);
|
||||
const text = bytes.toString("utf8");
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
zipfile.readEntry();
|
||||
}
|
||||
});
|
||||
zipfile.readEntry();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const unzip = async (
|
||||
zipPath: string,
|
||||
dest: string,
|
||||
option?: {
|
||||
process: (type: "start" | "end", entry: any) => void;
|
||||
}
|
||||
) => {
|
||||
option = Object.assign(
|
||||
{
|
||||
process: null,
|
||||
},
|
||||
option
|
||||
);
|
||||
if (!fs.existsSync(dest)) {
|
||||
fs.mkdirSync(dest, {recursive: true});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
// console.log('unzip', zipPath, dest)
|
||||
yauzl.open(zipPath, {lazyEntries: true}, (err: any, zipfile: any) => {
|
||||
if (err) {
|
||||
// console.log('unzip err', err)
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
zipfile.on("error", function (err: any) {
|
||||
// console.log('unzip error', err)
|
||||
reject(err);
|
||||
});
|
||||
zipfile.on("end", function () {
|
||||
// console.log('unzip end')
|
||||
resolve(undefined);
|
||||
});
|
||||
zipfile.on("entry", function (entry: any) {
|
||||
if (option.process) {
|
||||
option.process("start", entry);
|
||||
}
|
||||
// console.log('unzip entry', dest, entry.fileName)
|
||||
const destPath = dest + "/" + entry.fileName;
|
||||
if (/\/$/.test(entry.fileName)) {
|
||||
// console.log('unzip mkdir', destPath)
|
||||
fs.mkdirSync(destPath, {recursive: true});
|
||||
zipfile.readEntry();
|
||||
} else {
|
||||
const dirname = destPath.replace(/\/[^/]+$/, "");
|
||||
if (!fs.existsSync(dirname)) {
|
||||
fs.mkdirSync(dirname, {recursive: true});
|
||||
}
|
||||
zipfile.openReadStream(entry, function (err: any, readStream: any) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
readStream.on("end", function () {
|
||||
if (option.process) {
|
||||
option.process("end", entry);
|
||||
}
|
||||
zipfile.readEntry();
|
||||
});
|
||||
readStream.pipe(fs.createWriteStream(destPath));
|
||||
});
|
||||
}
|
||||
});
|
||||
zipfile.readEntry();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const zip = async (
|
||||
zipPath: string,
|
||||
sourceDir: string,
|
||||
option?: {
|
||||
end?: (archive: any) => Promise<void>;
|
||||
filter?: (params: { name: string, path: string, fullPath: string, isDir: boolean }) => Promise<boolean>;
|
||||
}
|
||||
): Promise<void> => {
|
||||
option = Object.assign(
|
||||
{
|
||||
end: null,
|
||||
filter: null,
|
||||
},
|
||||
option
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(zipPath);
|
||||
const archive = archiver("zip", {
|
||||
zlib: {level: 9},
|
||||
});
|
||||
output.on("close", function () {
|
||||
resolve(undefined);
|
||||
});
|
||||
archive.on("error", function (err: any) {
|
||||
reject(err);
|
||||
});
|
||||
archive.pipe(output);
|
||||
|
||||
const addFiles = async (dir: string, relativePath: string = "") => {
|
||||
const items = fs.readdirSync(path.join(dir, relativePath));
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, relativePath, item);
|
||||
const relPath = path.join(relativePath, item).replace(/\\/g, "/"); // Normalize for zip
|
||||
const stat = fs.statSync(fullPath);
|
||||
const isDir = stat.isDirectory();
|
||||
const shouldInclude = !option.filter || await option.filter({
|
||||
name: item,
|
||||
path: relPath,
|
||||
fullPath,
|
||||
isDir
|
||||
});
|
||||
if (isDir) {
|
||||
if (shouldInclude) {
|
||||
await addFiles(dir, relPath);
|
||||
}
|
||||
} else {
|
||||
if (shouldInclude) {
|
||||
archive.file(fullPath, {name: relPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addFiles(sourceDir).then(async () => {
|
||||
if (option.end) {
|
||||
await option.end(archive);
|
||||
}
|
||||
archive.finalize();
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
const request = async (option: {
|
||||
url: string,
|
||||
method?: "GET" | "POST";
|
||||
responseType?: "json" | "text" | "arraybuffer";
|
||||
headers?: any;
|
||||
data?: any;
|
||||
}) => {
|
||||
option = Object.assign({
|
||||
url: "",
|
||||
method: "GET",
|
||||
responseType: "json",
|
||||
headers: {},
|
||||
data: null,
|
||||
}, option);
|
||||
const response = await axios.request({
|
||||
url: option.url,
|
||||
method: option.method,
|
||||
responseType: option.responseType === "arraybuffer" ? "arraybuffer" : "text",
|
||||
headers: option.headers,
|
||||
data: option.data,
|
||||
});
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Request failed with status code ${response.status}`);
|
||||
}
|
||||
if (option.responseType === "json") {
|
||||
return JSON.parse(response.data);
|
||||
} else if (option.responseType === "text") {
|
||||
return response.data;
|
||||
} else if (option.responseType === "arraybuffer") {
|
||||
return Buffer.from(response.data);
|
||||
} else {
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const Misc = {
|
||||
getZipFileContent,
|
||||
unzip,
|
||||
zip,
|
||||
request,
|
||||
};
|
||||
|
||||
export default Misc;
|
||||
@@ -0,0 +1,28 @@
|
||||
import {ipcMain} from "electron";
|
||||
|
||||
import index from "./index";
|
||||
|
||||
// 注册所有 IPC 处理器,这样 render.ts 就不需要导入 Node.js 模块
|
||||
ipcMain.handle("misc:getZipFileContent", async (_, path: string, pathInZip: string) => {
|
||||
return await index.getZipFileContent(path, pathInZip);
|
||||
});
|
||||
|
||||
ipcMain.handle("misc:unzip", async (_, zipPath: string, dest: string, option?: any) => {
|
||||
return await index.unzip(zipPath, dest, option);
|
||||
});
|
||||
|
||||
ipcMain.handle("misc:zip", async (_, zipPath: string, sourceDir: string, option?: any) => {
|
||||
return await index.zip(zipPath, sourceDir, option);
|
||||
});
|
||||
|
||||
ipcMain.handle("misc:request", async (_, requestOption: any) => {
|
||||
return await index.request(requestOption);
|
||||
});
|
||||
|
||||
export default {
|
||||
...index,
|
||||
};
|
||||
|
||||
export const MiscMain = {
|
||||
...index,
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
// 🔧 纯 IPC 包装 - 不导入 Node.js 模块(特别是 archiver),防止被打包到渲染进程
|
||||
export default {
|
||||
getZipFileContent: async (path: string, pathInZip: string) => {
|
||||
if (!ipcRenderer) {
|
||||
throw new Error('IPC 接口不可用');
|
||||
}
|
||||
return await ipcRenderer.invoke("misc:getZipFileContent", path, pathInZip);
|
||||
},
|
||||
|
||||
unzip: async (zipPath: string, dest: string, option?: any) => {
|
||||
if (!ipcRenderer) {
|
||||
throw new Error('IPC 接口不可用');
|
||||
}
|
||||
return await ipcRenderer.invoke("misc:unzip", zipPath, dest, option);
|
||||
},
|
||||
|
||||
zip: async (zipPath: string, sourceDir: string, option?: any) => {
|
||||
if (!ipcRenderer) {
|
||||
throw new Error('IPC 接口不可用');
|
||||
}
|
||||
return await ipcRenderer.invoke("misc:zip", zipPath, sourceDir, option);
|
||||
},
|
||||
|
||||
request: async (requestOption: any) => {
|
||||
if (!ipcRenderer) {
|
||||
throw new Error('IPC 接口不可用');
|
||||
}
|
||||
return await ipcRenderer.invoke("misc:request", requestOption);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user