mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feat-578] use installed wine first then fallback to proton's wine bin
* explicitly tell BSIPA where `Beat Saber.exe` is located
This commit is contained in:
@@ -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"
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -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<string> {
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Mod> {
|
||||
@@ -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<boolean>(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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user