From ba12b93c9069dbe146d2c93abb6f8033600e762f Mon Sep 17 00:00:00 2001 From: zhang bo Date: Wed, 4 Dec 2024 14:21:38 +0800 Subject: [PATCH] feat: support unzip 7z files for hsr (#496) * chore:support unzip 7z files for hsr * chore:support unzip 7z files for hsr * Revert "chore:support unzip 7z files for hsr" This reverts commit cb1d3469e13bf0c7dad80f8fd732047882ca57ae. * fix: remove indent in .ini content --------- Co-authored-by: 3Shain --- src/clients/mhy/hkrpg/program-install-game.ts | 66 +++++++++-------- src/utils/unix.ts | 73 +++++++++++++++++++ 2 files changed, 107 insertions(+), 32 deletions(-) diff --git a/src/clients/mhy/hkrpg/program-install-game.ts b/src/clients/mhy/hkrpg/program-install-game.ts index 9497858..269c708 100644 --- a/src/clients/mhy/hkrpg/program-install-game.ts +++ b/src/clients/mhy/hkrpg/program-install-game.ts @@ -5,7 +5,7 @@ import { Server } from "@constants"; import { mkdirp, humanFileSize, - doStreamUnzip, + doStreamUn7z, removeFile, writeFile, } from "@utils"; @@ -23,46 +23,44 @@ export async function* downloadAndInstallGameProgram({ aria2: Aria2; server: Server; }): CommonUpdateProgram { - if (gameSegmentZips.length > 1) { - throw new Error( - "Assertation failed (gameSegmentZips.length > 1)! please file an issue." - ); - } - const gameFileZip = gameSegmentZips[0]; const downloadTmp = join(gameDir, ".ariatmp"); - const gameFileTmp = join(downloadTmp, "game.zip"); + const downloadedFiles: string[] = []; + await mkdirp(downloadTmp); yield ["setUndeterminedProgress"]; yield ["setStateText", "ALLOCATING_FILE"]; - let gameFileStart = false; - for await (const progress of aria2.doStreamingDownload({ - uri: gameFileZip, - absDst: gameFileTmp, - })) { - if (!gameFileStart && progress.downloadSpeed == BigInt(0)) { - continue; + + // Download each segmented file + for (const gameFile7z of gameSegmentZips) { + const localFile = join(downloadTmp, basename(gameFile7z)); + for await (const progress of aria2.doStreamingDownload({ + uri: gameFile7z, + absDst: localFile, + })) { + yield [ + "setStateText", + "DOWNLOADING_FILE_PROGRESS", + basename(gameFile7z), + humanFileSize(Number(progress.downloadSpeed)), + humanFileSize(Number(progress.completedLength)), + humanFileSize(Number(progress.totalLength)), + ]; + yield [ + "setProgress", + Number( + (progress.completedLength * BigInt(10000)) / progress.totalLength + ) / 100, + ]; } - gameFileStart = true; - yield [ - "setStateText", - "DOWNLOADING_FILE_PROGRESS", - basename(gameFileZip), - humanFileSize(Number(progress.downloadSpeed)), - humanFileSize(Number(progress.completedLength)), - humanFileSize(Number(progress.totalLength)), - ]; - yield [ - "setProgress", - Number( - (progress.completedLength * BigInt(10000)) / progress.totalLength - ) / 100, - ]; + downloadedFiles.push(localFile); // Save the downloaded file path } + yield ["setStateText", "DECOMPRESS_FILE_PROGRESS"]; - for await (const [dec, total] of doStreamUnzip(gameFileTmp, gameDir)) { + + for await (const [dec, total] of doStreamUn7z(downloadedFiles, gameDir)) { yield ["setProgress", (dec / total) * 100]; } - await removeFile(gameFileTmp); + await writeFile( join(gameDir, "config.ini"), `[General] @@ -71,4 +69,8 @@ channel=${server.channel_id} sub_channel=${server.subchannel_id} cps=${server.cps}` ); + + for (const file of downloadedFiles) { + await removeFile(file); + } } diff --git a/src/utils/unix.ts b/src/utils/unix.ts index 94a13c6..4b1bdd7 100644 --- a/src/utils/unix.ts +++ b/src/utils/unix.ts @@ -115,6 +115,79 @@ export async function* doStreamUnzip( throw new Error("unzip exited with code " + processExitCode); } +export async function* doStreamUn7z( + sources: string[], + destination: string +): AsyncGenerator { + const logFile = resolve("decompress.log"); + let processExit = false, + processExitCode = 0; + + const mainFile = sources.find(file => file.endsWith(".001")); + if (!mainFile) throw new Error("Missing main .001 file for decompression!"); + + const totalLines = Number( + ( + await exec([ + resolve("./sidecar/7z/7zz"), + "l", + mainFile, + rawString("|"), + "tee", + logFile, + rawString("|"), + "wc", + "-l", + ]) + ).stdOut + .trim() + .split(" ")[0] + ); + + // Extract the. 7z file + const { id } = await spawn([ + resolve("./sidecar/7z/7zz"), + "x", + `-o${destination}`, + mainFile, //Just need to transfer the. 001 file + rawString("|"), + "tee", + logFile, + rawString("&>"), + "/dev/null", + ]); + + const handler: Neutralino.events.Handler< + Neutralino.os.SpawnProcessResult + > = event => { + if (!event) return; + if (event.detail.id == id) { + if (event.detail["action"] == "exit") { + processExit = true; + processExitCode = Number(event.detail["data"]); + } + } + }; + + await Neutralino.events.on("spawnedProcess", handler); + + while (processExit == false) { + await wait(200); + const dNumber = Number( + (await exec(["wc", "-l", rawString("<"), logFile])).stdOut + .trim() + .split(" ")[0] + ); + yield [dNumber, totalLines] as const; + } + + await Neutralino.events.off("spawnedProcess", handler); + + if (processExitCode != 0) { + throw new Error("7z exited with code " + processExitCode); + } +} + export async function extract7z(source: string, destination: string) { return await exec([ resolve("./sidecar/7z/7zz"),