diff --git a/src/main/services/bs-launcher/oculus-launcher.service.ts b/src/main/services/bs-launcher/oculus-launcher.service.ts index 068e3694..f0757254 100644 --- a/src/main/services/bs-launcher/oculus-launcher.service.ts +++ b/src/main/services/bs-launcher/oculus-launcher.service.ts @@ -1,15 +1,16 @@ import { Observable, ReplaySubject, catchError, lastValueFrom, of, take, timeout } from "rxjs"; import { StoreLauncherInterface } from "./store-launcher.interface"; -import { BSLaunchError, BSLaunchErrorData, BSLaunchEvent, BSLaunchEventData, LaunchOption } from "../../../shared/models/bs-launch"; +import { BSLaunchError, BSLaunchEvent, BSLaunchEventData, LaunchOption } from "../../../shared/models/bs-launch"; import { OculusService } from "../oculus.service"; import { BS_EXECUTABLE, OCULUS_BS_BACKUP_DIR, OCULUS_BS_DIR } from "../../constants"; import path from "path"; import log from "electron-log"; import { sToMs } from "../../../shared/helpers/time.helpers"; -import { lstat, pathExists, readdir, rename, stat, symlink, unlink } from "fs-extra"; +import { pathExists, readdir, rename, symlink, unlink } from "fs-extra"; import { AbstractLauncherService } from "./abstract-launcher.service"; import { taskRunning } from "../../helpers/os.helpers"; import { isJunction } from "../../helpers/fs.helpers"; +import { CustomError } from "../../../shared/models/exceptions/custom-error.class"; export class OculusLauncherService extends AbstractLauncherService implements StoreLauncherInterface { @@ -84,12 +85,15 @@ export class OculusLauncherService extends AbstractLauncherService implements St return rename(bsFolderBackupPath, originalPath); } - // TODO : Convert all errors to CustomError public launch(launchOptions: LaunchOption): Observable { const prepareOriginalVersion: () => Promise = async () => { await this.restoreOriginalBeatSaber(); - return this.oculus.getGameFolder(OCULUS_BS_DIR); + const bsPath = this.oculus.getGameFolder(OCULUS_BS_DIR); + if(!bsPath){ + throw new Error("Oculus Beat Saber path not found"); + } + return bsPath; } const prepareDowngradedVersion: () => Promise = async () => { @@ -115,29 +119,37 @@ export class OculusLauncherService extends AbstractLauncherService implements St (async () => { // Cannot start multiple instances of Beat Saber with Oculus - const bsRunning = await taskRunning(BS_EXECUTABLE); + const bsRunning = await taskRunning(BS_EXECUTABLE).catch(() => false); if(bsRunning){ - throw ({type: BSLaunchError.BS_ALREADY_RUNNING, data: bsRunning}) as BSLaunchErrorData; + throw CustomError.fromError(new Error("Cannot start two instance of Beat Saber for Oculus"), BSLaunchError.BS_ALREADY_RUNNING); } // Remove previously symlinks created by BSM - await this.deleteBsSymlinks().catch(log.error); + await this.deleteBsSymlinks().catch(err => log.error("Error while deleting BSM symlinks", err)); - const bsPath = await (launchOptions.version.oculus ? prepareOriginalVersion() : prepareDowngradedVersion()); - - if(!bsPath){ - throw ({type: BSLaunchError.BS_NOT_FOUND}) as BSLaunchErrorData; - } + const bsPath = await (launchOptions.version.oculus ? prepareOriginalVersion() : prepareDowngradedVersion()) + .catch(err => CustomError.throw(err, BSLaunchError.OCULUS_LIB_NOT_FOUND)); // Launch Beat Saber - const exePath = path.join(bsPath, "Beat Saber.exe"); + const exePath = path.join(bsPath, BS_EXECUTABLE); + + if(!(await pathExists(exePath))){ + throw CustomError.fromError(new Error(`BS Path not exist ${bsPath}`), BSLaunchError.BS_NOT_FOUND); + } + obs.next({type: BSLaunchEvent.BS_LAUNCHING}); return this.launchBs(exePath, this.buildBsLaunchArgs(launchOptions)).catch(err => { - throw ({type: BSLaunchError.BS_EXIT_ERROR, data: err}) as BSLaunchErrorData; + throw CustomError.fromError(err, BSLaunchError.BS_EXIT_ERROR); }); - })().catch(err => { - obs.error(err); + })().then(exitCode => { + log.info("BS process exit code", exitCode); + }).catch(err => { + if(err instanceof CustomError){ + obs.error(err); + } else { + obs.error(CustomError.fromError(err, BSLaunchError.UNKNOWN_ERROR)); + } }).finally(() => { obs.complete(); }) diff --git a/src/main/services/bs-launcher/steam-launcher.service.ts b/src/main/services/bs-launcher/steam-launcher.service.ts index 608a9d9f..7ebc0cb0 100644 --- a/src/main/services/bs-launcher/steam-launcher.service.ts +++ b/src/main/services/bs-launcher/steam-launcher.service.ts @@ -1,5 +1,5 @@ import { Observable } from "rxjs"; -import { BSLaunchError, BSLaunchErrorData, BSLaunchEvent, BSLaunchEventData, BSLaunchWarning, LaunchOption } from "../../../shared/models/bs-launch"; +import { BSLaunchError, BSLaunchEvent, BSLaunchEventData, BSLaunchWarning, LaunchOption } from "../../../shared/models/bs-launch"; import { StoreLauncherInterface } from "./store-launcher.interface"; import { pathExists, rename } from "fs-extra"; import { SteamService } from "../steam.service"; @@ -7,6 +7,7 @@ import path from "path"; import { BS_APP_ID, BS_EXECUTABLE, STEAMVR_APP_ID } from "../../constants"; import log from "electron-log"; import { AbstractLauncherService } from "./abstract-launcher.service"; +import { CustomError } from "../../../shared/models/exceptions/custom-error.class"; export class SteamLauncherService extends AbstractLauncherService implements StoreLauncherInterface{ @@ -52,8 +53,7 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto log.error("Error while restoring SteamVR", err); }); } - - // TODO : Convert all errors to CustomError + public launch(launchOptions: LaunchOption): Observable{ return new Observable(obs => {(async () => { @@ -62,11 +62,11 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto const exePath = path.join(bsFolderPath, BS_EXECUTABLE); if(!(await pathExists(exePath))){ - return obs.error({type: BSLaunchError.BS_NOT_FOUND} as BSLaunchErrorData); + throw CustomError.fromError(new Error(`Path not exist : ${exePath}`), BSLaunchError.BS_NOT_FOUND); } // Open Steam if not running - if(!launchOptions.version.oculus && !(await this.steam.steamRunning())){ + if(!(await this.steam.steamRunning())){ obs.next({type: BSLaunchEvent.STEAM_LAUNCHING}); await this.steam.openSteam().then(() => { @@ -78,22 +78,22 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto } // Backup SteamVR when desktop mode is enabled - if(!launchOptions.version.oculus && launchOptions.desktop){ + if(launchOptions.desktop){ await this.backupSteamVR().catch(() => { return this.restoreSteamVR(); }); - } else if(!launchOptions.version.oculus){ - await this.restoreSteamVR(); + } else { + await this.restoreSteamVR().catch(log.error); } const launchArgs = this.buildBsLaunchArgs(launchOptions); obs.next({type: BSLaunchEvent.BS_LAUNCHING}); - this.launchBs(exePath, launchArgs, { env: {...process.env, "SteamAppId": BS_APP_ID} }).then(exitCode => { + await this.launchBs(exePath, launchArgs, { env: {...process.env, "SteamAppId": BS_APP_ID} }).then(exitCode => { log.info("BS process exit code", exitCode); }).catch(err => { - obs.error({type: BSLaunchError.BS_EXIT_ERROR, data: err} as BSLaunchErrorData); + throw CustomError.fromError(err, BSLaunchError.BS_EXIT_ERROR); }).finally(() => { this.restoreSteamVR().catch(log.error); }); @@ -101,7 +101,11 @@ export class SteamLauncherService extends AbstractLauncherService implements Sto })().then(() => { obs.complete(); }).catch(err => { - obs.error({type: BSLaunchError.UNKNOWN_ERROR, data: err} as BSLaunchErrorData); + if(err instanceof CustomError){ + obs.error(err); + } else { + obs.error(CustomError.fromError(err, BSLaunchError.UNKNOWN_ERROR)); + } })}); } diff --git a/src/renderer/services/bs-launcher.service.ts b/src/renderer/services/bs-launcher.service.ts index 9aa09461..8770f4ff 100644 --- a/src/renderer/services/bs-launcher.service.ts +++ b/src/renderer/services/bs-launcher.service.ts @@ -1,4 +1,4 @@ -import { LaunchOption, BSLaunchEvent, BSLaunchWarning, BSLaunchEventData, BSLaunchErrorData, BSLaunchError } from "shared/models/bs-launch"; +import { LaunchOption, BSLaunchEvent, BSLaunchWarning, BSLaunchEventData, BSLaunchError } from "shared/models/bs-launch"; import { BSVersion } from 'shared/bs-version.interface'; import { IpcService } from "./ipc.service"; import { NotificationService } from "./notification.service"; @@ -8,6 +8,8 @@ import { ThemeService } from "./theme.service"; import { BsStore } from "shared/models/bs-store.enum"; import { ModalExitCode, ModalService } from "./modale.service"; import { OriginalOculusVersionBackupModal } from "renderer/components/modal/modal-types/original-oculus-version-backup.modal"; +import { CustomError } from "shared/models/exceptions/custom-error.class"; +import { sToMs } from "shared/helpers/time.helpers"; export class BSLauncherService { private static instance: BSLauncherService; @@ -59,11 +61,11 @@ export class BSLauncherService { if(eventToFilter.includes(event.type)){ return; } this.notificationService.notifySuccess({title: `notifications.bs-launch.success.titles.${event.type}`, desc: `notifications.bs-launch.success.msg.${event.type}`}); }, - error: (err: BSLaunchErrorData) => { // TODO : Convert all errors to CustomError - if(!Object.values(BSLaunchError).includes(err.type)){ + error: (err: CustomError) => { + if(!err?.code || !Object.values(BSLaunchError).includes(err.code as BSLaunchError)){ this.notificationService.notifyError({title: "notifications.bs-launch.errors.titles.UNKNOWN_ERROR", desc: "notifications.bs-launch.errors.msg.UNKNOWN_ERROR"}); } else { - this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${err.type}`, desc: `notifications.bs-launch.errors.msg.${err.type}`}) + this.notificationService.notifyError({title: `notifications.bs-launch.errors.titles.${err.code}`, desc: `notifications.bs-launch.errors.msg.${err.code}`, duration: sToMs(9)}) } } }))