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 fs from "fs";
import fsPromise from "fs/promises";
import crypto from "crypto"; import crypto from "crypto";
import ffmpeg from "fluent-ffmpeg"; import ffmpeg from "fluent-ffmpeg";
import util from "util"; import util from "util";
@ -10,7 +11,7 @@ import {getConfigUtil} from "../config";
import {dbUtil} from "../db"; import {dbUtil} from "../db";
import * as fileType from "file-type"; import * as fileType from "file-type";
import {net} from "electron"; import {net} from "electron";
import ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; import ClientRequestConstructorOptions = Electron.Main.ClientRequestConstructorOptions;
export function isGIF(path: string) { export function isGIF(path: string) {
const buffer = Buffer.alloc(4); 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 chunks: Buffer[] = [];
let netRequest = net.request(options) let url: string;
return new Promise((resolve, reject) => { let headers: Record<string, string> = {
netRequest.on("response", (response) => { "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 (!(response.statusCode >= 200 && response.statusCode < 300)) { };
return reject(new Error(`下载失败,状态码${response.statusCode}`)) 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", () => { const fetchRes = await net.fetch(url, headers);
resolve(Buffer.concat(chunks)); if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`)
})
}).on("error", (err) => { const blob = await fetchRes.blob();
reject(err); let buffer = await blob.arrayBuffer();
}) return Buffer.from(buffer);
netRequest.end()
})
} }
type Uri2LocalRes = { 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:") { } else if (url.protocol == "http:" || url.protocol == "https:") {
// 下载文件 // 下载文件
let fetchRes: Response; let buffer: Buffer = null;
try { try{
fetchRes = await fetch(url) buffer = await httpDownload(uri);
} catch (e) { }catch (e) {
res.errMsg = `${url}下载失败` res.errMsg = `${url}下载失败,` + e.toString()
return res return res
} }
if (!fetchRes.ok) {
res.errMsg = `${url}下载失败,` + fetchRes.statusText
return res
}
let blob = await fetchRes.blob();
let buffer = await blob.arrayBuffer();
try { try {
const pathInfo = path.parse(decodeURIComponent(url.pathname)) const pathInfo = path.parse(decodeURIComponent(url.pathname))
if (pathInfo.name) { if (pathInfo.name) {
@ -358,7 +363,7 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
} }
res.fileName = fileName res.fileName = fileName
filePath = path.join(TEMP_DIR, uuidv4() + fileName) filePath = path.join(TEMP_DIR, uuidv4() + fileName)
fs.writeFileSync(filePath, Buffer.from(buffer)); fs.writeFileSync(filePath, buffer);
} catch (e: any) { } catch (e: any) {
res.errMsg = `${url}下载失败,` + e.toString() res.errMsg = `${url}下载失败,` + e.toString()
return res return res
@ -410,3 +415,26 @@ export async function uri2local(uri: string, fileName: string = null): Promise<U
res.path = filePath res.path = filePath
return res 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 {version} from "../../version";
import * as path from "node:path"; import * as path from "node:path";
import * as fs from "node:fs"; 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"; import compressing from "compressing";
@ -25,9 +25,7 @@ export async function upgradeLLOneBot() {
const latestVersion = await getRemoteVersion(); const latestVersion = await getRemoteVersion();
if (latestVersion && latestVersion != "") { if (latestVersion && latestVersion != "") {
const downloadUrl = "https://github.com/LLOneBot/LLOneBot/releases/download/v" + latestVersion + "/LLOneBot.zip"; 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 filePath = path.join(TEMP_DIR, "./update-" + latestVersion + ".zip");
const fileStream = fs.createWriteStream(filePath);
let downloadSuccess = false; let downloadSuccess = false;
// 多镜像下载 // 多镜像下载
for(const mirrorGithub of downloadMirrorHosts){ for(const mirrorGithub of downloadMirrorHosts){
@ -44,12 +42,13 @@ export async function upgradeLLOneBot() {
log("llonebot upgrade error", "download failed"); log("llonebot upgrade error", "download failed");
return false; return false;
} }
const temp_ver_dir = path.join(TEMP_DIR, "LLOneBot" + latestVersion);
let uncompressedPromise = async function () { let uncompressedPromise = async function () {
return new Promise<boolean>((resolve, reject) => { return new Promise<boolean>((resolve, reject) => {
compressing.zip.uncompress(filePath, PLUGIN_DIR).then(() => { compressing.zip.uncompress(filePath, temp_ver_dir).then(() => {
resolve(true); resolve(true);
}).catch((reason: any) => { }).catch((reason: any) => {
console.log(reason); log("llonebot upgrade failed, ", reason);
if (reason?.errno == -4082) { if (reason?.errno == -4082) {
resolve(true); resolve(true);
} }
@ -57,8 +56,11 @@ export async function upgradeLLOneBot() {
}); });
}); });
} }
const uncompressResult = await uncompressedPromise(); const uncompressedResult = await uncompressedPromise();
return uncompressResult; // 复制文件
await copyFolder(temp_ver_dir, PLUGIN_DIR);
return uncompressedResult;
} }
return false; return false;
} }
@ -81,7 +83,7 @@ export async function getRemoteVersionByMirror(mirrorGithub: string) {
try { try {
releasePage = (await httpDownload(mirrorGithub + "/LLOneBot/LLOneBot/releases")).toString(); releasePage = (await httpDownload(mirrorGithub + "/LLOneBot/LLOneBot/releases")).toString();
log("releasePage", releasePage); // log("releasePage", releasePage);
if (releasePage === "error") return ""; if (releasePage === "error") return "";
return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))[0]; return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))[0];
} catch { } catch {

View File

@ -2,7 +2,7 @@ import BaseAction from "../BaseAction";
import {ActionName} from "../types"; import {ActionName} from "../types";
import fs from "fs"; import fs from "fs";
import {join as joinPath} from "node:path"; 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"; import {v4 as uuid4} from "uuid";
interface Payload { interface Payload {
@ -29,12 +29,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
fs.writeFileSync(filePath, payload.base64, 'base64') fs.writeFileSync(filePath, payload.base64, 'base64')
} else if (payload.url) { } else if (payload.url) {
const headers = this.getHeaders(payload.headers); const headers = this.getHeaders(payload.headers);
let buffer = await httpDownload({url: payload.url, headers: 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();
fs.writeFileSync(filePath, Buffer.from(buffer), 'binary'); fs.writeFileSync(filePath, Buffer.from(buffer), 'binary');
} else { } else {
throw new Error("不存在任何文件, 无法下载") 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 = {}; const headers = {};
if (typeof headersIn == 'string') { if (typeof headersIn == 'string') {
headersIn = headersIn.split('[\\r\\n]'); headersIn = headersIn.split('[\\r\\n]');