add possibility to change installations folder

This commit is contained in:
MathieuG-P
2022-06-25 03:46:10 +02:00
parent ce768f6b8e
commit 0b50aa35f9
13 changed files with 190 additions and 36 deletions
+19 -3
View File
@@ -1,9 +1,9 @@
import { ipcMain } from 'electron';
import path from 'path';
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
import { UtilsService } from '../services/utils.service';
import { BSVersion } from '../services/bs-version-manager.service';
import { BSInstallerService, DownloadEventType } from '../services/bs-installer.service';
import { IpcRequest } from '../../shared/models/ipc-models.model';
import { InstallationLocationService } from '../services/installation-location.service';
import { UtilsService } from '../services/utils.service';
export interface InitDownloadInfoInterface {
@@ -29,6 +29,22 @@ ipcMain.on('bs-download.start', async (event, args: DownloadInfo) => {
ipcMain.on(`bs-download.${DownloadEventType.GUARD_CODE}`, async (event, args) => {
BSInstallerService.getInstance().sendInputProcess(args);
});
ipcMain.on('bs-download.installation-folder', async (event, request: IpcRequest<void>) => {
const installationFolder = InstallationLocationService.getInstance().installationDirectory;
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: installationFolder});
});
ipcMain.on('bs-download.set-installation-folder', (event, request: IpcRequest<string>) => {
const installerService = InstallationLocationService.getInstance();
installerService.setInstallationDirectory(request.args).then(res => {
console.log("déplacement terminer");
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: res});
}).catch(err => {
console.log(err);
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: false, error: err});
});
})
+1 -1
View File
@@ -23,7 +23,7 @@ ipcMain.on('bs-launch.launch', async (event, args: LauchOption) => { //Create a
cwd = await steamService.getGameFolder(BS_APP_ID, "Beat Saber");
}
else{
cwd = path.join(installerService.getBSInstallationFolder(), args.version.BSVersion);
cwd = path.join(installerService.installationFolder, args.version.BSVersion);
}
const exePath = path.join(cwd, BS_EXECUTABLE);
if(!UtilsService.getInstance().pathExist(exePath)){ UtilsService.getInstance().ipcSend("bs-launch.launch", 2); return; }
+1 -1
View File
@@ -25,7 +25,7 @@ ipcMain.on("bs-version.open-folder", async (event, args: BSVersion) => {
console.log(versionFolder)
}
else{
versionFolder = path.join(bsInstallerService.getBSInstallationFolder(), args.BSVersion);
versionFolder = path.join(bsInstallerService.installationFolder, args.BSVersion);
}
if(UtilsService.getInstance().folderExist(versionFolder)){
exec(`start "" "${versionFolder}"`);
+1 -1
View File
@@ -1,5 +1,5 @@
import './bs-download-ipcs';
import './window-controls-ipcs';
import './os-controls-ipcs';
import './bs-launcher-ipcs';
import './bs-version-ipcs';
import './bs-uninstall-ipcs';
+30
View File
@@ -0,0 +1,30 @@
import { ipcMain, shell, dialog } from 'electron';
import { UtilsService } from '../services/utils.service';
import { IpcRequest } from '../../shared/models/ipc-models.model';
import { getMainWindow } from '../main';
ipcMain.on('window.close', async () => {
getMainWindow()?.close();
});
ipcMain.on('window.maximize', async () => {
getMainWindow()?.maximize();
});
ipcMain.on('window.minimize', async () => {
getMainWindow()?.minimize();
});
ipcMain.on('window.reset', async () => {
getMainWindow()?.restore();
});
ipcMain.on('new-window', async (event, url: string) => {
shell.openExternal(url);
});
ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
dialog.showOpenDialog({properties: ['openDirectory']}).then(res => {
UtilsService.getInstance().newIpcSenc(request.responceChannel, {success: true, data: res});
})
})
-18
View File
@@ -1,18 +0,0 @@
import { ipcMain } from 'electron';
import { getMainWindow } from '../main';
ipcMain.on('window.close', async () => {
getMainWindow()?.close();
});
ipcMain.on('window.maximize', async () => {
getMainWindow()?.maximize();
});
ipcMain.on('window.minimize', async () => {
getMainWindow()?.minimize();
});
ipcMain.on('window.reset', async () => {
getMainWindow()?.restore();
});
+12 -11
View File
@@ -5,26 +5,30 @@ import { SteamService } from "./steam.service";
import { UtilsService } from "./utils.service";
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import log from "electron-log";
import { InstallationLocationService } from "./installation-location.service";
export class BSInstallerService{
private static readonly INSTALLATION_FOLDER = path.join("BSManager", "BSInstances");
private static readonly INSTALLATION_FOLDER = "BSInstances";
private static instance: BSInstallerService;
private readonly utils: UtilsService;
private readonly steamService: SteamService;
private readonly bsVersionService: BSVersionManagerService;
private readonly installLocationService: InstallationLocationService;
private downloadProcess: ChildProcessWithoutNullStreams;
private installationFolder: string;
private constructor(){
this.bsVersionService = BSVersionManagerService.getInstance();
this.utils = UtilsService.getInstance();
this.steamService = SteamService.getInstance();
this.installationFolder = path.join(this.utils.getUserDocumentsFolder(), BSInstallerService.INSTALLATION_FOLDER);
this.installLocationService = InstallationLocationService.getInstance();
}
public get installationFolder(): string{
return path.join(this.installLocationService.installationDirectory, BSInstallerService.INSTALLATION_FOLDER);
}
public static getInstance(){
@@ -36,9 +40,6 @@ export class BSInstallerService{
return path.join(this.utils.getAssetsPath(), 'depot-downloader', 'DepotDownloader.exe');
}
public getBSInstallationFolder(): string{ return this.installationFolder; }
public setBSInstallationFolder(path: string){ this.installationFolder = path; }
public async getInstalledBsVersion(): Promise<BSVersion[]>{
const versions: BSVersion[] = [];
const steamBsFolder = await this.steamService.getGameFolder(BS_APP_ID, "Beat Saber")
@@ -50,9 +51,9 @@ export class BSInstallerService{
}
}
if(!this.utils.folderExist(this.getBSInstallationFolder())){ return versions }
if(!this.utils.folderExist(this.installationFolder)){ return versions }
const folderInInstallation = this.utils.listDirsInDir(this.getBSInstallationFolder());
const folderInInstallation = this.utils.listDirsInDir(this.installationFolder);
folderInInstallation.forEach(f => {
const version = this.bsVersionService.getVersionDetailFromVersionNumber(f);
@@ -72,7 +73,7 @@ export class BSInstallerService{
const bsVersion = this.bsVersionService.getVersionDetailFromVersionNumber(downloadInfos.bsVersion.BSVersion);
if(!bsVersion){ this.utils.ipcSend(`bs-download.${DownloadEventType.ERROR}`); return; }
this.utils.createFolderIfNotExist(this.getBSInstallationFolder());
this.utils.createFolderIfNotExist(this.installationFolder);
this.downloadProcess = spawn(
this.getDepotDownloaderExePath(),
[
@@ -83,7 +84,7 @@ export class BSInstallerService{
`-dir ${bsVersion.BSVersion}`,
(downloadInfos.stay || !downloadInfos.password) && "-remember-password"
],
{shell: true, cwd: this.getBSInstallationFolder()}
{shell: true, cwd: this.installationFolder}
)
this.downloadProcess.stdout.on('data', async (data) => {
+1 -1
View File
@@ -22,7 +22,7 @@ export class BSUninstallerService {
public async uninstall(version :BSVersion){
if(version.steam){ throw "Cannot uninstall steam version"; }
const versionFolder = path.join(this.bsInstallerService.getBSInstallationFolder(), version.BSVersion);
const versionFolder = path.join(this.bsInstallerService.installationFolder, version.BSVersion);
if(!this.utilsService.folderExist(versionFolder)){ throw "Version folder not exist"; }
return await this.utilsService.deleteFolder(versionFolder);
@@ -0,0 +1,32 @@
import ElectronStore from "electron-store";
export class ConfigurationService {
private static instance: ConfigurationService;
private readonly _store: ElectronStore;
public static getInstance(): ConfigurationService{
if(!ConfigurationService.instance){ ConfigurationService.instance = new ConfigurationService(); }
return ConfigurationService.instance;
}
private constructor(){
this._store = new ElectronStore();
}
public get store(): ElectronStore{ return this._store; }
public set(key: string, value: any): void{
this.store.set(key, value);
}
public get(key: string): any{
return this.store.get(key);
}
public delete(key: string): void{
this.store.delete(key);
}
}
@@ -0,0 +1,56 @@
import path from "path";
import { ConfigurationService } from "./configuration.service";
import { UtilsService } from "./utils.service";
import fs from 'fs-extra';
import log from "electron-log";
export class InstallationLocationService {
private static instance: InstallationLocationService;
private readonly INSTALLATION_FOLDER = "BSManager";
private readonly STORE_INSTALLATION_PATH_KEY = "installation-folder";
private readonly configService: ConfigurationService;
private readonly utilsService: UtilsService;
private _installationDirectory: string;
public static getInstance(): InstallationLocationService{
if(!InstallationLocationService.instance){ InstallationLocationService.instance = new InstallationLocationService(); }
return InstallationLocationService.instance;
}
private constructor(){
this.configService = ConfigurationService.getInstance();
this.utilsService = UtilsService.getInstance();
this.initInstallationLocation();
}
private initInstallationLocation(): void{
this._installationDirectory = (this.configService.get(this.STORE_INSTALLATION_PATH_KEY) || this.utilsService.getUserDocumentsFolder()) as string;
}
public get installationDirectory(): string{
return path.join(this._installationDirectory, this.INSTALLATION_FOLDER);
}
public setInstallationDirectory(newDir: string): Promise<string>{
const oldDir = this.installationDirectory;
const newDest = path.join(newDir, this.INSTALLATION_FOLDER);
return new Promise<string>((resolve, reject) => {
fs.move(oldDir, newDest, { overwrite: true }).then(() => {
this._installationDirectory = newDir;
this.configService.store.set(this.STORE_INSTALLATION_PATH_KEY, newDir);
resolve(this.installationDirectory);
}).catch(err => {
reject(err);
log.error(err);
})
})
}
}
@@ -0,0 +1,22 @@
import { BsmButton } from "renderer/components/shared/bsm-button.component";
import { BsmImage } from "renderer/components/shared/bsm-image.component";
import { ModalExitCode, ModalResponse } from "renderer/services/modale.service";
import BeatConflict from "../../../../../assets/beat-conflict.png"
export function InstallationFolderModal({resolver}: {resolver: (x: ModalResponse) => void}) {
return (
<>
<span className="absolute bg-gradient-to-r from-blue-500 to-red-500 top-0 w-full left-0 h-1"></span>
<h1 className="text-3xl uppercase tracking-wide w-full text-center">installation folder</h1>
<BsmImage className="mx-auto h-24" image={BeatConflict}/>
<p className="max-w-sm">Changing the default installation folder for Beat Saber instances will cause all installed data to be moved to the new folder.</p>
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
<BsmButton className="rounded-md text-center bg-gray-500 hover:brightness-110 transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="Cancel"/>
<BsmButton className="rounded-md text-center bg-blue-500 hover:brightness-110 transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED})} withBar={false} text="Choose Folder"/>
</div>
</>
)
}
@@ -1,7 +1,9 @@
import { BehaviorSubject } from 'rxjs';
import { IpcResponse } from 'shared/models/ipc-models.model';
import { DownloadInfo } from '../../main/ipcs/bs-download-ipcs';
import { BSVersion } from '../../main/services/bs-version-manager.service'
import { BSVersionManagerService } from './bs-version-manager.service';
import { IpcService } from './ipc.service';
import { ModalExitCode, ModalService, ModalType } from './modale.service';
export class BsDownloaderService{
@@ -9,6 +11,7 @@ export class BsDownloaderService{
private static instance: BsDownloaderService;
private readonly modalService: ModalService = ModalService.getInsance();
private readonly ipcService: IpcService;
private readonly bsVersionManager: BSVersionManagerService = BSVersionManagerService.getInstance();
public readonly currentBsVersionDownload$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
@@ -16,6 +19,7 @@ export class BsDownloaderService{
public readonly selectedBsVersion$: BehaviorSubject<BSVersion> = new BehaviorSubject(null);
public static getInstance(): BsDownloaderService{
if(!BsDownloaderService.instance){ BsDownloaderService.instance = new BsDownloaderService(); }
return BsDownloaderService.instance;
@@ -23,6 +27,7 @@ export class BsDownloaderService{
private constructor(){
this.asignListerners();
this.ipcService = IpcService.getInstance();
}
private asignListerners(): void{
@@ -81,4 +86,13 @@ export class BsDownloaderService{
return !!this.currentBsVersionDownload$.value || !!this.downloadProgress$.value;
}
public async getInstallationFolder(): Promise<string>{
const res = await this.ipcService.send<string>("bs-download.installation-folder");
return res.success ? res.data : "";
}
public setInstallationFolder(path: string): Promise<IpcResponse<string>>{
return this.ipcService.send<string>("bs-download.set-installation-folder", {args: path});
}
}
+1
View File
@@ -52,6 +52,7 @@ export enum ModalType {
STEAM_LOGIN = "STEAM_LOGIN",
GUARD_CODE = "GUARD_CODE",
UNINSTALL = "UNINSTALL",
INSTALLATION_FOLDER = "INSTALLATION_FOLDER",
}
export enum ModalExitCode {