diff --git a/src/main/constants.ts b/src/main/constants.ts index a43daebd..651da7e5 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -20,8 +20,4 @@ export const HTTP_STATUS_CODES = constants; // Linux related stuff export const PROTON_BINARY_PREFIX = "proton"; -export const WINE_BINARY_PREFIX = path.join( - "files", "bin", "wine" -); - diff --git a/src/main/services/linux.service.ts b/src/main/services/linux.service.ts index beeb1122..524694b7 100644 --- a/src/main/services/linux.service.ts +++ b/src/main/services/linux.service.ts @@ -1,10 +1,10 @@ +import log from "electron-log"; import path from "path"; -import { StaticConfigurationService } from "./static-configuration.service"; import { pathExistsSync } from "fs-extra"; -import { PROTON_BINARY_PREFIX, WINE_BINARY_PREFIX } from "main/constants"; +import { PROTON_BINARY_PREFIX } from "main/constants"; +import { exec } from "child_process"; +import { StaticConfigurationService } from "./static-configuration.service"; - -// Linux handling export class LinuxService { private static instance: LinuxService; @@ -15,22 +15,59 @@ export class LinuxService { return LinuxService.instance; } + private readonly WINE_BINARY_PREFIX = path.join("files", "bin", "wine"); + private readonly staticConfig: StaticConfigurationService; + private winePath = ""; + private constructor() { this.staticConfig = StaticConfigurationService.getInstance(); } - public verifyProtonPath(): boolean { - if (!this.staticConfig.has("proton-folder")) { - return false; + public verifyProtonPath(protonFolder: string = ""): boolean { + if (protonFolder === "") { + if (!this.staticConfig.has("proton-folder")) { + return false; + } + + protonFolder = this.staticConfig.get("proton-folder"); } - const protonFolder = this.staticConfig.get("proton-folder"); const protonPath = path.join(protonFolder, PROTON_BINARY_PREFIX); - const winePath = path.join(protonFolder, WINE_BINARY_PREFIX); - - return pathExistsSync(protonPath) && pathExistsSync(winePath); + return pathExistsSync(protonPath); } + public async getWinePath(): Promise { + if (this.winePath) { + return this.winePath; + } + + return new Promise((resolve, reject) => { + // Get the default installed wine + exec("wine --version", (error, stdout) => { + if (!error) { + log.info("found", stdout); + this.winePath = "wine"; + return resolve("wine"); + } + + log.warn("wine is not installed, falling back to proton's wine binary"); + log.warn("wine warn:", error); + + // Fallback to the use the wine bundled in proton + if (!this.staticConfig.has("proton-folder")) { + return reject(new Error("proton folder not in configuration setup")); + } + + const tmpWinePath = path.join(this.staticConfig.get("proton-folder"), this.WINE_BINARY_PREFIX); + if (!pathExistsSync(tmpWinePath)) { + return reject(new Error("wine binary not in proton folder")); + } + + this.winePath = tmpWinePath; + resolve(this.winePath); + }); + }); + } } diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index b5392a08..874c074e 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -6,7 +6,7 @@ import path from "path"; import md5File from "md5-file"; import { RequestService } from "../request.service"; import { spawn } from "child_process"; -import { BS_EXECUTABLE, WINE_BINARY_PREFIX } from "../../constants"; +import { BS_EXECUTABLE } from "../../constants"; import log from "electron-log"; import { deleteFolder, pathExist, Progression, unlinkPath } from "../../helpers/fs.helpers"; import { lastValueFrom, Observable } from "rxjs"; @@ -17,15 +17,15 @@ import { sToMs } from "../../../shared/helpers/time.helpers"; import { ensureDir, pathExistsSync } from "fs-extra"; import { CustomError } from "shared/models/exceptions/custom-error.class"; import { popElement } from "shared/helpers/array.helpers"; -import { StaticConfigurationService } from "../static-configuration.service"; +import { LinuxService } from "../linux.service"; export class BsModsManagerService { private static instance: BsModsManagerService; private readonly beatModsApi: BeatModsApiService; private readonly bsLocalService: BSLocalVersionService; + private readonly linuxService: LinuxService; private readonly requestService: RequestService; - private readonly staticConfig: StaticConfigurationService; private manifestMatches: Mod[]; @@ -39,8 +39,8 @@ export class BsModsManagerService { private constructor() { this.beatModsApi = BeatModsApiService.getInstance(); this.bsLocalService = BSLocalVersionService.getInstance(); + this.linuxService = LinuxService.getInstance(); this.requestService = RequestService.getInstance(); - this.staticConfig = StaticConfigurationService.getInstance(); } private async getModFromHash(hash: string): Promise { @@ -143,34 +143,24 @@ export class BsModsManagerService { return false; } - // Just use the wine binary within the proton folder so no additional wine installation is needed - let winePath: string = ""; + let cmd = ""; if (process.platform === "linux") { - if (!this.staticConfig.has("proton-folder")) { - log.error("Proton folder not setup"); - return false; - } - - winePath = path.join( - this.staticConfig.get("proton-folder"), - WINE_BINARY_PREFIX - ); - - if (!pathExistsSync(winePath)) { - log.error("Wine binary not found"); + try { + const winePath = await this.linuxService.getWinePath(); + cmd = `"${winePath}" "${ipaPath}" "${bsExePath}" ${args.join(" ")}`; + } catch (error) { + log.error("wine not found", error); return false; } + } else { + cmd = `"${ipaPath}" "${bsExePath}" ${args.join(" ")}`; } return new Promise(resolve => { - const cmd = process.platform === "linux" - ? `"${winePath}" "${ipaPath}" ${args.join(" ")}` - : `"${ipaPath}" ${args.join(" ")}`; - log.info("START IPA PROCESS", cmd); const processIPA = spawn(cmd, { cwd: versionPath, detached: true, shell: true }); - const timemout = setTimeout(() => { + const timeout = setTimeout(() => { log.info("Ipa process timeout"); resolve(false) }, sToMs(30)); @@ -183,7 +173,7 @@ export class BsModsManagerService { }) processIPA.once("exit", code => { - clearTimeout(timemout); + clearTimeout(timeout); if (code === 0) { log.info("Ipa process exist with code 0"); return resolve(true); diff --git a/src/main/services/static-configuration.service.ts b/src/main/services/static-configuration.service.ts index 508df1ea..e4753842 100644 --- a/src/main/services/static-configuration.service.ts +++ b/src/main/services/static-configuration.service.ts @@ -1,7 +1,7 @@ import ElectronStore from "electron-store"; import { pathExistsSync } from "fs-extra"; import path from "path"; -import { PROTON_BINARY_PREFIX, WINE_BINARY_PREFIX } from "main/constants"; +import { PROTON_BINARY_PREFIX } from "main/constants"; import { Observable, Subject } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; import { CustomError } from "shared/models/exceptions/custom-error.class"; @@ -60,8 +60,7 @@ export class StaticConfigurationService { private validateProtonFolder(protonFolder: string): void { const protonPath = path.join(protonFolder, PROTON_BINARY_PREFIX); - const winePath = path.join(protonFolder, WINE_BINARY_PREFIX); - if (!pathExistsSync(protonPath) || !pathExistsSync(winePath)) { + if (!pathExistsSync(protonPath)) { throw new CustomError("Invalid proton folder path", "invalid-folder"); } }