From 03ed0a4cb755475ad53118c8a4f3228f887ae533 Mon Sep 17 00:00:00 2001 From: Tianpao Date: Sat, 27 Dec 2025 14:23:34 +0800 Subject: [PATCH] =?UTF-8?q?chore=EF=BC=9A=E4=BA=BA=E5=B7=A5=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=B1=8E=E5=B1=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/Dex.ts | 163 ++++++++++++++--------------- backend/src/modloader/fabric.ts | 4 +- backend/src/modloader/forge.ts | 4 +- backend/src/modloader/minecraft.ts | 2 - backend/src/platform/curseforge.ts | 15 +-- backend/src/platform/index.ts | 6 +- backend/src/platform/modrinth.ts | 12 +-- backend/src/utils/logger.ts | 14 ++- backend/src/utils/utils.ts | 134 ++++-------------------- backend/src/utils/ws.ts | 56 ++++++++++ front/src/component/Main.vue | 2 +- 11 files changed, 182 insertions(+), 230 deletions(-) create mode 100644 backend/src/utils/ws.ts diff --git a/backend/src/Dex.ts b/backend/src/Dex.ts index 612e7b8..b8ee79f 100644 --- a/backend/src/Dex.ts +++ b/backend/src/Dex.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import p from "node:path" +import p from "node:path"; import websocket, { WebSocketServer } from "ws"; import { yauzl_promise } from "./utils/yauzl.promise.js"; import { pipeline } from "node:stream/promises"; @@ -8,103 +8,95 @@ import { DeEarth } from "./utils/DeEarth.js"; import { dinstall, mlsetup } from "./modloader/index.js"; import config from "./utils/config.js"; import { execPromise } from "./utils/utils.js"; +import { MessageWS } from "./utils/ws.js"; +import { debug } from "./utils/logger.js"; export class Dex { wsx!: WebSocketServer; - in: any; - ws!: websocket; + message!: MessageWS; constructor(ws: WebSocketServer) { this.wsx = ws; this.wsx.on("connection", (e) => { - this.ws = e; + this.message = new MessageWS(e); }); - this.in = {}; } public async Main(buffer: Buffer, dser: boolean) { - try{ - const first = Date.now(); - const info = await this._getinfo(buffer).catch((e)=>{ - throw new Error(e) - }); - const plat = what_platform(info); - const mpname = this.in.name; - const unpath = `./instance/${mpname}`; - await Promise.all([ - this._unzip(buffer, mpname), - await platform(plat).downloadfile(this.in, unpath, this.ws), - ]).catch((e) => { - throw new Error(e) - }); // 解压和下载 - this.ws.send( - JSON.stringify({ - status: "changed", - result: undefined, - }) - ); //改变状态 - await new DeEarth(`${unpath}/mods`, `./.rubbish/${mpname}`).Main().catch((e) => { - throw new Error(e) - }); - this.ws.send( - JSON.stringify({ - status: "changed", - result: undefined, - }) - ); //改变状态(DeEarth筛选模组完毕) - const mlinfo = await platform(plat).getinfo(this.in).catch((e)=>{ - throw new Error(e) - }); - if (dser) { - await mlsetup( - mlinfo.loader, - mlinfo.minecraft, - mlinfo.loader_version, - unpath - ).catch((e) => { - throw new Error(e) - }); //安装服务端 - } - if (!dser) { - dinstall(mlinfo.loader, mlinfo.minecraft, mlinfo.loader_version, unpath).catch((e) => { - throw new Error(e) + try { + const first = Date.now(); + const { contain, info } = await this._getinfo(buffer).catch((e) => { + throw new Error(e); }); + const plat = what_platform(contain); + debug(plat); + debug(info); + const mpname = info.name; + const unpath = `./instance/${mpname}`; + await Promise.all([ + this._unzip(buffer, mpname), + await platform(plat).downloadfile(info, unpath, this.message), + ]).catch((e) => { + throw new Error(e); + }); // 解压和下载 + this.message.statusChange(); //改变状态 + await new DeEarth(`${unpath}/mods`, `./.rubbish/${mpname}`) + .Main() + .catch((e) => { + throw new Error(e); + }); + this.message.statusChange(); //改变状态(DeEarth筛选模组完毕) + const mlinfo = await platform(plat) + .getinfo(info) + .catch((e) => { + throw new Error(e); + }); + if (dser) { + await mlsetup( + mlinfo.loader, + mlinfo.minecraft, + mlinfo.loader_version, + unpath + ).catch((e) => { + throw new Error(e); + }); //安装服务端 + } + if (!dser) { + dinstall( + mlinfo.loader, + mlinfo.minecraft, + mlinfo.loader_version, + unpath + ).catch((e) => { + throw new Error(e); + }); + } + const latest = Date.now(); + this.message.finish(first, latest); //完成 + if (config.oaf) { + await execPromise(`start ${p.join("./instance")}`).catch((e) => { + throw new Error(e); + }); + } + //await this._unzip(buffer); + } catch (e) { + const err = e as Error; + this.message.handleError(err); } - const latest = Date.now(); - this.ws.send( - JSON.stringify({ - status: "finish", - result: latest - first, - }) - ); - if (config.oaf) { - await execPromise(`start ${p.join("./instance")}`).catch((e) => { - throw new Error(e) - }); - } - //await this._unzip(buffer); - }catch(e){ - const err = e as Error - this.ws.send( - JSON.stringify({ - status: "error", - result: err.message, - }) - ); - } } private async _getinfo(buffer: Buffer) { const important_name = ["manifest.json", "modrinth.index.json"]; let contain: string = ""; + let info: any = {}; const zip = await yauzl_promise(buffer); - zip.forEach(async (e) => { - if (important_name.includes(e.fileName)) { - contain = e.fileName; - this.in = JSON.parse((await e.ReadEntry).toString()); - return; + for await (const entry of zip) { + if (important_name.includes(entry.fileName)) { + contain = entry.fileName; + info = JSON.parse((await entry.ReadEntry).toString()); + break; } - }); - return contain; + } + return { contain, info }; } private async _unzip(buffer: Buffer, instancename: string) { @@ -139,12 +131,13 @@ export class Dex { ); await pipeline(stream, write); } - this.ws.send( - JSON.stringify({ - status: "unzip", - result: { name: entry.fileName, total: zip.length, current: index }, - }) - ); + this.message.unzip(entry.fileName, zip.length, index); + // this.ws.send( + // JSON.stringify({ + // status: "unzip", + // result: { name: entry.fileName, total: zip.length, current: index }, + // }) + // ); index++; } /* 解压完成 */ diff --git a/backend/src/modloader/fabric.ts b/backend/src/modloader/fabric.ts index 34ce26b..31a4825 100644 --- a/backend/src/modloader/fabric.ts +++ b/backend/src/modloader/fabric.ts @@ -1,6 +1,6 @@ import got, { Got } from "got"; import fs from "node:fs" -import { execPromise, fastdownload, xfastdownload } from "../utils/utils.js"; +import { execPromise, fastdownload } from "../utils/utils.js"; interface ILatestLoader{ url:string, @@ -56,7 +56,7 @@ export class Fabric{ const path = this.MTP(e.name) _downlist.push([`https://bmclapi2.bangbang93.com/maven/${path}`,`${this.path}/libraries/${path}`]) }) - await xfastdownload(_downlist) + await fastdownload(_downlist) } async installer(){ diff --git a/backend/src/modloader/forge.ts b/backend/src/modloader/forge.ts index 14397b0..db7b771 100644 --- a/backend/src/modloader/forge.ts +++ b/backend/src/modloader/forge.ts @@ -1,7 +1,7 @@ import got, { Got } from "got"; import fs from "node:fs" import fse from "fs-extra" -import { execPromise, fastdownload, version_compare, xfastdownload } from "../utils/utils.js"; +import { execPromise, fastdownload, version_compare } from "../utils/utils.js"; import { yauzl_promise } from "../utils/yauzl.promise.js"; import { execSync } from "node:child_process"; @@ -76,7 +76,7 @@ export class Forge { } } const downlist = [...new Set(_downlist)] - await xfastdownload(downlist) + await fastdownload(downlist) } async install(){ diff --git a/backend/src/modloader/minecraft.ts b/backend/src/modloader/minecraft.ts index ebc6254..e0364a3 100644 --- a/backend/src/modloader/minecraft.ts +++ b/backend/src/modloader/minecraft.ts @@ -1,10 +1,8 @@ import fs from "node:fs" -import pa from "node:path" import { fastdownload, version_compare } from "../utils/utils.js"; import { yauzl_promise } from "../utils/yauzl.promise.js"; import { pipeline } from "node:stream/promises"; import got from "got"; -import fsExtra from "fs-extra/esm"; interface ILInfo { libraries: { diff --git a/backend/src/platform/curseforge.ts b/backend/src/platform/curseforge.ts index 1516938..29139d2 100644 --- a/backend/src/platform/curseforge.ts +++ b/backend/src/platform/curseforge.ts @@ -3,6 +3,7 @@ import { WebSocket } from "ws"; import { join } from "node:path"; import { Wfastdownload, Utils } from "../utils/utils.js"; import { modpack_info, XPlatform } from "./index.js"; +import { MessageWS } from "../utils/ws.js"; export interface CurseForgeManifest { minecraft: { @@ -39,7 +40,7 @@ export class CurseForge implements XPlatform { return result; } - async downloadfile(manifest: object, path: string, ws:WebSocket): Promise { + async downloadfile(manifest: object, path: string, ws:MessageWS): Promise { const local_manifest = manifest as CurseForgeManifest; if (local_manifest.files.length === 0){ return; @@ -49,7 +50,7 @@ export class CurseForge implements XPlatform { (file: { fileID: number }) => file.fileID ), }); - let tmp: [string, string] | string[][] = []; + let tmp: string[][] = []; await this.got .post("v1/mods/files", { body: FileID, @@ -64,17 +65,9 @@ export class CurseForge implements XPlatform { const unpath = join(path + "/mods/", e.fileName); const url = e.downloadUrl.replace("https://edge.forgecdn.net", this.utils.curseforge_Durl) tmp.push([url, unpath]) - // if (usemirror) { - // tmp.push([ - // "https://mod.mcimirror.top" + new URL(e.downloadUrl).pathname, - // unpath, - // ]); - // } else { - // tmp.push([e.downloadUrl, unpath]); - // } } ); }); - await Wfastdownload(tmp as unknown as [string, string],ws); //下载文件 + await Wfastdownload(tmp,ws); //下载文件 } } diff --git a/backend/src/platform/index.ts b/backend/src/platform/index.ts index e7a68b2..5646c7e 100644 --- a/backend/src/platform/index.ts +++ b/backend/src/platform/index.ts @@ -1,10 +1,10 @@ +import { MessageWS } from "../utils/ws.js"; import { CurseForge } from "./curseforge.js"; -import { Modrinth } from "./modrinth.js"; -import { WebSocket } from "ws"; +import { Modrinth } from "./modrinth.js";; export interface XPlatform { getinfo(manifest: object): Promise; - downloadfile(manifest: object,path:string,ws:WebSocket): Promise; + downloadfile(manifest: object,path:string,ws:MessageWS): Promise; } export interface modpack_info { diff --git a/backend/src/platform/modrinth.ts b/backend/src/platform/modrinth.ts index 45da771..0143a23 100644 --- a/backend/src/platform/modrinth.ts +++ b/backend/src/platform/modrinth.ts @@ -3,6 +3,7 @@ import { WebSocket } from "ws"; import { Wfastdownload, Utils } from "../utils/utils.js"; import { modpack_info, XPlatform } from "./index.js"; import { join } from "node:path"; +import { MessageWS } from "../utils/ws.js"; interface ModrinthManifest { files: Array<{ path: string; downloads: string[]; fileSize: number; }>; @@ -35,7 +36,7 @@ export class Modrinth implements XPlatform { } return result; } - async downloadfile(manifest: object,path:string,ws:WebSocket): Promise { + async downloadfile(manifest: object,path:string,ws:MessageWS): Promise { const index = manifest as ModrinthManifest; let tmp: [string, string][] = [] index.files.forEach(async (e: { path: string; downloads: string[]; fileSize: number;}) => { @@ -44,13 +45,8 @@ export class Modrinth implements XPlatform { } const url = e.downloads[0].replace("https://cdn.modrinth.com",this.utils.modrinth_Durl) const unpath = join(path,e.path) - tmp.push([e.downloads[0],unpath]) - // if (usemirror){ - // tmp.push(["https://mod.mcimirror.top"+new URL(e.downloads[0]).pathname,unpath,String(e.fileSize)]) - // }else{ - // tmp.push([e.downloads[0],unpath,String(e.fileSize)]) - // } + tmp.push([url,unpath]) }); - await Wfastdownload(tmp as unknown as [string, string],ws) + await Wfastdownload(tmp,ws) } } diff --git a/backend/src/utils/logger.ts b/backend/src/utils/logger.ts index 53b9dde..9c19540 100644 --- a/backend/src/utils/logger.ts +++ b/backend/src/utils/logger.ts @@ -1,7 +1,17 @@ const env = process.env.DEBUG; -export function debug(msg: string){ +export function debug(msg: any){ if (env === "true"){ - console.info(msg); + if(msg instanceof Error){ + console.log(`[ERROR] [${new Date().toLocaleString()}] `); + console.log(msg); + } + if (typeof msg === "string"){ + console.log(`[DEBUG] [${new Date().toLocaleString()}] ` + msg); + } + if (typeof msg === "object"){ + console.log(`[OBJ] [${new Date().toLocaleString()}] `); + console.log(msg); + } } } diff --git a/backend/src/utils/utils.ts b/backend/src/utils/utils.ts index 8d01b8b..85206d4 100644 --- a/backend/src/utils/utils.ts +++ b/backend/src/utils/utils.ts @@ -6,6 +6,7 @@ import fs from "node:fs"; import fse from "fs-extra"; import { WebSocket } from "ws"; import { ExecOptions, exec} from "node:child_process"; +import { MessageWS } from "./ws.js"; export class Utils { public modrinth_url: string; @@ -62,30 +63,20 @@ export function execPromise(cmd:string,options?:ExecOptions){ }) } -export async function fastdownload(data: [string, string]) { +export async function fastdownload(data: [string, string]|string[][]) { + let _data = undefined; + if(Array.isArray(data[0])){ + _data = data + }else{ + _data = [data] + } return await pMap( - [data], + _data, async (e:any) => { try { await pRetry( async () => { if (!fs.existsSync(e[1])) { - /* - const size: number = await (async () => { - const head = ( - await got.head( - e[0], - { headers: { "user-agent": "DeEarthX" } } - ) - ).headers["content-length"]; - if (head) { - return Number(head); - } else { - return 0; - } - })();*/ - - //console.log(e) await got .get(e[0], { responseType: "buffer", @@ -93,9 +84,6 @@ export async function fastdownload(data: [string, string]) { "user-agent": "DeEarthX", }, }) - .on("downloadProgress", (progress) => { - //bar.update(progress.transferred); - }) .then((res) => { fse.outputFileSync(e[1], res.rawBody); }); @@ -111,7 +99,7 @@ export async function fastdownload(data: [string, string]) { ); } -export async function Wfastdownload(data: [string, string],ws:WebSocket) { +export async function Wfastdownload(data: string[][],ws:MessageWS) { let index = 1; return await pMap( data, @@ -131,14 +119,15 @@ export async function Wfastdownload(data: [string, string],ws:WebSocket) { fse.outputFileSync(e[1], res.rawBody); }); } - ws.send(JSON.stringify({ - status:"downloading", - result:{ - total:data.length, - index:index, - name:e[1] - } - })) + ws.download(data.length,index,e[1]) + // ws.send(JSON.stringify({ + // status:"downloading", + // result:{ + // total:data.length, + // index:index, + // name:e[1] + // } + // })) index++ }, { retries: 3 } @@ -149,87 +138,4 @@ export async function Wfastdownload(data: [string, string],ws:WebSocket) { }, { concurrency: 16 } ); -} - -export async function xfastdownload(data: [string, string][]) { - return await pMap( - data, - async (e:any) => { - try { - await pRetry( - async () => { - if (!fs.existsSync(e[1])) { - /* - const size: number = await (async () => { - const head = ( - await got.head( - e[0], - { headers: { "user-agent": "DeEarthX" } } - ) - ).headers["content-length"]; - if (head) { - return Number(head); - } else { - return 0; - } - })();*/ - //console.log(e) - await got - .get(e[0], { - responseType: "buffer", - headers: { - "user-agent": "DeEarthX", - }, - }) - .on("downloadProgress", (progress) => { - //bar.update(progress.transferred); - }) - .then((res) => { - fse.outputFileSync(e[1], res.rawBody); - }); - } - }, - { retries: 3 } - ); - } catch (e) { - //LOGGER.error({ err: e }); - } - }, - { concurrency: 16 } - ); -} - -export async function mr_fastdownload(data: [string, string, string]) { - return await pMap( - data, - async (e) => { - //const bar = multibar.create(Number(e[2]), 0, { filename: e[1] }); - try { - await pRetry( - async () => { - if (!fse.existsSync(e[1])) { - await got - .get(e[0], { - responseType: "buffer", - headers: { - "user-agent": "DeEarthX", - }, - }) - .on("downloadProgress", (progress) => { - //bar.update(progress.transferred); - }) - .then((res) => { - fse.outputFileSync(e[1], res.rawBody); - }); - } - }, - { retries: 3 } - ); - } catch (e) { - //LOGGER.error({ err: e }); - } - }, - { concurrency: 16 } - ); -} - +} \ No newline at end of file diff --git a/backend/src/utils/ws.ts b/backend/src/utils/ws.ts new file mode 100644 index 0000000..a58c1fb --- /dev/null +++ b/backend/src/utils/ws.ts @@ -0,0 +1,56 @@ +import websocket, { WebSocketServer } from "ws"; +export class MessageWS { + ws!: websocket; + constructor(ws: websocket) { + this.ws = ws; + } + + finish(first: number, latest: number) { + this.ws.send( + JSON.stringify({ + status: "finish", + result: latest - first, + }) + ); + } + + unzip(entryName: string, total: number, current: number) { + this.ws.send( + JSON.stringify({ + status: "unzip", + result: { name: entryName, total, current }, + }) + ); + } + + download(total: number, index: number, name: string) { + this.ws.send( + JSON.stringify({ + status: "downloading", + result: { + total, + index, + name, + }, + }) + ); + } + + statusChange() { + this.ws.send( + JSON.stringify({ + status: "changed", + result: undefined, + }) + ); + } + + handleError(error: Error) { + this.ws.send( + JSON.stringify({ + status: "error", + result: error.message, + }) + ); + } +} diff --git a/front/src/component/Main.vue b/front/src/component/Main.vue index 383a3b6..6a6866d 100644 --- a/front/src/component/Main.vue +++ b/front/src/component/Main.vue @@ -133,7 +133,7 @@ function prews(){ if (_data.status === "error"){ notification.error({ message: "DeEarth.X.Core 遇到了一个致命错误!", - description:_data.result + description:`请将整个窗口截图发在群里\n错误信息:${_data.result}` }) } })