mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[hotfix] download mod zip in buffer to avoid eprem error
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import JSZip from 'jszip';
|
||||
import { pathExist } from './fs.helpers';
|
||||
import path from 'path';
|
||||
import { mkdir, writeFile } from 'fs/promises';
|
||||
|
||||
export async function extractZip(zip: JSZip, dest: string): Promise<string[]>{
|
||||
if(!await pathExist(dest)){ throw new Error(`Path ${dest} does not exist`); }
|
||||
const files: string[] = [];
|
||||
await zip.forEach(async (relativePath, entry) => {
|
||||
if(entry.dir){ return; }
|
||||
|
||||
const content = await entry.async("nodebuffer");
|
||||
const outPath = path.join(dest, relativePath);
|
||||
const outDir = path.dirname(outPath);
|
||||
|
||||
await mkdir(outDir, { recursive: true });
|
||||
await writeFile(outPath, content);
|
||||
|
||||
files.push(outPath);
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
@@ -6,13 +6,15 @@ import path from "path";
|
||||
import { UtilsService } from "../utils.service";
|
||||
import md5File from "md5-file";
|
||||
import fs from "fs"
|
||||
import StreamZip from "node-stream-zip";
|
||||
import { RequestService } from "../request.service";
|
||||
import { spawn } from "child_process";
|
||||
import { BS_EXECUTABLE } from "../../constants";
|
||||
import log from "electron-log";
|
||||
import { deleteFolder, ensureFolderExist, pathExist, unlinkPath } from "../../helpers/fs.helpers";
|
||||
import { deleteFolder, pathExist, unlinkPath } from "../../helpers/fs.helpers";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import JSZip from "jszip"
|
||||
import { extractZip } from "../../helpers/zip.helpers";
|
||||
import { ensureFolderExist } from "../../helpers/fs.helpers";
|
||||
|
||||
export class BsModsManagerService {
|
||||
|
||||
@@ -96,17 +98,20 @@ export class BsModsManagerService {
|
||||
return this.getIpaFromHash(injectorMd5);
|
||||
}
|
||||
|
||||
private async downloadZip(zipUrl: string): Promise<{zip: StreamZip.StreamZipAsync, zipPath: string}>{
|
||||
private async downloadZip(zipUrl: string): Promise<JSZip>{
|
||||
zipUrl = path.join(this.beatModsApi.BEAT_MODS_URL, zipUrl);
|
||||
const fileName = path.basename(zipUrl);
|
||||
const tempPath = this.utilsService.getTempPath();
|
||||
await ensureFolderExist(this.utilsService.getTempPath());
|
||||
const dest = path.join(tempPath, fileName);
|
||||
|
||||
const zipPath = (await lastValueFrom(this.requestService.downloadFile(zipUrl, dest))).data;
|
||||
const zip = new StreamZip.async({file : zipPath});
|
||||
const buffer = await lastValueFrom(this.requestService.downloadBuffer(zipUrl)).then(progress => progress.data).catch(e => {
|
||||
log.error("ZIP", "Error while downloading zip", e);
|
||||
return undefined
|
||||
});
|
||||
|
||||
return {zip, zipPath};
|
||||
if(!buffer){ return null; }
|
||||
|
||||
return JSZip.loadAsync(buffer).catch(e => {
|
||||
log.error("ZIP", "Error while loading zip", e);
|
||||
return null
|
||||
});
|
||||
}
|
||||
|
||||
private async executeBSIPA(version: BSVersion, args: string[]): Promise<boolean>{
|
||||
@@ -135,23 +140,22 @@ export class BsModsManagerService {
|
||||
}
|
||||
|
||||
private async installMod(mod: Mod, version: BSVersion): Promise<boolean>{
|
||||
|
||||
|
||||
this.utilsService.ipcSend<ModInstallProgression>("mod-installed", {success: true, data: {name: mod.name, progression: ((this.nbInstalledMods + 1) / this.nbModsToInstall) * 100}})
|
||||
|
||||
const download = this.getModDownload(mod, version);
|
||||
|
||||
if(!download){ return false; }
|
||||
|
||||
const {zip, zipPath} = await this.downloadZip(download.url);
|
||||
const zip = await this.downloadZip(download.url);
|
||||
|
||||
if(!zip){ return false; }
|
||||
|
||||
const crypto = require('crypto');
|
||||
const entries = await zip.entries();
|
||||
const files = await zip.files;
|
||||
|
||||
const checkedEntries = (await Promise.all(Object.values(entries).map(async (entry) => {
|
||||
if(!entry.isFile){ return undefined; }
|
||||
const data = await zip.entryData(entry);
|
||||
const checkedEntries = (await Promise.all(Object.values(files).map(async (entry) => {
|
||||
const data = await entry.async("nodebuffer");
|
||||
const entryMd5 = crypto.createHash('md5').update(data).digest('hex')
|
||||
return download.hashMd5.some(md5 => md5.hash === entryMd5) ? entry : undefined;
|
||||
}))).filter(entry => !!entry);
|
||||
@@ -162,12 +166,16 @@ export class BsModsManagerService {
|
||||
const isBSIPA = mod.name.toLowerCase() === "bsipa";
|
||||
const destDir = isBSIPA ? verionPath : path.join(verionPath, ModsInstallFolder.PENDING);
|
||||
|
||||
const extracted = await zip.extract(null, destDir).then(() => true).catch(err => {log.error(err); return false});
|
||||
await ensureFolderExist(destDir);
|
||||
const extracted = await extractZip(zip, destDir).then(() => true).catch(e => {
|
||||
log.error("EXTRACT MOD ZIP", e);
|
||||
return false;
|
||||
})
|
||||
|
||||
await zip.close();
|
||||
await unlinkPath(zipPath);
|
||||
|
||||
const res = isBSIPA ? (extracted && (await this.executeBSIPA(version, ["-n"]))) : extracted;
|
||||
const res = isBSIPA ? (extracted && (await this.executeBSIPA(version, ["-n"]).catch(e => {
|
||||
log.error(e);
|
||||
return false;
|
||||
}))) : extracted;
|
||||
|
||||
res && this.nbInstalledMods++;
|
||||
|
||||
|
||||
@@ -61,17 +61,30 @@ export class RequestService {
|
||||
|
||||
}
|
||||
|
||||
public downloadBuffer(url: string): Observable<Buffer>{
|
||||
public downloadBuffer(url: string): Observable<Progression<Buffer>>{
|
||||
|
||||
return new Observable<Progression<Buffer>>(subscriber => {
|
||||
|
||||
const progress: Progression<Buffer> = {
|
||||
current: 0,
|
||||
total: 0,
|
||||
data: null
|
||||
};
|
||||
|
||||
return new Observable<Buffer>(subscriber => {
|
||||
const allChunks: Buffer[] = [];
|
||||
|
||||
const req = get(url, res => {
|
||||
|
||||
progress.total = parseInt(res.headers?.["content-length"] || "0", 10);
|
||||
|
||||
res.on("data", chunk => {
|
||||
allChunks.push(chunk);
|
||||
progress.current += chunk.length;
|
||||
subscriber.next(progress);
|
||||
});
|
||||
res.on('end', () => {
|
||||
subscriber.next(Buffer.concat(allChunks));
|
||||
progress.data = Buffer.concat(allChunks);
|
||||
subscriber.next(progress);
|
||||
subscriber.complete();
|
||||
});
|
||||
res.on('error', (err) => subscriber.error(err))
|
||||
|
||||
Reference in New Issue
Block a user