diff --git a/assets/jsons/patreons.json b/assets/jsons/patreons.json index 873f2d41..00d8f14d 100644 --- a/assets/jsons/patreons.json +++ b/assets/jsons/patreons.json @@ -89,5 +89,8 @@ }, { "username": "rhythmshade" + }, + { + "username": "liborsaf" } ] diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index 330d9900..42b5add8 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -155,8 +155,13 @@ export class BsModsManagerService { } return new Promise(resolve => { - log.info("START IPA PROCESS", `start /wait /min "" "${ipaPath}" ${args.join(" ")}`); - const processIPA = spawn(`start /wait /min "" "${ipaPath}" ${args.join(" ")}`, { cwd: versionPath, detached: true, shell: true }); + const cmd = process.platform === 'linux' + ? `screen -dmS "BSIPA" dotnet ${ipaPath} ${args.join(" ")}` // Must run through screen, otherwise BSIPA tries to move console cursor and crashes. + : `start /wait /min "" "${ipaPath}" ${args.join(" ")}`; + + log.info("START IPA PROCESS", cmd); + const processIPA = spawn(cmd, { cwd: versionPath, detached: true, shell: true }); + processIPA.once("exit", code => { if (code === 0) { log.info("Ipa process exist with code 0"); @@ -230,7 +235,7 @@ export class BsModsManagerService { log.error("Error while extracting mod zip", e); return false; }); - + log.info("Mod zip extraction end", mod.name, "to", destDir, "success:", extracted); const res = isBSIPA diff --git a/src/main/services/request.service.ts b/src/main/services/request.service.ts index dbd2fcf9..2c7f6741 100644 --- a/src/main/services/request.service.ts +++ b/src/main/services/request.service.ts @@ -1,9 +1,11 @@ -import { Agent, get } from "https"; +import { Agent, RequestOptions, get } from "https"; import { createWriteStream, unlink } from "fs"; import { Progression } from "main/helpers/fs.helpers"; import { Observable, shareReplay, tap } from "rxjs"; import log from "electron-log"; import fetch, { RequestInfo, RequestInit } from "node-fetch"; +import { app } from "electron"; +import os from "os"; export class RequestService { private static instance: RequestService; @@ -15,16 +17,33 @@ export class RequestService { return RequestService.instance; } - private constructor() {} + private readonly defaultRequestInit: RequestInit; - private get ipv4Agent(){ - return new Agent({ family: 4 }); + private constructor() { + + this.defaultRequestInit = { + headers: { + "User-Agent": `BSManager/${app.getVersion()} (${os.type()} ${os.release()})` + }, + agent: new Agent({ family: 4 }), + }; + } + + private getInitWithOptions(options?: RequestInit): RequestInit { + return { ...this.defaultRequestInit, ...(options || {}) }; + } + + private requestOptionsFromDefaultInit(): RequestOptions { + return { + headers: this.defaultRequestInit.headers as Record, + agent: this.defaultRequestInit.agent as Agent, + }; } public async getJSON(url: RequestInfo, options?: RequestInit): Promise { try { - const response = await fetch(url, {...options, agent: this.ipv4Agent}); + const response = await fetch(url, this.getInitWithOptions(options)); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status} ${url}`); @@ -50,7 +69,7 @@ export class RequestService { }); file.on("error", err => unlink(dest, () => subscriber.error(err))); - const req = get(url, { agent: this.ipv4Agent }, res => { + const req = get(url, this.requestOptionsFromDefaultInit(), res => { progress.total = parseInt(res.headers?.["content-length"] || "0", 10); res.on("data", chunk => { @@ -77,7 +96,7 @@ export class RequestService { const allChunks: Buffer[] = []; - const req = get(url, { agent: this.ipv4Agent }, res => { + const req = get(url, this.requestOptionsFromDefaultInit(), res => { progress.total = parseInt(res.headers?.["content-length"] || "0", 10); res.on("data", chunk => {