refactor: upgrade

This commit is contained in:
linyuchen 2024-03-19 16:32:12 +08:00
parent 3a964af0b0
commit 37c4f02118
3 changed files with 70 additions and 45 deletions

View File

@ -1,4 +1,5 @@
import fs from "fs";
import fsPromise from "fs/promises";
import crypto from "crypto";
import ffmpeg from "fluent-ffmpeg";
import util from "util";
@ -10,7 +11,7 @@ import {getConfigUtil} from "../config";
import {dbUtil} from "../db";
import * as fileType from "file-type";
import {net} from "electron";
import ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions;
import ClientRequestConstructorOptions = Electron.Main.ClientRequestConstructorOptions;
export function isGIF(path: string) {
const buffer = Buffer.alloc(4);
@ -270,24 +271,34 @@ export function calculateFileMD5(filePath: string): Promise<string> {
});
}
export function httpDownload(options: ClientRequestConstructorOptions | string): Promise<Buffer> {
export interface HttpDownloadOptions {
url: string;
headers?: Record<string, string> | string;
}
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
let chunks: Buffer[] = [];
let netRequest = net.request(options)
return new Promise((resolve, reject) => {
netRequest.on("response", (response) => {
if (!(response.statusCode >= 200 && response.statusCode < 300)) {
return reject(new Error(`下载失败,状态码${response.statusCode}`))
let url: string;
let headers: Record<string, string> = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
};
if (typeof options === "string") {
url = options;
} else {
url = options.url;
if (options.headers) {
if (typeof options.headers === "string") {
headers = JSON.parse(options.headers);
} else {
headers = options.headers;
}
response.on("data", (chunk) => {
chunks.push(chunk);
}).on("end", () => {
resolve(Buffer.concat(chunks));
})
}).on("error", (err) => {
reject(err);
})
netRequest.end()
})
}
}
const fetchRes = await net.fetch(url, headers);
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`)
const blob = await fetchRes.blob();
let buffer = await blob.arrayBuffer();
return Buffer.from(buffer);
}
type Uri2LocalRes = {
@ -334,19 +345,13 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
}
} else if (url.protocol == "http:" || url.protocol == "https:") {
// 下载文件
let fetchRes: Response;
try {
fetchRes = await fetch(url)
} catch (e) {
res.errMsg = `${url}下载失败`
let buffer: Buffer = null;
try{
buffer = await httpDownload(uri);
}catch (e) {
res.errMsg = `${url}下载失败,` + e.toString()
return res
}
if (!fetchRes.ok) {
res.errMsg = `${url}下载失败,` + fetchRes.statusText
return res
}
let blob = await fetchRes.blob();
let buffer = await blob.arrayBuffer();
try {
const pathInfo = path.parse(decodeURIComponent(url.pathname))
if (pathInfo.name) {
@ -358,7 +363,7 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
}
res.fileName = fileName
filePath = path.join(TEMP_DIR, uuidv4() + fileName)
fs.writeFileSync(filePath, Buffer.from(buffer));
fs.writeFileSync(filePath, buffer);
} catch (e: any) {
res.errMsg = `${url}下载失败,` + e.toString()
return res
@ -409,4 +414,27 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
res.success = true
res.path = filePath
return res
}
export async function copyFolder(sourcePath: string, destPath: string) {
try {
const entries = await fsPromise.readdir(sourcePath, {withFileTypes: true});
await fsPromise.mkdir(destPath, {recursive: true});
for (let entry of entries) {
const srcPath = path.join(sourcePath, entry.name);
const dstPath = path.join(destPath, entry.name);
if (entry.isDirectory()) {
await copyFolder(srcPath, dstPath);
} else {
try {
await fsPromise.copyFile(srcPath, dstPath);
} catch (error) {
console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`);
// 这里可以决定是否要继续复制其他文件
}
}
}
} catch (error) {
console.error('复制文件夹时出错:', error);
}
}

View File

@ -1,7 +1,7 @@
import {version} from "../../version";
import * as path from "node:path";
import * as fs from "node:fs";
import {httpDownload, log, PLUGIN_DIR, TEMP_DIR} from ".";
import {copyFolder, httpDownload, log, PLUGIN_DIR, TEMP_DIR} from ".";
import compressing from "compressing";
@ -25,9 +25,7 @@ export async function upgradeLLOneBot() {
const latestVersion = await getRemoteVersion();
if (latestVersion && latestVersion != "") {
const downloadUrl = "https://github.com/LLOneBot/LLOneBot/releases/download/v" + latestVersion + "/LLOneBot.zip";
const mirrorUrl = downloadMirrorHosts[0] + downloadUrl;
const filePath = path.join(TEMP_DIR, "./update-" + latestVersion + ".zip");
const fileStream = fs.createWriteStream(filePath);
let downloadSuccess = false;
// 多镜像下载
for(const mirrorGithub of downloadMirrorHosts){
@ -44,12 +42,13 @@ export async function upgradeLLOneBot() {
log("llonebot upgrade error", "download failed");
return false;
}
const temp_ver_dir = path.join(TEMP_DIR, "LLOneBot" + latestVersion);
let uncompressedPromise = async function () {
return new Promise<boolean>((resolve, reject) => {
compressing.zip.uncompress(filePath, PLUGIN_DIR).then(() => {
compressing.zip.uncompress(filePath, temp_ver_dir).then(() => {
resolve(true);
}).catch((reason: any) => {
console.log(reason);
log("llonebot upgrade failed, ", reason);
if (reason?.errno == -4082) {
resolve(true);
}
@ -57,8 +56,11 @@ export async function upgradeLLOneBot() {
});
});
}
const uncompressResult = await uncompressedPromise();
return uncompressResult;
const uncompressedResult = await uncompressedPromise();
// 复制文件
await copyFolder(temp_ver_dir, PLUGIN_DIR);
return uncompressedResult;
}
return false;
}
@ -81,7 +83,7 @@ export async function getRemoteVersionByMirror(mirrorGithub: string) {
try {
releasePage = (await httpDownload(mirrorGithub + "/LLOneBot/LLOneBot/releases")).toString();
log("releasePage", releasePage);
// log("releasePage", releasePage);
if (releasePage === "error") return "";
return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))[0];
} catch {

View File

@ -2,7 +2,7 @@ import BaseAction from "../BaseAction";
import {ActionName} from "../types";
import fs from "fs";
import {join as joinPath} from "node:path";
import {calculateFileMD5, TEMP_DIR} from "../../../common/utils";
import {calculateFileMD5, httpDownload, TEMP_DIR} from "../../../common/utils";
import {v4 as uuid4} from "uuid";
interface Payload {
@ -29,12 +29,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
fs.writeFileSync(filePath, payload.base64, 'base64')
} else if (payload.url) {
const headers = this.getHeaders(payload.headers);
const result = await fetch(payload.url, {headers})
if (! result.ok) throw new Error(`下载文件失败: ${result.statusText}`)
const blob = await result.blob();
let buffer = await blob.arrayBuffer();
let buffer = await httpDownload({url: payload.url, headers: headers})
fs.writeFileSync(filePath, Buffer.from(buffer), 'binary');
} else {
throw new Error("不存在任何文件, 无法下载")
@ -54,7 +49,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
}
}
getHeaders(headersIn?: string | string[]): any {
getHeaders(headersIn?: string | string[]): Record<string, string> {
const headers = {};
if (typeof headersIn == 'string') {
headersIn = headersIn.split('[\\r\\n]');