From 30a53c013f7e4d108a217634461224f639df68f0 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:51:51 +0100 Subject: [PATCH 1/6] [bugfix] fix downloading models not working Add useragent to requests to not being rejected --- release/app/package-lock.json | 4 ++-- src/main/services/request.service.ts | 33 ++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/release/app/package-lock.json b/release/app/package-lock.json index 24e99b05..9afc7978 100644 --- a/release/app/package-lock.json +++ b/release/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "bs-manager", - "version": "1.4.4", + "version": "1.4.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bs-manager", - "version": "1.4.4", + "version": "1.4.6", "hasInstallScript": true, "license": "MIT", "dependencies": { 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 => { From 88a1691d4b5a1bd2b766ce48db86b493d3bd3a6c Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:04:45 +0100 Subject: [PATCH 2/6] bumb to 1.4.7 --- release/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/app/package.json b/release/app/package.json index 0d1d674d..8cc11a8c 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -1,6 +1,6 @@ { "name": "bs-manager", - "version": "1.4.6", + "version": "1.4.7", "description": "BSManager", "main": "./dist/main/main.js", "author": { From 067b967da1fc58d6e8e15f2f859ca1552848ac35 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:55:16 +0100 Subject: [PATCH 3/6] add patreon --- assets/jsons/patreons.json | 3 +++ 1 file changed, 3 insertions(+) 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" } ] From 49358b7006ee0415b8c19c1c5b2457f66c32450c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Libor=20=C5=A0af=C3=A1=C5=99?= Date: Fri, 15 Mar 2024 17:44:22 +0100 Subject: [PATCH 4/6] Add reset button for name to version edit modal --- .../modal-types/edit-version-modal.component.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx b/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx index fc1e549b..19dbae7b 100644 --- a/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/edit-version-modal.component.tsx @@ -29,6 +29,10 @@ export const EditVersionModal: ModalComponent<{ name: string; color: string }, { setColor(configService.get("second-color" as DefaultConfigKey)); }; + const resetName = () => { + setName(version.BSVersion); + }; + return (
{t("modals.clone-version.inputs.name.label")} - setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} /> +
+ setName(e.target.value)} value={name} type="text" name="name" id="name" minLength={2} maxLength={15} placeholder={t("modals.clone-version.inputs.name.placeholder")} /> +
+ +
+
{t("modals.clone-version.inputs.color.label")} From d7f3936619bcb72763f792e5c8e9d0d0475c3969 Mon Sep 17 00:00:00 2001 From: Pierce Thompson Date: Sat, 16 Mar 2024 20:57:55 -0400 Subject: [PATCH 5/6] Fix BSIPA not running on Linux --- src/main/services/mods/bs-mods-manager.service.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 From 169a6e99b0005e84ede899aa73d4aa5b7ea6a37a Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Wed, 20 Mar 2024 19:00:35 +0100 Subject: [PATCH 6/6] [chore] add routes for IPCs + migrate all old ipc.send to sendV2 + remove some dead code --- assets/jsons/bs-versions.json | 4 +- src/main/ipcs/beat-saver-ipcs.ts | 64 ++----- src/main/ipcs/bs-launcher-ipcs.ts | 14 +- src/main/ipcs/bs-maps-ipcs.ts | 113 +++-------- src/main/ipcs/bs-model-ipcs.ts | 83 +++----- src/main/ipcs/bs-mods-ipcs.ts | 57 +----- src/main/ipcs/bs-playlist-ipcs.ts | 41 +--- src/main/ipcs/bs-uninstall-ipcs.ts | 6 +- .../bs-version-download/bs-download-ipcs.ts | 51 ++--- src/main/ipcs/bs-version-ipcs.ts | 180 ++++-------------- src/main/ipcs/launcher-ipcs.ts | 18 +- src/main/ipcs/model-saber.ipcs.ts | 21 +- src/main/ipcs/os-controls-ipcs.ts | 52 ++--- src/main/ipcs/supporters-ipcs.ts | 20 +- src/main/ipcs/window-manager-ipcs.ts | 31 ++- src/main/main.ts | 10 +- src/main/preload.ts | 9 +- .../local-maps-manager.service.ts | 35 ++-- .../local-models-manager.service.ts | 20 +- .../local-playlists-manager.service.ts | 12 +- .../bs-launcher/bs-launcher.service.ts | 24 +-- .../bs-oculus-downloader.service.ts | 121 +----------- src/main/services/ipc.service.ts | 28 +-- .../services/mods/bs-mods-manager.service.ts | 4 +- .../share-folders-modal.component.tsx | 9 +- .../title-bar/title-bar.component.tsx | 16 +- src/renderer/hooks/use-window-args.hook.ts | 16 ++ .../hooks/use-window-controls.hook.ts | 17 ++ .../pages/settings-page.component.tsx | 21 +- .../pages/version-viewer.component.tsx | 2 +- src/renderer/preload.d.ts | 6 - src/renderer/services/auto-updater.service.ts | 11 +- src/renderer/services/bs-launcher.service.ts | 10 +- .../services/bs-mods-manager.service.ts | 56 +++--- .../oculus-downloader.service.ts | 14 +- .../steam-downloader.service.ts | 30 +-- .../services/bs-version-manager.service.ts | 64 ++++--- src/renderer/services/ipc.service.ts | 19 +- src/renderer/services/link-opener.service.ts | 4 +- .../services/maps-downloader.service.ts | 11 +- src/renderer/services/maps-manager.service.ts | 36 ++-- .../models-downloader.service.ts | 9 +- .../models-manager.service.ts | 27 ++- src/renderer/services/notification.service.ts | 6 +- .../services/playlist-downloader.service.ts | 2 +- .../services/playlists-manager.service.ts | 9 +- src/renderer/services/progress-bar.service.ts | 4 +- src/renderer/services/supporters.service.ts | 8 +- .../thrird-partys/beat-saver.service.ts | 17 +- .../thrird-partys/model-saber.service.ts | 12 +- .../services/version-folder-linker.service.ts | 10 +- .../services/window-manager.service.ts | 6 +- .../windows/OneClick/OneClickDownloadMap.tsx | 26 +-- .../OneClick/OneClickDownloadModel.tsx | 12 +- .../OneClick/OneClickDownloadPlaylist.tsx | 13 +- src/renderer/windows/ShortcutLaunch.tsx | 10 +- .../models/ipc/ipc-request.interface.ts | 2 +- src/shared/models/ipc/ipc-routes.ts | 134 +++++++++++++ 58 files changed, 645 insertions(+), 1022 deletions(-) create mode 100644 src/renderer/hooks/use-window-args.hook.ts create mode 100644 src/renderer/hooks/use-window-controls.hook.ts create mode 100644 src/shared/models/ipc/ipc-routes.ts diff --git a/assets/jsons/bs-versions.json b/assets/jsons/bs-versions.json index 6484682a..719425bf 100644 --- a/assets/jsons/bs-versions.json +++ b/assets/jsons/bs-versions.json @@ -700,7 +700,7 @@ "ReleaseDate": "1708091473", "year": "2024" }, - { + { "BSVersion": "1.35.0", "BSManifest": "1490986193481243578", "OculusBinaryId": "6720809361352119", @@ -709,4 +709,4 @@ "ReleaseDate": "1709831174", "year": "2024" } -] +] \ No newline at end of file diff --git a/src/main/ipcs/beat-saver-ipcs.ts b/src/main/ipcs/beat-saver-ipcs.ts index 9ed7df2f..ed730d4a 100644 --- a/src/main/ipcs/beat-saver-ipcs.ts +++ b/src/main/ipcs/beat-saver-ipcs.ts @@ -1,63 +1,21 @@ -import { ipcMain } from "electron"; -import { UtilsService } from "../services/utils.service"; -import { IpcRequest } from "shared/models/ipc"; -import { SearchParams } from "shared/models/maps/beat-saver.model"; import { BeatSaverService } from "../services/thrid-party/beat-saver/beat-saver.service"; -import log from "electron-log"; +import { IpcService } from "../services/ipc.service"; +import { from } from "rxjs"; -ipcMain.on("bsv-search-map", async (event, request: IpcRequest) => { - const utlis = UtilsService.getInstance(); +const ipc = IpcService.getInstance(); + +ipc.on("bsv-search-map", (args, reply) => { const bsvService = BeatSaverService.getInstance(); - - bsvService - .searchMaps(request.args) - .then(maps => { - utlis.ipcSend(request.responceChannel, { success: true, data: maps }); - }) - .catch(e => { - utlis.ipcSend(request.responceChannel, { success: false, error: e }); - }); + reply(from(bsvService.searchMaps(args))); }); -ipcMain.on("bsv-get-map-details-from-hashs", async (event, request: IpcRequest) => { - const utlis = UtilsService.getInstance(); +ipc.on("bsv-get-map-details-from-hashs", (args, reply) => { const bsvService = BeatSaverService.getInstance(); - - bsvService - .getMapDetailsFromHashs(request.args) - .then(maps => { - utlis.ipcSend(request.responceChannel, { success: true, data: maps }); - }) - .catch(e => { - log.error(e); - utlis.ipcSend(request.responceChannel, { success: false, error: e }); - }); + reply(from(bsvService.getMapDetailsFromHashs(args))); }); -ipcMain.on("bsv-get-map-details-by-id", async (event, request: IpcRequest) => { - const utlis = UtilsService.getInstance(); +ipc.on("bsv-get-map-details-by-id", (args, reply) => { const bsvService = BeatSaverService.getInstance(); - - bsvService - .getMapDetailsById(request.args) - .then(maps => { - utlis.ipcSend(request.responceChannel, { success: true, data: maps }); - }) - .catch(e => { - utlis.ipcSend(request.responceChannel, { success: false, error: e }); - }); -}); - -ipcMain.on("bsv-get-playlist-details-by-id", async (event, request: IpcRequest) => { - const utlis = UtilsService.getInstance(); - const bsvService = BeatSaverService.getInstance(); - - bsvService - .getPlaylistPage(request.args) - .then(maps => { - utlis.ipcSend(request.responceChannel, { success: true, data: maps }); - }) - .catch(e => { - utlis.ipcSend(request.responceChannel, { success: false, error: e }); - }); + console.log("AAAAAAZEZE", args); + reply(from(bsvService.getMapDetailsById(args))); }); diff --git a/src/main/ipcs/bs-launcher-ipcs.ts b/src/main/ipcs/bs-launcher-ipcs.ts index 8f70af62..dd2ffcd6 100644 --- a/src/main/ipcs/bs-launcher-ipcs.ts +++ b/src/main/ipcs/bs-launcher-ipcs.ts @@ -1,22 +1,20 @@ -import { LaunchOption } from "shared/models/bs-launch"; import { BSLauncherService } from "../services/bs-launcher/bs-launcher.service" import { IpcService } from '../services/ipc.service'; import { from } from "rxjs"; import { SteamLauncherService } from "../services/bs-launcher/steam-launcher.service"; -import { OculusLauncherService } from "../services/bs-launcher/oculus-launcher.service"; import { SteamService } from "../services/steam.service"; import log from "electron-log"; import isElevated from "is-elevated"; const ipc = IpcService.getInstance(); -ipc.on('bs-launch.launch', (req, reply) => { +ipc.on('bs-launch.launch', (args, reply) => { const bsLauncher = BSLauncherService.getInstance(); - reply(bsLauncher.launch(req.args)); + reply(bsLauncher.launch(args)); }); -ipc.on("bs-launch.need-start-as-admin", (_, reply) => { +ipc.on("bs-launch.need-start-as-admin", (_, reply) => { const steam = SteamService.getInstance(); reply(from(isElevated().then(elevated => { if(elevated){ return false; } @@ -27,12 +25,12 @@ ipc.on("bs-launch.need-start-as-admin", (_, reply) => { }))); }); -ipc.on("create-launch-shortcut", (req, reply) => { +ipc.on("create-launch-shortcut", (args, reply) => { const bsLauncher = BSLauncherService.getInstance(); - reply(from(bsLauncher.createLaunchShortcut(req.args))); + reply(from(bsLauncher.createLaunchShortcut(args))); }); -ipc.on("bs-launch.restore-steamvr", (_, reply) => { +ipc.on("bs-launch.restore-steamvr", (_, reply) => { const steamLauncher = SteamLauncherService.getInstance(); reply(from(steamLauncher.restoreSteamVR())); }); diff --git a/src/main/ipcs/bs-maps-ipcs.ts b/src/main/ipcs/bs-maps-ipcs.ts index 24b4fef0..112df2f5 100644 --- a/src/main/ipcs/bs-maps-ipcs.ts +++ b/src/main/ipcs/bs-maps-ipcs.ts @@ -1,119 +1,64 @@ import { LocalMapsManagerService } from "../services/additional-content/local-maps-manager.service"; -import { UtilsService } from "../services/utils.service"; -import { BSVersion } from "shared/bs-version.interface"; -import { IpcRequest } from "shared/models/ipc"; -import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; -import { BsvMapDetail } from "shared/models/maps"; import { IpcService } from "../services/ipc.service"; -import { from } from "rxjs"; -import log from "electron-log" +import { from, of, throwError } from "rxjs"; +import { tryit } from "shared/helpers/error.helpers"; const ipc = IpcService.getInstance(); -ipc.on("load-version-maps", async (request: IpcRequest, reply) => { +ipc.on("load-version-maps", (args, reply) => { const localMaps = LocalMapsManagerService.getInstance(); - reply(localMaps.getMaps(request.args)); + reply(localMaps.getMaps(args)); }); -ipc.on("verion-have-maps-linked", async (request: IpcRequest) => { - const utils = UtilsService.getInstance(); +ipc.on("delete-maps", (args, reply) => { const maps = LocalMapsManagerService.getInstance(); - - utils.ipcSend(request.responceChannel, { success: true, data: await maps.versionIsLinked(request.args) }); + reply(maps.deleteMaps(args)); }); -ipc.on("link-version-maps", async (request: IpcRequest<{ version: BSVersion; keepMaps: boolean }>) => { - const utils = UtilsService.getInstance(); +ipc.on("export-maps", async (args, reply) => { const maps = LocalMapsManagerService.getInstance(); - - maps.linkVersionMaps(request.args.version, request.args.keepMaps) - .then(() => { - utils.ipcSend(request.responceChannel, { success: true }); - }) - .catch(err => { - utils.ipcSend(request.responceChannel, { success: true, error: err }); - }); + reply(await maps.exportMaps(args.version, args.maps, args.outPath)); }); -ipc.on("unlink-version-maps", async (request: IpcRequest<{ version: BSVersion; keepMaps: boolean }>) => { - const utils = UtilsService.getInstance(); +ipc.on("download-map", async (args, reply) => { const maps = LocalMapsManagerService.getInstance(); - - maps.unlinkVersionMaps(request.args.version, request.args.keepMaps) - .then(() => { - utils.ipcSend(request.responceChannel, { success: true }); - }) - .catch(err => { - utils.ipcSend(request.responceChannel, { success: true, error: err }); - }); + reply(from(maps.downloadMap(args.map, args.version))); }); -ipc.on("delete-maps", async (request: IpcRequest, reply) => { +ipc.on("one-click-install-map", (args, reply) => { const maps = LocalMapsManagerService.getInstance(); - reply(maps.deleteMaps(request.args)); + reply(from(maps.oneClickDownloadMap(args))) }); -ipc.on("export-maps", async (request: IpcRequest<{ version: BSVersion; maps: BsmLocalMap[]; outPath: string }>, reply) => { +ipc.on("register-maps-deep-link", (_, reply) => { const maps = LocalMapsManagerService.getInstance(); - reply(await maps.exportMaps(request.args.version, request.args.maps, request.args.outPath)); -}); + const { error, result } = tryit(() => maps.enableDeepLinks()); -ipc.on("download-map", async (request: IpcRequest<{ map: BsvMapDetail; version: BSVersion }>, reply) => { - const maps = LocalMapsManagerService.getInstance(); - reply(from(maps.downloadMap(request.args.map, request.args.version))); -}); - -ipc.on("one-click-install-map", async (request: IpcRequest) => { - const utils = UtilsService.getInstance(); - const maps = LocalMapsManagerService.getInstance(); - - maps.oneClickDownloadMap(request.args) - .then(() => { - utils.ipcSend(request.responceChannel, { success: true }); - }) - .catch(err => { - log.error(err); - utils.ipcSend(request.responceChannel, { success: false, error: err }); - }); -}); - -ipc.on("register-maps-deep-link", async (request: IpcRequest) => { - const maps = LocalMapsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.enableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); + if(error) { + return reply(throwError(() => error)); } + + reply(of(result)); }); -ipc.on("unregister-maps-deep-link", async (request: IpcRequest) => { +ipc.on("unregister-maps-deep-link", (_, reply) => { const maps = LocalMapsManagerService.getInstance(); - const utils = UtilsService.getInstance(); + const { error, result } = tryit(() => maps.disableDeepLinks()); - try { - const res = maps.disableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); + if(error) { + return reply(throwError(() => error)); } + + reply(of(result)); }); -ipc.on("is-map-deep-links-enabled", async (request: IpcRequest) => { +ipc.on("is-map-deep-links-enabled", (_, reply) => { const maps = LocalMapsManagerService.getInstance(); - const utils = UtilsService.getInstance(); + const { error, result } = tryit(() => maps.isDeepLinksEnabled()); - try { - const res = maps.isDeepLinksEnabled(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); + if(error) { + return reply(throwError(() => error)); } -}); -ipc.on("get-version-maps-path", async (req: IpcRequest, reply) => { - const maps = LocalMapsManagerService.getInstance(); - reply(from(maps.getMapsFolderPath(req.args))); + reply(of(result)); }); diff --git a/src/main/ipcs/bs-model-ipcs.ts b/src/main/ipcs/bs-model-ipcs.ts index 223b3884..70fde8bf 100644 --- a/src/main/ipcs/bs-model-ipcs.ts +++ b/src/main/ipcs/bs-model-ipcs.ts @@ -1,82 +1,45 @@ -import { ipcMain } from "electron"; -import { UtilsService } from "../services/utils.service"; -import { IpcRequest } from "shared/models/ipc"; -import { MSModel, MSModelType } from "shared/models/models/model-saber.model"; import { LocalModelsManagerService } from "../services/additional-content/local-models-manager.service"; import { IpcService } from "../services/ipc.service"; -import { BSVersion } from "shared/bs-version.interface"; -import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface"; -import { ModelDownload } from "renderer/services/models-management/models-downloader.service"; +import { from, of } from "rxjs"; const ipc = IpcService.getInstance(); -ipcMain.on("one-click-install-model", async (event, request: IpcRequest) => { - const utils = UtilsService.getInstance(); +ipc.on("one-click-install-model", (args, reply) => { const models = LocalModelsManagerService.getInstance(); - - models - .oneClickDownloadModel(request.args) - .then(() => { - utils.ipcSend(request.responceChannel, { success: true }); - }) - .catch(e => { - utils.ipcSend(request.responceChannel, { success: false, error: e }); - }); + reply(from(models.oneClickDownloadModel(args))); }); -ipcMain.on("register-models-deep-link", async (event, request: IpcRequest) => { +ipc.on("register-models-deep-link", (_, reply) => { + const models = LocalModelsManagerService.getInstance(); + reply(of(models.enableDeepLinks())); +}); + +ipc.on("unregister-models-deep-link", (_, reply) => { + const models = LocalModelsManagerService.getInstance(); + reply(of(models.disableDeepLinks())); +}); + +ipc.on("is-models-deep-links-enabled", (_, reply) => { const maps = LocalModelsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.enableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } + reply(of(maps.isDeepLinksEnabled())); }); -ipcMain.on("unregister-models-deep-link", async (event, request: IpcRequest) => { - const maps = LocalModelsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.disableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } -}); - -ipcMain.on("is-models-deep-links-enabled", async (event, request: IpcRequest) => { - const maps = LocalModelsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.isDeepLinksEnabled(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } -}); - -ipc.on("download-model", async (req, reply) => { +ipc.on("download-model", (args, reply) => { const models = LocalModelsManagerService.getInstance(); - reply(models.downloadModel(req.args.model, req.args.version)); + reply(models.downloadModel(args.model, args.version)); }); -ipc.on<{ version: BSVersion; type: MSModelType }>("get-version-models", async (req, reply) => { +ipc.on("get-version-models", (args, reply) => { const models = LocalModelsManagerService.getInstance(); - const res = await models.getModels(req.args.type, req.args.version); - reply(res); + reply(from(models.getModels(args.type, args.version))); }); -ipc.on<{ version: BSVersion; models: BsmLocalModel[]; outPath: string }>("export-models", async (req, reply) => { +ipc.on("export-models", (args, reply) => { const models = LocalModelsManagerService.getInstance(); - reply(models.exportModels(req.args.outPath, req.args.version, req.args.models)); + reply(models.exportModels(args.outPath, args.version, args.models)); }); -ipc.on("delete-models", async (req, reply) => { +ipc.on("delete-models", (args, reply) => { const models = LocalModelsManagerService.getInstance(); - reply(models.deleteModels(req.args)); + reply(models.deleteModels(args)); }); diff --git a/src/main/ipcs/bs-mods-ipcs.ts b/src/main/ipcs/bs-mods-ipcs.ts index 20509c0b..7d580f04 100644 --- a/src/main/ipcs/bs-mods-ipcs.ts +++ b/src/main/ipcs/bs-mods-ipcs.ts @@ -1,67 +1,30 @@ -import { ipcMain } from "electron"; import { BsModsManagerService } from "../services/mods/bs-mods-manager.service"; -import { UtilsService } from "../services/utils.service"; -import { BSVersion } from "shared/bs-version.interface"; -import { IpcRequest } from "shared/models/ipc"; -import { Mod } from "shared/models/mods/mod.interface"; -import { InstallModsResult } from "shared/models/mods"; -import log from "electron-log"; import { IpcService } from "../services/ipc.service"; import { from } from "rxjs"; const ipc = IpcService.getInstance(); -ipc.on("get-available-mods", (req, reply) => { +ipc.on("get-available-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - reply(from(modsManager.getAvailableMods(req.args))); + reply(from(modsManager.getAvailableMods(args))); }); -ipc.on("get-installed-mods", (req, reply) => { +ipc.on("get-installed-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - reply(from(modsManager.getInstalledMods(req.args))); + reply(from(modsManager.getInstalledMods(args))); }); -ipcMain.on("install-mods", (event, request: IpcRequest<{ mods: Mod[]; version: BSVersion }>) => { - const utils = UtilsService.getInstance(); +ipc.on("install-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - - modsManager - .installMods(request.args.mods, request.args.version) - .then(nbInstalled => { - utils.ipcSend(request.responceChannel, { success: true, data: nbInstalled }); - }) - .catch(err => { - utils.ipcSend(request.responceChannel, { success: false, error: err }); - log.error("ipc", "install-mods", err, request); - }); + reply(from(modsManager.installMods(args.mods, args.version))); }); -ipcMain.on("uninstall-mods", (event, request: IpcRequest<{ mods: Mod[]; version: BSVersion }>) => { - const utils = UtilsService.getInstance(); +ipc.on("uninstall-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - - modsManager - .uninstallMods(request.args.mods, request.args.version) - .then(nbInstalled => { - utils.ipcSend(request.responceChannel, { success: true, data: nbInstalled }); - }) - .catch(err => { - utils.ipcSend(request.responceChannel, { success: false, error: err }); - log.error("ipc", "uninstall-mods", err, request); - }); + reply(from(modsManager.uninstallMods(args.mods, args.version))); }); -ipcMain.on("uninstall-all-mods", (event, request: IpcRequest) => { - const utils = UtilsService.getInstance(); +ipc.on("uninstall-all-mods", (args, reply) => { const modsManager = BsModsManagerService.getInstance(); - - modsManager - .uninstallAllMods(request.args) - .then(nbInstalled => { - utils.ipcSend(request.responceChannel, { success: true, data: nbInstalled }); - }) - .catch(err => { - utils.ipcSend(request.responceChannel, { success: false, error: err }); - log.error("ipc", "uninstall-all-mods", err, request); - }); + reply(from(modsManager.uninstallAllMods(args))); }); diff --git a/src/main/ipcs/bs-playlist-ipcs.ts b/src/main/ipcs/bs-playlist-ipcs.ts index 0b58dd85..7ac78860 100644 --- a/src/main/ipcs/bs-playlist-ipcs.ts +++ b/src/main/ipcs/bs-playlist-ipcs.ts @@ -1,48 +1,25 @@ -import { ipcMain } from "electron"; -import { IpcRequest } from "shared/models/ipc"; import { LocalPlaylistsManagerService } from "../services/additional-content/local-playlists-manager.service"; -import { UtilsService } from "../services/utils.service"; import { IpcService } from "../services/ipc.service"; +import { of } from "rxjs"; const ipc = IpcService.getInstance(); -ipc.on("one-click-install-playlist", (req, reply) => { +ipc.on("one-click-install-playlist", (args, reply) => { const mapsManager = LocalPlaylistsManagerService.getInstance(); - reply(mapsManager.oneClickInstallPlaylist(req.args)); + reply(mapsManager.oneClickInstallPlaylist(args)); }); -ipcMain.on("register-playlists-deep-link", async (event, request: IpcRequest) => { +ipc.on("register-playlists-deep-link", (args, reply) => { const maps = LocalPlaylistsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.enableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } + reply(of(maps.enableDeepLinks())); }); -ipcMain.on("unregister-playlists-deep-link", async (event, request: IpcRequest) => { +ipc.on("unregister-playlists-deep-link", (args, reply) => { const maps = LocalPlaylistsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.disableDeepLinks(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } + reply(of(maps.disableDeepLinks())); }); -ipcMain.on("is-playlists-deep-links-enabled", async (event, request: IpcRequest) => { +ipc.on("is-playlists-deep-links-enabled", (args, reply) => { const maps = LocalPlaylistsManagerService.getInstance(); - const utils = UtilsService.getInstance(); - - try { - const res = maps.isDeepLinksEnabled(); - utils.ipcSend(request.responceChannel, { success: true, data: res }); - } catch (e) { - utils.ipcSend(request.responceChannel, { success: false }); - } + reply(of(maps.isDeepLinksEnabled())); }); diff --git a/src/main/ipcs/bs-uninstall-ipcs.ts b/src/main/ipcs/bs-uninstall-ipcs.ts index 9f65dfaa..2922bf24 100644 --- a/src/main/ipcs/bs-uninstall-ipcs.ts +++ b/src/main/ipcs/bs-uninstall-ipcs.ts @@ -1,12 +1,10 @@ -import { BSVersion } from "shared/bs-version.interface"; import { BSLocalVersionService } from "../services/bs-local-version.service"; import { IpcService } from "../services/ipc.service"; import { from } from "rxjs"; const ipc = IpcService.getInstance(); -ipc.on("bs.uninstall", (req, reply) => { +ipc.on("bs.uninstall", (args, reply) => { const bsLocalVersionService = BSLocalVersionService.getInstance(); - - reply(from(bsLocalVersionService.deleteVersion(req.args))); + reply(from(bsLocalVersionService.deleteVersion(args))); }); diff --git a/src/main/ipcs/bs-version-download/bs-download-ipcs.ts b/src/main/ipcs/bs-version-download/bs-download-ipcs.ts index 9ca8405d..d5e081be 100644 --- a/src/main/ipcs/bs-version-download/bs-download-ipcs.ts +++ b/src/main/ipcs/bs-version-download/bs-download-ipcs.ts @@ -1,18 +1,18 @@ import { BsOculusDownloaderService } from "../../services/bs-version-download/bs-oculus-downloader.service"; -import { BsSteamDownloaderService, DownloadInfo, DownloadSteamInfo } from "../../services/bs-version-download/bs-steam-downloader.service"; +import { BsSteamDownloaderService } from "../../services/bs-version-download/bs-steam-downloader.service"; import { InstallationLocationService } from "../../services/installation-location.service"; import { IpcService } from "../../services/ipc.service"; import { from, of } from "rxjs"; -import { BSLocalVersionService, ImportVersionOptions } from "../../services/bs-local-version.service"; +import { BSLocalVersionService } from "../../services/bs-local-version.service"; const ipc = IpcService.getInstance(); -ipc.on("import-version", (req, reply) => { +ipc.on("import-version", (args, reply) => { const versionManager = BSLocalVersionService.getInstance(); - reply(versionManager.importVersion(req.args)); + reply(versionManager.importVersion(args)); }); -// #region Steam +// #region Steam ipc.on("is-dotnet-6-installed", (_, reply) => { const installer = BsSteamDownloaderService.getInstance(); @@ -24,24 +24,24 @@ ipc.on("bs-download.installation-folder", (_, reply) => { reply(from(installLocation.installationDirectory())); }); -ipc.on("bs-download.set-installation-folder", (req, reply) => { +ipc.on("bs-download.set-installation-folder", (args, reply) => { const installerService = InstallationLocationService.getInstance(); - reply(from(installerService.setInstallationDirectory(req.args))); + reply(from(installerService.setInstallationDirectory(args))); }); -ipc.on("auto-download-bs-version", (req, reply) => { +ipc.on("auto-download-bs-version", (args, reply) => { const bsInstaller = BsSteamDownloaderService.getInstance(); - reply(bsInstaller.autoDownloadBsVersion(req.args)); + reply(bsInstaller.autoDownloadBsVersion(args)); }); -ipc.on("download-bs-version", (req, reply) => { +ipc.on("download-bs-version", (args, reply) => { const bsInstaller = BsSteamDownloaderService.getInstance(); - reply(bsInstaller.downloadBsVersion(req.args)) + reply(bsInstaller.downloadBsVersion(args)) }); -ipc.on("download-bs-version-qr", (req, reply) => { +ipc.on("download-bs-version-qr", (args, reply) => { const bsInstaller = BsSteamDownloaderService.getInstance(); - reply(bsInstaller.downloadBsVersionWithQRCode(req.args)) + reply(bsInstaller.downloadBsVersionWithQRCode(args)) }); ipc.on("stop-download-bs-version", (_, reply) => { @@ -49,23 +49,18 @@ ipc.on("stop-download-bs-version", (_, reply) => { reply(of(bsInstaller.stopDownload())); }); -ipc.on("send-input-bs-download", (req, reply) => { +ipc.on("send-input-bs-download", (args, reply) => { const bsInstaller = BsSteamDownloaderService.getInstance(); - reply(of(bsInstaller.sendInput(req.args))); + reply(of(bsInstaller.sendInput(args))); }); // #endregion // #region Oculus -ipc.on("bs-oculus-download", async (req, reply) => { +ipc.on("bs-oculus-download", async (args, reply) => { const oculusDownloader = BsOculusDownloaderService.getInstance(); - reply(oculusDownloader.downloadVersion(req.args)); -}); - -ipc.on("bs-oculus-auto-download", async (req, reply) => { - const oculusDownloader = BsOculusDownloaderService.getInstance(); - reply(oculusDownloader.autoDownloadVersion(req.args)); + reply(oculusDownloader.downloadVersion(args)); }); ipc.on("bs-oculus-stop-download", async (_, reply) => { @@ -73,14 +68,4 @@ ipc.on("bs-oculus-stop-download", async (_, reply) => { reply(of(oculusDownloader.stopDownload())); }); -ipc.on("bs-oculus-has-auth-token", async (_, reply) => { - const oculusDownloader = BsOculusDownloaderService.getInstance(); - reply(from(oculusDownloader.getAuthToken().then(token => !!token))); -}); - -ipc.on("bs-oculus-clear-auth-token", async (_, reply) => { - const oculusDownloader = BsOculusDownloaderService.getInstance(); - reply(from(oculusDownloader.clearAuthToken())); -}); - -// #endregion \ No newline at end of file +// #endregion diff --git a/src/main/ipcs/bs-version-ipcs.ts b/src/main/ipcs/bs-version-ipcs.ts index 0c317096..1e8dde0c 100644 --- a/src/main/ipcs/bs-version-ipcs.ts +++ b/src/main/ipcs/bs-version-ipcs.ts @@ -1,173 +1,69 @@ -import { ipcMain, shell } from "electron"; -import { UtilsService } from "../services/utils.service"; +import { shell } from "electron"; import { BSVersionLibService } from "../services/bs-version-lib.service"; -import { BSVersion } from "shared/bs-version.interface"; -import { IpcRequest } from "shared/models/ipc"; import { BSLocalVersionService } from "../services/bs-local-version.service"; -import { BsmException } from "shared/models/bsm-exception.model"; import { IpcService } from "../services/ipc.service"; import { from } from "rxjs"; import path from "path"; -import { pathExist } from "../helpers/fs.helpers"; -import { FolderLinkerService, LinkOptions } from "../services/folder-linker.service"; -import { LocalMapsManagerService } from "../services/additional-content/local-maps-manager.service"; -import { readJSON, writeJSON } from "fs-extra"; -import log from "electron-log"; -import { VersionLinkerAction } from "renderer/services/version-folder-linker.service"; +import { pathExists } from "fs-extra"; import { VersionFolderLinkerService } from "../services/version-folder-linker.service"; const ipc = IpcService.getInstance(); -ipcMain.on("bs-version.get-version-dict", (_event, req: IpcRequest) => { - BSVersionLibService.getInstance() - .getAvailableVersions() - .then(versions => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: true, data: versions }); - }) - .catch(() => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: false }); - }); +ipc.on("bs-version.get-version-dict", (_, reply) => { + const versionsLib = BSVersionLibService.getInstance(); + reply(from(versionsLib.getAvailableVersions())); }); -ipcMain.on("bs-version.installed-versions", async (_event, req: IpcRequest) => { - BSLocalVersionService.getInstance() - .getInstalledVersions() - .then(versions => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: true, data: versions }); - }) - .catch(() => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: false }); - }); +ipc.on("bs-version.installed-versions", (_, reply) => { + const versions = BSLocalVersionService.getInstance(); + reply(from(versions.getInstalledVersions())); }); -ipcMain.on("bs-version.open-folder", async (_event, req: IpcRequest) => { - const localVersionService = BSLocalVersionService.getInstance(); - const versionFolder = await localVersionService.getVersionPath(req.args); - if (!(await pathExist(versionFolder))) return; - shell.openPath(versionFolder); -}); - -ipcMain.on("bs-version.edit", async (__event, req: IpcRequest<{ version: BSVersion; name: string; color: string }>) => { - BSLocalVersionService.getInstance() - .editVersion(req.args.version, req.args.name, req.args.color) - .then(res => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: !!res, data: res }); - }) - .catch((error: BsmException) => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: false, error }); - }); -}); - -ipcMain.on("bs-version.clone", async (_event, req: IpcRequest<{ version: BSVersion; name: string; color: string }>) => { - BSLocalVersionService.getInstance() - .cloneVersion(req.args.version, req.args.name, req.args.color) - .then(res => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: !!res, data: res }); - }) - .catch((error: BsmException) => { - UtilsService.getInstance().ipcSend(req.responceChannel, { success: false, error }); - }); -}); - -ipc.on("get-version-full-path", async (req: IpcRequest, reply) => { - const localVersions = BSLocalVersionService.getInstance(); - reply(from(localVersions.getVersionPath(req.args))); -}); - -ipc.on("relative-version-path-to-full", async (req: IpcRequest<{ version: BSVersion; relative: string }>, reply) => { - path.isAbsolute(req.args.relative) && reply(from(Promise.resolve(req.args.relative))); - - const localVersions = BSLocalVersionService.getInstance(); - const promise = localVersions - .getVersionPath(req.args.version) - .catch(() => null) - .then(versionPath => { - return path.join(versionPath, req.args.relative); - }); +ipc.on("bs-version.open-folder", (args, reply) => { + const versions = BSLocalVersionService.getInstance(); + const promise = versions.getVersionPath(args).then(versionFolder => { + if(!versionFolder || !pathExists(versionFolder)) return; + shell.openPath(versionFolder); + }) reply(from(promise)); }); -ipc.on("full-version-path-to-relative", async (req: IpcRequest<{ version: BSVersion; fullPath: string }>, reply) => { +ipc.on("bs-version.edit", (args, reply) => { + const versions = BSLocalVersionService.getInstance(); + reply(from(versions.editVersion(args.version, args.name, args.color))); +}); + +ipc.on("bs-version.clone", (args, reply) => { + const versions = BSLocalVersionService.getInstance(); + reply(from(versions.cloneVersion(args.version, args.name, args.color))); +}); + +ipc.on("get-version-full-path", (args, reply) => { const localVersions = BSLocalVersionService.getInstance(); - const promise = localVersions - .getVersionPath(req.args.version) - .catch(() => null) - .then(versionPath => { - return path.relative(versionPath, req.args.fullPath); - }); - reply(from(promise)); + reply(from(localVersions.getVersionPath(args))); }); -ipc.on("get-linked-folders", async (req: IpcRequest<{ version: BSVersion; options?: { relative?: boolean } }>, reply) => { +ipc.on("full-version-path-to-relative", (args, reply) => { + const localVersions = BSLocalVersionService.getInstance(); + reply(from(localVersions.getVersionPath(args.version).then(versionPath => path.relative(versionPath, args.fullPath)))); +}); + +ipc.on("get-linked-folders", (args, reply) => { const versionLinker = VersionFolderLinkerService.getInstance(); - reply(from(versionLinker.getLinkedFolders(req.args.version, req.args.options))); + reply(from(versionLinker.getLinkedFolders(args.version, args.options))); }); -ipc.on("link-folder", async (req: IpcRequest<{ folder: string; options?: LinkOptions }>, reply) => { - req.args.options ??= {}; - - const linker = FolderLinkerService.getInstance(); - - const relativeMapsFolder = path.join(LocalMapsManagerService.LEVELS_ROOT_FOLDER, LocalMapsManagerService.CUSTOM_LEVELS_FOLDER); - - if (req.args.folder.includes(relativeMapsFolder)) { - return reply(from(linker.linkFolder(req.args.folder, { keepContents: req.args.options?.keepContents, intermediateFolder: LocalMapsManagerService.SHARED_MAPS_FOLDER }))); - } - - if (req.args.folder.includes("UserData")) { - req.args.options = { ...req.args.options, backup: true }; - } - - const res = from(linker.linkFolder(req.args.folder, req.args.options)); - - const jsonIPAPath = path.join(req.args.folder, "Beat Saber IPA.json"); - - if (!(await pathExist(jsonIPAPath))) { - return reply(res); - } - - await res.toPromise(); - - try { - const ipaData = (await readJSON(jsonIPAPath)) ?? ({} as any); - ipaData.YeetMods = false; - await writeJSON(jsonIPAPath, ipaData, { spaces: 4 }); - } catch (e) { - log.error("Disable YeetMods", e); - } - - reply(res); -}); - -ipc.on("link-version-folder-action", async (req: IpcRequest, reply) => { +ipc.on("link-version-folder-action", (args, reply) => { const versionLinker = VersionFolderLinkerService.getInstance(); - reply(from(versionLinker.doAction(req.args))); + reply(from(versionLinker.doAction(args))); }); -ipc.on("is-version-folder-linked", async (req: IpcRequest<{ version: BSVersion; relativeFolder: string }>, reply) => { +ipc.on("is-version-folder-linked", (args, reply) => { const versionLinker = VersionFolderLinkerService.getInstance(); - reply(from(versionLinker.isFolderLinked(req.args.version, req.args.relativeFolder))); + reply(from(versionLinker.isFolderLinked(args.version, args.relativeFolder))); }); -ipc.on("unlink-folder", async (req: IpcRequest<{ folder: string; options?: LinkOptions }>, reply) => { - req.args.options ??= {}; - - const linker = FolderLinkerService.getInstance(); - - const relativeMapsFolder = path.join(LocalMapsManagerService.LEVELS_ROOT_FOLDER, LocalMapsManagerService.CUSTOM_LEVELS_FOLDER); - - if (req.args.folder.includes(relativeMapsFolder)) { - return reply(from(linker.unlinkFolder(req.args.folder, { ...req.args.options, intermediateFolder: LocalMapsManagerService.SHARED_MAPS_FOLDER }))); - } - - if (req.args.folder.includes("UserData")) { - req.args.options = { ...req.args.options, backup: true }; - } - - reply(from(linker.unlinkFolder(req.args.folder, req.args.options))); -}); - -ipc.on("relink-all-versions-folders", async (req: IpcRequest, reply) => { +ipc.on("relink-all-versions-folders", (_, reply) => { const versionLinker = VersionFolderLinkerService.getInstance(); reply(from(versionLinker.relinkAllVersionsFolders())); }); diff --git a/src/main/ipcs/launcher-ipcs.ts b/src/main/ipcs/launcher-ipcs.ts index 20473765..02fa1bfb 100644 --- a/src/main/ipcs/launcher-ipcs.ts +++ b/src/main/ipcs/launcher-ipcs.ts @@ -1,20 +1,12 @@ -import { ipcMain } from "electron"; import { AutoUpdaterService } from "../services/auto-updater.service"; -import { IpcRequest } from "shared/models/ipc"; -import { UtilsService } from "../services/utils.service"; import { IpcService } from "../services/ipc.service"; -import { from } from "rxjs"; +import { from, of } from "rxjs"; const ipc = IpcService.getInstance(); -ipcMain.on("download-update", async (event, request: IpcRequest) => { +ipc.on("download-update", (_, reply) => { const updaterService = AutoUpdaterService.getInstance(); - const utilsService = UtilsService.getInstance(); - - updaterService - .downloadUpdate() - .then(res => utilsService.ipcSend(request.responceChannel, { success: res })) - .catch(() => utilsService.ipcSend(request.responceChannel, { success: false })); + reply(from(updaterService.downloadUpdate())); }); ipc.on("check-update", (_, reply) => { @@ -22,7 +14,7 @@ ipc.on("check-update", (_, reply) => { reply(from(updaterService.isUpdateAvailable())); }); -ipcMain.on("install-update", async (event, request: IpcRequest) => { +ipc.on("install-update", (_, reply) => { const updaterService = AutoUpdaterService.getInstance(); - updaterService.quitAndInstall(); + reply(of(updaterService.quitAndInstall())); }); diff --git a/src/main/ipcs/model-saber.ipcs.ts b/src/main/ipcs/model-saber.ipcs.ts index 14023773..fc9f500b 100644 --- a/src/main/ipcs/model-saber.ipcs.ts +++ b/src/main/ipcs/model-saber.ipcs.ts @@ -1,26 +1,15 @@ -import { ipcMain } from "electron"; -import { IpcRequest } from "shared/models/ipc"; import { ModelSaberService } from "../services/thrid-party/model-saber/model-saber.service"; -import { UtilsService } from "../services/utils.service"; import { IpcService } from "../services/ipc.service"; -import { MSGetQuery } from "shared/models/models/model-saber.model"; +import { from } from "rxjs"; const ipc = IpcService.getInstance(); -ipcMain.on("ms-get-model-by-id", async (event, request: IpcRequest) => { - const utils = UtilsService.getInstance(); +ipc.on("ms-get-model-by-id", (args, reply) => { const ms = ModelSaberService.getInstance(); - - ms.getModelById(request.args) - .then(model => { - utils.ipcSend(request.responceChannel, { success: true, data: model }); - }) - .catch(e => { - utils.ipcSend(request.responceChannel, { success: false, error: e }); - }); + reply(from(ms.getModelById(args))); }); -ipc.on("search-models", async (req, reply) => { +ipc.on("search-models", async (args, reply) => { const ms = ModelSaberService.getInstance(); - reply(ms.searchModels(req.args)); + reply(ms.searchModels(args)); }); diff --git a/src/main/ipcs/os-controls-ipcs.ts b/src/main/ipcs/os-controls-ipcs.ts index a5b42525..6d59e706 100644 --- a/src/main/ipcs/os-controls-ipcs.ts +++ b/src/main/ipcs/os-controls-ipcs.ts @@ -1,9 +1,5 @@ -import { ipcMain, shell, dialog, app, BrowserWindow } from "electron"; -import { UtilsService } from "../services/utils.service"; -import { IpcRequest } from "shared/models/ipc"; -import { SystemNotificationOptions } from "shared/models/notification/system-notification.model"; +import { shell, dialog, app, BrowserWindow } from "electron"; import { NotificationService } from "../services/notification.service"; -import { SteamService } from "../services/steam.service"; import { IpcService } from "../services/ipc.service"; import { from, of } from "rxjs"; @@ -11,49 +7,37 @@ import { from, of } from "rxjs"; const ipc = IpcService.getInstance(); -ipcMain.on("new-window", async (event, request: IpcRequest) => { - shell.openExternal(request.args); +ipc.on("new-window", (args, reply) => { + reply(from(shell.openExternal(args))); }); -ipc.on("choose-folder", async (req, reply) => { - reply(from(dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: req.args ?? "" }))); +ipc.on("choose-folder", (args, reply) => { + reply(from(dialog.showOpenDialog({ properties: ["openDirectory"], defaultPath: args ?? "" }))); }); -ipcMain.on("window.progression", async (event, request: IpcRequest) => { - BrowserWindow.fromWebContents(event.sender)?.setProgressBar(request.args / 100); +ipc.on("window.progression",(args, reply, sender) => { + BrowserWindow.fromWebContents(sender)?.setProgressBar(args / 100); + reply(of(undefined)); }); -ipcMain.on("save-file", async (event, request: IpcRequest<{ filename?: string; filters?: Electron.FileFilter[] }>) => { - dialog.showSaveDialog({ properties: ["showOverwriteConfirmation"], defaultPath: request.args.filename, filters: request.args.filters }).then(res => { - const utils = UtilsService.getInstance(); +ipc.on("save-file", (args, reply) => { + reply(from(dialog.showSaveDialog({ properties: ["showOverwriteConfirmation"], defaultPath: args.filename, filters: args.filters }).then(res => { if (res.canceled || !res.filePath) { - utils.ipcSend(request.responceChannel, { success: false }); + throw new Error("No file path selected"); } - UtilsService.getInstance().ipcSend(request.responceChannel, { success: true, data: res.filePath }); - }); + return res.filePath; + }))); }); ipc.on("current-version", (_, reply) => { reply(of(app.getVersion())); }); -ipcMain.on("open-logs", async (event, request: IpcRequest) => { - shell.openPath(app.getPath("logs")); +ipc.on("open-logs", (_, reply) => { + reply(from(shell.openPath(app.getPath("logs")))); }); -ipcMain.on("notify-system", async (event, request: IpcRequest) => { - NotificationService.getInstance().notify(request.args); -}); - -ipcMain.on("open-steam", async (event, request: IpcRequest) => { - const steam = SteamService.getInstance(); - const utils = UtilsService.getInstance(); - steam - .openSteam() - .then(res => { - utils.ipcSend(request.responceChannel, { success: true, data: res }); - }) - .catch(e => { - utils.ipcSend(request.responceChannel, { success: false, error: e }); - }); +ipc.on("notify-system", (args, reply) => { + const systemNotification = NotificationService.getInstance(); + reply(of(systemNotification.notify(args))); }); diff --git a/src/main/ipcs/supporters-ipcs.ts b/src/main/ipcs/supporters-ipcs.ts index 1a97f2bd..ad124006 100644 --- a/src/main/ipcs/supporters-ipcs.ts +++ b/src/main/ipcs/supporters-ipcs.ts @@ -1,18 +1,10 @@ -import { ipcMain } from "electron"; import { SupportersService } from "../services/supporters.service"; -import { IpcRequest } from "shared/models/ipc"; -import { UtilsService } from "../services/utils.service"; +import { IpcService } from "../services/ipc.service"; +import { from } from "rxjs"; -ipcMain.on("get-supporters", (event, request: IpcRequest) => { - const utils = UtilsService.getInstance(); +const ipc = IpcService.getInstance(); + +ipc.on("get-supporters", (_, reply) => { const supportersService = SupportersService.getInstance(); - - supportersService - .getSupporters() - .then(supporters => { - utils.ipcSend(request.responceChannel, { success: true, data: supporters }); - }) - .catch(() => { - utils.ipcSend(request.responceChannel, { success: false }); - }); + reply(from(supportersService.getSupporters())); }); diff --git a/src/main/ipcs/window-manager-ipcs.ts b/src/main/ipcs/window-manager-ipcs.ts index 94b54e6e..bdf96a61 100644 --- a/src/main/ipcs/window-manager-ipcs.ts +++ b/src/main/ipcs/window-manager-ipcs.ts @@ -1,40 +1,39 @@ import { WindowManagerService } from "../services/window-manager.service"; -import { AppWindow } from "shared/models/window-manager/app-window.model"; import { IpcService } from "../services/ipc.service"; -import { from } from "rxjs"; -import { BrowserWindow, ipcMain } from "electron"; +import { from, of } from "rxjs"; +import { BrowserWindow } from "electron"; const ipc = IpcService.getInstance(); // Native windows control, do not pass through IPC service -ipcMain.on("close-window", async (event) => { - BrowserWindow.fromWebContents(event.sender)?.close(); +ipc.on("close-window", (_, reply, sender) => { + reply(of(BrowserWindow.fromWebContents(sender)?.close())); }); -ipcMain.on("maximise-window", async (event) => { - BrowserWindow.fromWebContents(event.sender)?.maximize(); +ipc.on("maximise-window", (_, reply, sender) => { + reply(of(BrowserWindow.fromWebContents(sender)?.maximize())); }); -ipcMain.on("minimise-window", async (event) => { - BrowserWindow.fromWebContents(event.sender)?.minimize(); +ipc.on("minimise-window", (_, reply, sender) => { + reply(of(BrowserWindow.fromWebContents(sender)?.minimize())); }); -ipcMain.on("unmaximise-window", async (event) => { - BrowserWindow.fromWebContents(event.sender)?.unmaximize(); +ipc.on("unmaximise-window", (_, reply, sender) => { + reply(of(BrowserWindow.fromWebContents(sender)?.unmaximize())); }); -ipc.on("open-window-then-close-all", (req, reply) => { +ipc.on("open-window-then-close-all", (args, reply) => { const windowManager = WindowManagerService.getInstance(); - const res = windowManager.openWindow(req.args).then(() => { - windowManager.closeAllWindows(req.args); + const res = windowManager.openWindow(args).then(() => { + windowManager.closeAllWindows(args); }); reply(from(res)); }); -ipc.on("open-window-or-focus", (req, reply) => { +ipc.on("open-window-or-focus", (args, reply) => { const windowManager = WindowManagerService.getInstance(); - reply(from(windowManager.openWindowOrFocus(req.args))); + reply(from(windowManager.openWindowOrFocus(args))); }); diff --git a/src/main/main.ts b/src/main/main.ts index 6cf82c74..5a7339fc 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -90,11 +90,11 @@ if (!gotTheLock) { }) app.whenReady().then(() => { - + app.setAppUserModelId(APP_NAME); initServicesMustBeInitialized(); - + const deepLink = process.argv.find(arg => DeepLinkService.getInstance().isDeepLink(arg)); if (!deepLink) { @@ -102,13 +102,13 @@ if (!gotTheLock) { } else { DeepLinkService.getInstance().dispatchLinkOpened(deepLink); } - + SteamLauncherService.getInstance().restoreSteamVR(); - + // Log renderer errors ipcMain.on("log-error", (_, args: IpcRequest) => { log.error(args?.args); }); - + }).catch(log.error); } diff --git a/src/main/preload.ts b/src/main/preload.ts index ca0f53b1..61ced3c1 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -26,12 +26,5 @@ contextBridge.exposeInMainWorld("electron", { join: (...args: string[]): string => { return args.join(sep); } - }, - window: { - close: () => { ipcRenderer.send("close-window"); }, - minimise: () => { ipcRenderer.send("minimise-window"); }, - maximise: () => { ipcRenderer.send("maximise-window"); }, - unmaximise: () => { ipcRenderer.send("unmaximise-window"); }, } - -}); \ No newline at end of file +}); diff --git a/src/main/services/additional-content/local-maps-manager.service.ts b/src/main/services/additional-content/local-maps-manager.service.ts index b30349aa..4fd058af 100644 --- a/src/main/services/additional-content/local-maps-manager.service.ts +++ b/src/main/services/additional-content/local-maps-manager.service.ts @@ -14,14 +14,13 @@ import sanitize from "sanitize-filename"; import { DeepLinkService } from "../deep-link.service"; import log from "electron-log"; import { WindowManagerService } from "../window-manager.service"; -import { Observable, lastValueFrom, of } from "rxjs"; +import { Observable, lastValueFrom } from "rxjs"; import { Archive } from "../../models/archive.class"; -import { deleteFolder, ensureFolderExist, getFilesInFolder, getFoldersInFolder, pathExist } from "../../helpers/fs.helpers"; +import { Progression, deleteFolder, ensureFolderExist, getFilesInFolder, getFoldersInFolder, pathExist } from "../../helpers/fs.helpers"; import { readFile } from "fs/promises"; import { FolderLinkerService } from "../folder-linker.service"; import { allSettled } from "../../../shared/helpers/promise.helpers"; import { splitIntoChunk } from "../../../shared/helpers/array.helpers"; -import { IpcService } from "../ipc.service"; export class LocalMapsManagerService { private static instance: LocalMapsManagerService; @@ -48,7 +47,6 @@ export class LocalMapsManagerService { private readonly reqService: RequestService; private readonly deepLink: DeepLinkService; private readonly windows: WindowManagerService; - private readonly ipc: IpcService; private readonly linker = FolderLinkerService.getInstance(); private constructor() { @@ -59,16 +57,19 @@ export class LocalMapsManagerService { this.deepLink = DeepLinkService.getInstance(); this.windows = WindowManagerService.getInstance(); this.linker = FolderLinkerService.getInstance(); - this.ipc = IpcService.getInstance(); + + const handleOneClick = (mapId: string, isHash = false) => { + this.windows.openWindow(`oneclick-download-map.html?mapId=${mapId}&isHash=${isHash}`); + } this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.BeatSaver, link => { log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link); - this.openOneClickDownloadMapWindow(new URL(link).host); + handleOneClick(new URL(link).host); }); this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.ScoreSaber, link => { log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.ScoreSaber, link); - this.openOneClickDownloadMapWindow(new URL(link).host, true); + handleOneClick(new URL(link).host, true); }); } @@ -87,7 +88,7 @@ export class LocalMapsManagerService { const mapRawInfo: RawMapInfoData = JSON.parse(rawInfoString); const shasum = crypto.createHash("sha1"); shasum.update(rawInfoString); - + const hashFile = (filePath: string): Promise => { return new Promise((resolve, reject) => { const stream = createReadStream(filePath); @@ -103,7 +104,7 @@ export class LocalMapsManagerService { await hashFile(diffFilePath); } } - + return shasum.digest("hex"); } @@ -138,18 +139,6 @@ export class LocalMapsManagerService { return { zip, zipPath }; } - private openOneClickDownloadMapWindow(mapId: string, isHash = false): void { - this.windows.openWindow("oneclick-download-map.html").then(window => { - - this.ipc.once("one-click-map-info", async (_, reply) => { - reply(of({ id: mapId, isHash })); - }, window.webContents.ipc); - - }); - - - } - public getMaps(version?: BSVersion): Observable { const progression: BsmLocalMapsProgress = { total: 0, @@ -261,7 +250,7 @@ export class LocalMapsManagerService { if(!exists){ return null; } return this.loadMapInfoFromPath(mapPath); }).catch(() => null); - + if(map.versions.every(version => version.hash === installedMap?.hash)) { return installedMap; } @@ -284,7 +273,7 @@ export class LocalMapsManagerService { return localMap; } - public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string) { + public async exportMaps(version: BSVersion, maps: BsmLocalMap[], outPath: string): Promise> { const archive = new Archive(outPath); if (!maps || maps.length === 0) { diff --git a/src/main/services/additional-content/local-models-manager.service.ts b/src/main/services/additional-content/local-models-manager.service.ts index 7365f28f..2513482f 100644 --- a/src/main/services/additional-content/local-models-manager.service.ts +++ b/src/main/services/additional-content/local-models-manager.service.ts @@ -11,14 +11,13 @@ import sanitize from "sanitize-filename"; import { Progression, ensureFolderExist, unlinkPath } from "../../helpers/fs.helpers"; import { MODEL_FILE_EXTENSIONS, MODEL_TYPES, MODEL_TYPE_FOLDERS } from "../../../shared/models/models/constants"; import { InstallationLocationService } from "../installation-location.service"; -import { Observable, Subscription, lastValueFrom, of } from "rxjs"; +import { Observable, Subscription, lastValueFrom } from "rxjs"; import { readdir } from "fs/promises"; import md5File from "md5-file"; import { allSettled } from "../../../shared/helpers/promise.helpers"; import { ModelSaberService } from "../thrid-party/model-saber/model-saber.service"; import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface"; import { Archive } from "../../models/archive.class"; -import { IpcService } from "../ipc.service"; export class LocalModelsManagerService { private static instance: LocalModelsManagerService; @@ -40,7 +39,6 @@ export class LocalModelsManagerService { private readonly installPaths: InstallationLocationService; private readonly request: RequestService; private readonly modelSaber: ModelSaberService; - private readonly ipc: IpcService; private constructor() { this.deepLink = DeepLinkService.getInstance(); @@ -49,26 +47,14 @@ export class LocalModelsManagerService { this.request = RequestService.getInstance(); this.installPaths = InstallationLocationService.getInstance(); this.modelSaber = ModelSaberService.getInstance(); - this.ipc = IpcService.getInstance(); this.deepLink.addLinkOpenedListener(this.DEEP_LINKS.ModelSaber, link => { log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.ModelSaber, link); - const url = new URL(link); - const type = url.host; + const url = new URL(link); const id = url.pathname.replace("/", "").split("/").at(0); - this.openOneClickDownloadModelWindow(id, type); - }); - } - - private openOneClickDownloadModelWindow(id: string, type: string) { - this.windows.openWindow("oneclick-download-model.html").then(window => { - - this.ipc.once("one-click-model-info", (_, reply) => { - reply(of({ id, type })); - }, window.webContents.ipc); - + this.windows.openWindow(`oneclick-download-model.html?modelId=${id}`); }); } diff --git a/src/main/services/additional-content/local-playlists-manager.service.ts b/src/main/services/additional-content/local-playlists-manager.service.ts index 22881e54..f1281969 100644 --- a/src/main/services/additional-content/local-playlists-manager.service.ts +++ b/src/main/services/additional-content/local-playlists-manager.service.ts @@ -50,7 +50,7 @@ export class LocalPlaylistsManagerService { log.info("DEEP-LINK RECEIVED FROM", this.DEEP_LINKS.BeatSaver, link); const url = new URL(link); const bplistUrl = url.host === "playlist" ? url.pathname.replace("/", "") : ""; - this.openOneClickDownloadPlaylistWindow(bplistUrl); + this.windows.openWindow(`oneclick-download-playlist.html?playlistUrl=${bplistUrl}`); }); } @@ -79,7 +79,7 @@ export class LocalPlaylistsManagerService { } return lastValueFrom(this.request.downloadFile(bslistSource, destFile)).then(res => res.data); } - + private async readPlaylistFile(path: string): Promise { if (!(await pathExist(path))) { @@ -91,10 +91,6 @@ export class LocalPlaylistsManagerService { return JSON.parse(rawContent); } - private openOneClickDownloadPlaylistWindow(downloadUrl: string): void { - this.windows.openWindow(`oneclick-download-playlist.html?playlistUrl=${downloadUrl}`); - } - public downloadPlaylist(bpListUrl: string, version: BSVersion): Observable> { return new Observable>(obs => { @@ -102,8 +98,8 @@ export class LocalPlaylistsManagerService { const bpListFilePath = await this.installBPListFile(bpListUrl, version); const bpList = await this.readPlaylistFile(bpListFilePath); - - const progress: Progression = { + + const progress: Progression = { total: bpList.songs.length, current: 0, data: { diff --git a/src/main/services/bs-launcher/bs-launcher.service.ts b/src/main/services/bs-launcher/bs-launcher.service.ts index e4441948..0917cf57 100644 --- a/src/main/services/bs-launcher/bs-launcher.service.ts +++ b/src/main/services/bs-launcher/bs-launcher.service.ts @@ -128,7 +128,7 @@ export class BSLauncherService { } private createShortcutPngBuffer(color: Color): Promise{ - + const svgBuffer = Buffer.from(` @@ -141,8 +141,8 @@ export class BSLauncherService { /** * Create .png file for the shortcut with the given color - * @param {Color} color - * @returns {Promise} Path of the icon + * @param {Color} color + * @returns {Promise} Path of the icon */ private async createShortcutPng(color: Color): Promise{ const pngBuffer = this.createShortcutPngBuffer(color); @@ -211,25 +211,25 @@ export class BSLauncherService { const bsPath: string = await (async () => { const bsPath = await this.localVersionService.getInstalledVersionPath(launchOption.version); return bsPath ?? this.localVersionService.getVersionPath(launchOption.version); - })().catch(e => { - log.error(e); + })().catch(e => { + log.error(e); return null; }); launchOption.version = (await this.localVersionService.getVersionOfBSFolder(bsPath, { steam: launchOption.version.steam, - oculus: launchOption.version.oculus, + oculus: launchOption.version.oculus, })) ?? launchOption.version; launchOption.version = {...(await this.remoteVersion.getVersionDetails(launchOption.version.BSVersion)), ...launchOption.version}; - - this.ipc.once("shortcut-launch-options", (_data, reply) => { + + this.ipc.once("shortcut-launch-options", (_, reply) => { reply(of(launchOption)); }); this.windows.openWindow("shortcut-launch.html"); } - + } type ShortcutParams = { @@ -246,9 +246,9 @@ type ShortcutParams = { /** * Create .desktop file for url shortcut (only for linux) - * @param {string} shortcutPath - * @param options - * @returns + * @param {string} shortcutPath + * @param options + * @returns */ function createDesktopUrlShortcut(shortcutPath: string, options?: { url: string diff --git a/src/main/services/bs-version-download/bs-oculus-downloader.service.ts b/src/main/services/bs-version-download/bs-oculus-downloader.service.ts index 21820526..dda1949d 100644 --- a/src/main/services/bs-version-download/bs-oculus-downloader.service.ts +++ b/src/main/services/bs-version-download/bs-oculus-downloader.service.ts @@ -1,13 +1,9 @@ import { BSVersion } from "../../../shared/bs-version.interface"; -import { WindowManagerService } from "../window-manager.service"; -import { minToMs, msToS } from "../../../shared/helpers/time.helpers"; import log from "electron-log"; -import { CustomError } from "../../../shared/models/exceptions/custom-error.class"; import { OculusDownloader } from "../../models/oculus-downloader.class"; -import { Cookie, session } from "electron"; import { Progression, ensurePathNotAlreadyExist } from "../../helpers/fs.helpers"; import { BSLocalVersionService } from "../bs-local-version.service"; -import { Observable, finalize, from, map, of, switchMap } from "rxjs"; +import { Observable, finalize, map, of, switchMap } from "rxjs"; import path from "path"; import { DownloadInfo } from "./bs-steam-downloader.service"; import { BsStore } from "../../../shared/models/bs-store.enum"; @@ -26,90 +22,19 @@ export class BsOculusDownloaderService { } private readonly oculusDownloader: OculusDownloader; - - private readonly windows: WindowManagerService; private readonly versions: BSLocalVersionService; private constructor() { - this.windows = WindowManagerService.getInstance(); this.versions = BSLocalVersionService.getInstance(); this.oculusDownloader = new OculusDownloader(); } - private isUserTokenValid(token: string): boolean{ - return isOculusTokenValid(token, log.info); - } - - private isCookieValid(cookie: Cookie): boolean { - - if(!cookie){ - return false; - } - - return cookie.expirationDate > msToS(Date.now()); - } - - public async getAuthToken(): Promise { - const cookie = await session.defaultSession.cookies.get({ name: "oc_www_at" }).then(a => a?.at(0)); - - if(this.isCookieValid(cookie) && this.isUserTokenValid(cookie.value)){ - return cookie.value; - } - - return undefined; - } - - private async getUserTokenFromMetaAuth(keepToken: boolean): Promise{ - - const redirectUrl = "https://developer.oculus.com/manage/"; - const loginUrl = `https://auth.oculus.com/login/?redirect_uri=${encodeURIComponent(redirectUrl)}`; - const window = await this.windows.openWindow(loginUrl, { frame: true, width: 650, height: 800 }); - - let timout: NodeJS.Timeout; - - const promise = new Promise((resolve, reject) => { - timout = setTimeout(() => { - reject(new CustomError("Trying to get Oculus user token timed out", "META_LOGIN_TIMED_OUT")); - window.close(); - }, minToMs(5)); - - window.webContents.on("did-navigate", async (_, url) => { - if(!url.startsWith(redirectUrl)){ return; } - - const token = (await window.webContents.session.cookies.get({ name: "oc_www_at" })).at(0)?.value; - - if(!this.isUserTokenValid(token)){ - return; - } - - resolve(token); - }); - - window.on("closed", () => { - reject(new CustomError("Oculus login window closed by user", "META_LOGIN_WINDOW_CLOSED_BY_USER")); - }); - }).finally(() => { - - clearTimeout(timout); - - if(!keepToken){ - this.clearAuthToken(); - } - - if(!window.isDestroyed() && window.isClosable()){ - window.close(); - } - }); - - return promise; - } - private async createDownloadVersion(version: BSVersion): Promise<{version: BSVersion, dest: string}>{ const dest = await ensurePathNotAlreadyExist(await this.versions.getVersionPath(version)); return { version: { - ...version, + ...version, ...(path.basename(dest) !== version.BSVersion && { name: path.basename(dest) }), metadata: { store: BsStore.OCULUS, id: "" } }, @@ -125,9 +50,7 @@ export class BsOculusDownloaderService { let downloadVersion: BSVersion - const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getUserTokenFromMetaAuth(downloadInfo.stay)); - - return tokenObs$.pipe( + return of(downloadInfo.token).pipe( switchMap(token => { isOculusTokenValid(token, log.info); // Log token validity if(!downloadInfo.isVerification){ @@ -138,7 +61,7 @@ export class BsOculusDownloaderService { switchMap(({token, version, dest}) => { downloadVersion = version; return this.oculusDownloader.downloadApp({ accessToken: token, binaryId: version.OculusBinaryId, destination: dest }).pipe(map( - progress => ({...progress, data: version}) + progress => ({...progress, data: version}) )); }), finalize(() => downloadVersion && this.versions.initVersionMetadata(downloadVersion, { store: BsStore.OCULUS })), @@ -146,43 +69,9 @@ export class BsOculusDownloaderService { ); } - public autoDownloadVersion(downloadInfo: DownloadInfo): Observable>{ - - let downloadVersion: BSVersion - - const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getAuthToken()); - - return tokenObs$.pipe( - map(token => { - if(!token){ - throw new CustomError("No Meta auth token was found in cookies for auto download", "NO_META_AUTH_TOKEN"); - } - return token; - }), - switchMap(token => { - if(!downloadInfo.isVerification){ - return this.createDownloadVersion(downloadInfo.bsVersion).then(({version, dest}) => ({token, version, dest})); - } - return this.versions.getVersionPath(downloadInfo.bsVersion).then(path => ({token, version: downloadInfo.bsVersion, dest: path})); - }), - switchMap(({token, version, dest}) => { - downloadVersion = version; - return this.oculusDownloader.downloadApp({ accessToken: token, binaryId: version.OculusBinaryId, destination: dest }).pipe( - map(progress => ({...progress, data: version})), - ); - }), - finalize(() => downloadVersion && this.versions.initVersionMetadata(downloadVersion, { store: BsStore.OCULUS })), - finalize(() => this.oculusDownloader.stopDownload()), - ); - } - - public clearAuthToken(): Promise{ - return session.defaultSession.clearStorageData({ storages: ["cookies"], origin: ".oculus.com" }) - } - } export interface OculusDownloadInfo { version: BSVersion; stay?: boolean; -} \ No newline at end of file +} diff --git a/src/main/services/ipc.service.ts b/src/main/services/ipc.service.ts index cd1f8f50..786be0f7 100644 --- a/src/main/services/ipc.service.ts +++ b/src/main/services/ipc.service.ts @@ -1,10 +1,11 @@ import { IpcRequest } from "shared/models/ipc"; -import { BrowserWindow, ipcMain } from "electron"; +import { BrowserWindow, IpcMainEvent, WebContents, ipcMain } from "electron"; import { Observable } from "rxjs"; import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface"; import { IpcReplier } from "shared/models/ipc/ipc-request.interface"; import { serializeError } from 'serialize-error'; import log from "electron-log"; +import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes"; export class IpcService { private static instance: IpcService; @@ -30,11 +31,11 @@ export class IpcService { return `${channel}_teardown`; } - private buildProxyListener(listener: IpcListener) { - return (event: Electron.IpcMainEvent, req: IpcRequest) => { + private buildProxyListener(listener: IpcListenerFromChannel) { + return (event: IpcMainEvent, req: IpcRequest>) => { const window = BrowserWindow.fromWebContents(event.sender); const replier = (data: Observable) => this.connectStream(req.responceChannel, window, data); - listener(req, replier); + listener(req.args, replier, event.sender); }; } @@ -54,21 +55,26 @@ export class IpcService { complete: () => this.send(this.getCompleteChannel(channel), window) }) - window.webContents.once("destroyed", () => sub.unsubscribe()); - window.webContents.ipc.once(this.getTearDownChannel(channel), () => sub.unsubscribe()); + const unsubscribe = () => sub.unsubscribe(); + + window.webContents.once("destroyed", unsubscribe); + window.webContents.ipc.once(this.getTearDownChannel(channel), unsubscribe); sub.add(() => { window.webContents.ipc.removeAllListeners(this.getTearDownChannel(channel)); + window.webContents.removeListener("destroyed", unsubscribe); }); } - public on(channel: string, listener: IpcListener, ipc = ipcMain): void { - ipc.on(channel, this.buildProxyListener(listener)); + public on(channel: C, listener: IpcListenerFromChannel, ipc = ipcMain): void { + ipc.on(channel as string, this.buildProxyListener(listener)); } - public once(channel: string, listener: IpcListener, ipc = ipcMain): void { - ipc.once(channel, this.buildProxyListener(listener)); + public once(channel: C, listener: IpcListenerFromChannel, ipc = ipcMain): void { + ipc.once(channel as string, this.buildProxyListener(listener)); } } -type IpcListener = (req: IpcRequest, replier: IpcReplier) => void | Promise; + +type IpcListener = (req: TRequest, replier: IpcReplier, webContents: WebContents) => void | Promise; +type IpcListenerFromChannel = IpcListener, IpcResponseType>; diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index 42b5add8..fb336d33 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -246,7 +246,9 @@ export class BsModsManagerService { })) : extracted; - res && this.nbInstalledMods++; + if(res){ + this.nbInstalledMods++; + } return res; } diff --git a/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx b/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx index c04865d7..c8ec69ce 100644 --- a/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx @@ -12,6 +12,7 @@ import { ConfigurationService } from "renderer/services/configuration.service"; import { IpcService } from "renderer/services/ipc.service"; import { ModalComponent } from "renderer/services/modale.service"; import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionType } from "renderer/services/version-folder-linker.service"; +import { lastValueFrom } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; export const ShareFoldersModal: ModalComponent = ({ data }) => { @@ -45,14 +46,14 @@ export const ShareFoldersModal: ModalComponent = ({ data }) => }, [folders]); const addFolder = async () => { - const versionPath = await versionManager.getVersionPath(data).toPromise(); - const folder = await ipc.sendV2<{ canceled: boolean; filePaths: string[] }, string>("choose-folder", { args: versionPath }).toPromise(); + const versionPath = await lastValueFrom(versionManager.getVersionPath(data)); + const folder = await lastValueFrom(ipc.sendV2("choose-folder", versionPath)); if (!folder || folder.canceled || !folder.filePaths?.length) { return; } - const relativeFolder = await ipc.sendV2("full-version-path-to-relative", { args: { version: data, fullPath: folder.filePaths[0] } }).toPromise(); + const relativeFolder = await lastValueFrom(ipc.sendV2("full-version-path-to-relative", { version: data, fullPath: folder.filePaths[0] })); if (folders.includes(relativeFolder)) { return; @@ -137,7 +138,7 @@ const FolderItem = ({ version, relativeFolder, onDelete }: FolderProps) => {
- audio.volume$, audio.volume); const color = useThemeColor("first-color"); @@ -22,7 +24,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin const [previewVersion, setPreviewVersion] = useState(null); useEffect(() => { - lastValueFrom(ipcService.sendV2("current-version")).then(version => { + lastValueFrom(ipcService.sendV2("current-version")).then(version => { if (version.toLocaleLowerCase().includes("alpha")) { return setPreviewVersion("ALPHA"); } @@ -35,19 +37,19 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin const [maximized, setMaximized] = useState(false); const closeWindow = () => { - return window.electron.window.close(); + return windowControls.close(); }; const maximizeWindow = () => { - window.electron.window.maximise(); + windowControls.maximise(); }; const minimizeWindow = () => { - window.electron.window.minimise(); + windowControls.minimise(); }; const resetWindow = () => { - window.electron.window.unmaximise(); + windowControls.unmaximise(); }; const toogleMaximize = () => { @@ -117,7 +119,7 @@ export default function TitleBar({ template = "index.html" }: { template: AppWin ); } - + return (
diff --git a/src/renderer/hooks/use-window-args.hook.ts b/src/renderer/hooks/use-window-args.hook.ts new file mode 100644 index 00000000..adb3b073 --- /dev/null +++ b/src/renderer/hooks/use-window-args.hook.ts @@ -0,0 +1,16 @@ +import { useConstant } from "./use-constant.hook"; + +export function useWindowArgs(...keys: Key[]): Record { + + const getArgs = (...keys: Key[]) => { + const url = new URLSearchParams(window.location.search); + const result = {} as Record; + keys.forEach(key => { + result[key] = url.get(key) || undefined; + }); + + return result; + } + + return useConstant(() => getArgs(...keys)); +} diff --git a/src/renderer/hooks/use-window-controls.hook.ts b/src/renderer/hooks/use-window-controls.hook.ts new file mode 100644 index 00000000..841ef56d --- /dev/null +++ b/src/renderer/hooks/use-window-controls.hook.ts @@ -0,0 +1,17 @@ +import { IpcService } from "renderer/services/ipc.service"; +import { useService } from "./use-service.hook"; +import { useConstant } from "./use-constant.hook"; +import { lastValueFrom } from "rxjs"; + +export function useWindowControls() { + const ipc = useService(IpcService); + + const { close, maximise, minimise, unmaximise } = useConstant(() => ({ + close: () => lastValueFrom(ipc.sendV2("close-window")), + maximise: () => lastValueFrom(ipc.sendV2("maximise-window")), + minimise: () => lastValueFrom(ipc.sendV2("minimise-window")), + unmaximise: () => lastValueFrom(ipc.sendV2("unmaximise-window")) + })); + + return { close, maximise, minimise, unmaximise }; +} diff --git a/src/renderer/pages/settings-page.component.tsx b/src/renderer/pages/settings-page.component.tsx index 5ca7155b..1b549c9c 100644 --- a/src/renderer/pages/settings-page.component.tsx +++ b/src/renderer/pages/settings-page.component.tsx @@ -35,7 +35,6 @@ import { useService } from "renderer/hooks/use-service.hook"; import { lastValueFrom } from "rxjs"; import { BsmException } from "shared/models/bsm-exception.model"; import { useObservable } from "renderer/hooks/use-observable.hook"; -import { OculusDownloaderService } from "renderer/services/bs-version-download/oculus-downloader.service"; import { BsStore } from "shared/models/bs-store.enum"; import { SteamIcon } from "renderer/components/svgs/icons/steam-icon.component"; import { OculusIcon } from "renderer/components/svgs/icons/oculus-icon.component"; @@ -52,7 +51,6 @@ export function SettingsPage() { const modalService = useService(ModalService); const bsDownloader = useService(BsDownloaderService); const steamDownloader = useService(SteamDownloaderService); - const oculusDownloader = useService(OculusDownloaderService); const progressBarService = useService(ProgressBarService); const notificationService = useService(NotificationService); const i18nService = useService(I18nService); @@ -91,7 +89,7 @@ export function SettingsPage() { const [playlistsDeepLinkEnabled, setPlaylistsDeepLinkEnabled] = useState(false); const [modelsDeepLinkEnabled, setModelsDeepLinkEnabled] = useState(false); const [hasDownloaderSession, setHasDownloaderSession] = useState(false); - const appVersion = useObservable(() => ipcService.sendV2("current-version")); + const appVersion = useObservable(() => ipcService.sendV2("current-version")); const [isChangelogAvailable, setIsChangelogAvailable] = useState(true); const [changlogsLoading, setChanglogsLoading] = useState(false); @@ -116,16 +114,11 @@ export function SettingsPage() { }; const loadDownloadersSession = () => { - if(steamDownloader.sessionExist()){ return setHasDownloaderSession(true); } - - oculusDownloader.hasAuthToken().then(hasToken => { - setHasDownloaderSession(hasToken); - }); + setHasDownloaderSession(steamDownloader.sessionExist()); } const clearDownloadersSession = () => { steamDownloader.deleteSteamSession(); - oculusDownloader.clearAuthToken(); loadDownloadersSession(); } @@ -171,7 +164,7 @@ export function SettingsPage() { return; } - const fileChooserRes = await ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder").toPromise(); + const fileChooserRes = await lastValueFrom(ipcService.sendV2("choose-folder")); if (!fileChooserRes.canceled && fileChooserRes.filePaths?.length) { progressBarService.showFake(0.008); @@ -217,7 +210,7 @@ export function SettingsPage() { const openDiscord = () => linkOpener.open("https://discord.gg/uSqbHVpKdV"); const openTwitter = () => linkOpener.open("https://twitter.com/BSManager_"); - const openLogs = () => ipcService.sendLazy("open-logs"); + const openLogs = () => lastValueFrom(ipcService.sendV2("open-logs")); const showDeepLinkError = (isDeactivation: boolean) => { const desc = isDeactivation ? "notifications.settings.additional-content.deep-link.deactivation.error.description" : "notifications.settings.additional-content.deep-link.activation.error.description"; @@ -231,8 +224,10 @@ export function SettingsPage() { }; const switchDeepLink = async (manager: MapsManagerService | PlaylistsManagerService | ModelsManagerService, enable: boolean, showNotification: boolean, setter: Dispatch>) => { - const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink()); - showNotification && (res ? showDeepLinkSuccess(!enable) : showDeepLinkError(!enable)); + const res = await (enable ? manager.enableDeepLink() : manager.disableDeepLink()).then(() => true).catch(() => false); + if(showNotification){ + res ? showDeepLinkSuccess(enable) : showDeepLinkError(enable); + } const isEnable = await manager.isDeepLinksEnabled(); setter(() => isEnable); return res; diff --git a/src/renderer/pages/version-viewer.component.tsx b/src/renderer/pages/version-viewer.component.tsx index 2b3f1cf8..047050d5 100644 --- a/src/renderer/pages/version-viewer.component.tsx +++ b/src/renderer/pages/version-viewer.component.tsx @@ -42,7 +42,7 @@ export function VersionViewer() { } navigate(`/bs-version/${version.BSVersion}`, { state: version }); }; - const openFolder = () => ipcService.sendLazy("bs-version.open-folder", { args: state }); + const openFolder = () => lastValueFrom(ipcService.sendV2("bs-version.open-folder", state)); const verifyFiles = () => bsDownloader.verifyBsVersion(state); const uninstall = async () => { diff --git a/src/renderer/preload.d.ts b/src/renderer/preload.d.ts index 93ad048c..ab023814 100644 --- a/src/renderer/preload.d.ts +++ b/src/renderer/preload.d.ts @@ -11,12 +11,6 @@ declare global { sep: "/"|"\\"; join: (...args: string[]) => string; }; - window: { - close: () => void; - minimise: () => void; - maximise: () => void; - unmaximise: () => void; - }; }; } } diff --git a/src/renderer/services/auto-updater.service.ts b/src/renderer/services/auto-updater.service.ts index d4de5b2e..d88d90c9 100644 --- a/src/renderer/services/auto-updater.service.ts +++ b/src/renderer/services/auto-updater.service.ts @@ -47,20 +47,17 @@ export class AutoUpdaterService { } public isUpdateAvailable(): Promise { - return lastValueFrom(this.ipcService.sendV2("check-update")).catch(() => false); + return lastValueFrom(this.ipcService.sendV2("check-update")).catch(() => false); } public downloadUpdate(): Promise { - const promise = this.ipcService.send("download-update").then(res => { - return res.success; - }); - + const promise = lastValueFrom(this.ipcService.sendV2("download-update")).then(() => true).catch(() => false); this.progressService.show(this.downloadProgress$, true); return promise; } public quitAndInstall() { - this.ipcService.sendLazy("install-update"); + lastValueFrom(this.ipcService.sendV2("install-update")); } public getLastAppVersion(): string { @@ -103,7 +100,7 @@ export class AutoUpdaterService { } public getAppVersion() : Observable { - return this.ipcService.sendV2("current-version"); + return this.ipcService.sendV2("current-version"); } public async showChangelog(version:string): Promise{ diff --git a/src/renderer/services/bs-launcher.service.ts b/src/renderer/services/bs-launcher.service.ts index d47e1d18..8bc89ec8 100644 --- a/src/renderer/services/bs-launcher.service.ts +++ b/src/renderer/services/bs-launcher.service.ts @@ -73,7 +73,7 @@ export class BSLauncherService { } private async doMustStartAsAdmin(): Promise { - const needAdmin = await lastValueFrom(this.ipcService.sendV2("bs-launch.need-start-as-admin")); + const needAdmin = await lastValueFrom(this.ipcService.sendV2("bs-launch.need-start-as-admin")); if(!needAdmin){ return false; } if(this.config.get("dont-remind-admin")){ return true; } const modalRes = await this.modals.openModal(NeedLaunchAdminModal); @@ -83,7 +83,7 @@ export class BSLauncherService { } public doLaunch(launchOptions: LaunchOption): Observable{ - return this.ipcService.sendV2("bs-launch.launch", {args: launchOptions}); + return this.ipcService.sendV2("bs-launch.launch", launchOptions); } public launch(launchOptions: LaunchOption): Observable { @@ -114,13 +114,13 @@ export class BSLauncherService { } - public createLaunchShortcut(launchOptions: LaunchOption): Observable{ + public createLaunchShortcut(launchOptions: LaunchOption): Observable{ const options: LaunchOption = {...launchOptions, version: {...launchOptions.version, color: launchOptions.version.color || this.theme.getBsmColors()[1]}}; - return this.ipcService.sendV2("create-launch-shortcut", {args: options}); + return this.ipcService.sendV2("create-launch-shortcut", options); } public restoreSteamVR(): Promise{ - return lastValueFrom(this.ipcService.sendV2("bs-launch.restore-steamvr")); + return lastValueFrom(this.ipcService.sendV2("bs-launch.restore-steamvr")); } } diff --git a/src/renderer/services/bs-mods-manager.service.ts b/src/renderer/services/bs-mods-manager.service.ts index 2aa9819a..e390e94b 100644 --- a/src/renderer/services/bs-mods-manager.service.ts +++ b/src/renderer/services/bs-mods-manager.service.ts @@ -1,9 +1,9 @@ import { UninstallAllModsModal } from "renderer/components/modal/modal-types/uninstall-all-mods-modal.component"; import { UninstallModModal } from "renderer/components/modal/modal-types/uninstall-mod-modal.component"; -import { Observable, BehaviorSubject } from "rxjs"; +import { Observable, BehaviorSubject, lastValueFrom } from "rxjs"; import { map } from "rxjs/operators"; import { BSVersion } from "shared/bs-version.interface"; -import { InstallModsResult, UninstallModsResult, Mod, ModInstallProgression } from "shared/models/mods"; +import { Mod, ModInstallProgression } from "shared/models/mods"; import { ProgressionInterface } from "shared/models/progress-bar"; import { IpcService } from "./ipc.service"; import { ModalExitCode, ModalService } from "./modale.service"; @@ -42,11 +42,11 @@ export class BsModsManagerService { } public getAvailableMods(version: BSVersion): Observable { - return this.ipcService.sendV2("get-available-mods", { args: version }); + return this.ipcService.sendV2("get-available-mods", version); } public getInstalledMods(version: BSVersion): Observable { - return this.ipcService.sendV2("get-installed-mods", { args: version }); + return this.ipcService.sendV2("get-installed-mods", version); } public installMods(mods: Mod[], version: BSVersion): Promise { @@ -71,19 +71,20 @@ export class BsModsManagerService { this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); this.isInstalling$.next(true); - return this.ipcService.send("install-mods", { args: { mods, version } }).then(res => { - if (res.success && res.data) { - const isFullyInstalled = res.data.nbInstalledMods === res.data.nbModsToInstall; - const title = `notifications.mods.install-mods.titles.${isFullyInstalled ? "success" : "warning"}`; - const desc = `notifications.mods.install-mods.msg.${isFullyInstalled ? "success" : "warning"}`; - this.notifications.notify({ type: isFullyInstalled ? NotificationType.SUCCESS : NotificationType.WARNING, title, desc, duration: this.NOTIFICATION_DURATION }); - } else { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION }); - } + return lastValueFrom(this.ipcService.sendV2("install-mods", { mods, version })).then(res => { + const isFullyInstalled = res.nbInstalledMods === res.nbModsToInstall; + + const title = `notifications.mods.install-mods.titles.${isFullyInstalled ? "success" : "warning"}`; + const desc = `notifications.mods.install-mods.msg.${isFullyInstalled ? "success" : "warning"}`; + + this.notifications.notify({ type: isFullyInstalled ? NotificationType.SUCCESS : NotificationType.WARNING, title, desc, duration: this.NOTIFICATION_DURATION }); + }).catch(e => { + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.install-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION }); + }).finally(() => { this.isInstalling$.next(false); this.progressBar.hide(); - }); + }) } public async uninstallMod(mod: Mod, version: BSVersion): Promise { if (!this.progressBar.require()) { @@ -100,16 +101,15 @@ export class BsModsManagerService { this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); this.isUninstalling$.next(true); - return this.ipcService.send("uninstall-mods", { args: { mods: [mod], version } }).then(res => { - if (res.success) { - this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION }); - } else { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION }); - } + return lastValueFrom(this.ipcService.sendV2("uninstall-mods", { mods: [mod], version })).then(() => { + this.notifications.notifySuccess({ title: "notifications.mods.uninstall-mod.titles.success", duration: this.NOTIFICATION_DURATION }); + }).catch(e => { + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-mod.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION }); + }).finally(() => { this.isUninstalling$.next(false); this.progressBar.hide(); - }); + }) } public async uninstallAllMods(version: BSVersion) { @@ -127,15 +127,13 @@ export class BsModsManagerService { this.progressBar.show(progress$, true, { paddingLeft: "190px", paddingRight: "190px", bottom: "20px" }); this.isUninstalling$.next(true); - return this.ipcService.send("uninstall-all-mods", { args: version }).then(res => { - if (res.success) { - this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION }); - } else { - this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${res.error}`, duration: this.NOTIFICATION_DURATION }); - } - + return lastValueFrom(this.ipcService.sendV2("uninstall-all-mods", version)).then(() => { + this.notifications.notifySuccess({ title: "notifications.mods.uninstall-all-mods.titles.success", desc: "notifications.mods.uninstall-all-mods.msg.success", duration: this.NOTIFICATION_DURATION }); + }).catch(e => { + this.notifications.notifyError({ title: "notifications.types.error", desc: `notifications.mods.uninstall-all-mods.msg.errors.${e}`, duration: this.NOTIFICATION_DURATION }); + }).finally(() => { this.isUninstalling$.next(false); this.progressBar.hide(); - }); + }) } } diff --git a/src/renderer/services/bs-version-download/oculus-downloader.service.ts b/src/renderer/services/bs-version-download/oculus-downloader.service.ts index 6bc8bca2..bd705008 100644 --- a/src/renderer/services/bs-version-download/oculus-downloader.service.ts +++ b/src/renderer/services/bs-version-download/oculus-downloader.service.ts @@ -71,7 +71,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme private startDownloadBsVersion(downloadInfo: DownloadInfo): Observable>{ const ignoreCode = [MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER, OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED]; return this.handleDownload( - this.ipc.sendV2>("bs-oculus-download", { args: downloadInfo }), + this.ipc.sendV2("bs-oculus-download", downloadInfo ), ignoreCode ); } @@ -115,15 +115,7 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme } public stopDownload(): Promise{ - return lastValueFrom(this.ipc.sendV2("bs-oculus-stop-download")); + return lastValueFrom(this.ipc.sendV2("bs-oculus-stop-download")); } - public hasAuthToken(): Promise{ - return lastValueFrom(this.ipc.sendV2("bs-oculus-has-auth-token")); - } - - public clearAuthToken(): Promise{ - return lastValueFrom(this.ipc.sendV2("bs-oculus-clear-auth-token")); - } - -} \ No newline at end of file +} diff --git a/src/renderer/services/bs-version-download/steam-downloader.service.ts b/src/renderer/services/bs-version-download/steam-downloader.service.ts index e679d0ca..31fe58ec 100644 --- a/src/renderer/services/bs-version-download/steam-downloader.service.ts +++ b/src/renderer/services/bs-version-download/steam-downloader.service.ts @@ -15,7 +15,7 @@ import { DownloaderServiceInterface } from "./bs-store-downloader.interface"; import { AbstractBsDownloaderService } from "./abstract-bs-downloader.service"; export class SteamDownloaderService extends AbstractBsDownloaderService implements DownloaderServiceInterface{ - + private static instance: SteamDownloaderService; public static getInstance(): SteamDownloaderService { @@ -45,7 +45,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } public isDotNet6Installed(): Promise { - return lastValueFrom(this.ipcService.sendV2("is-dotnet-6-installed")); + return lastValueFrom(this.ipcService.sendV2("is-dotnet-6-installed")); } private setSteamSession(username: string): void { localStorage.setItem(this.STEAM_SESSION_USERNAME_KEY, username); } @@ -67,11 +67,11 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } public async getInstallationFolder(): Promise { - return lastValueFrom(this.ipcService.sendV2("bs-download.installation-folder")); + return lastValueFrom(this.ipcService.sendV2("bs-download.installation-folder")); } public setInstallationFolder(path: string): Observable { - return this.ipcService.sendV2("bs-download.set-installation-folder", { args: path }); + return this.ipcService.sendV2("bs-download.set-installation-folder", path); } // ### Downloading @@ -128,7 +128,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.verification-finished"}); } return this.notificationService.notifySuccess({title: "notifications.bs-download.success.titles.download-success"}); - })); + })); return subs; } @@ -177,12 +177,12 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen tap({ error: (e) => { this.deleteSteamSession(); - !silent && this.hanndleErrorEvent(e) + if(!silent){ this.hanndleErrorEvent(e) } } }), share({connector: () => new ReplaySubject(1)}) ); - + } private tryAutoDownloadBsVersion(downloadInfo: DownloadSteamInfo){ @@ -193,20 +193,20 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen const infos: DownloadSteamInfo = {...downloadInfo, username: this.getSteamUsername()} return this.wrapDownload( - this.ipcService.sendV2("auto-download-bs-version", { args: infos }), + this.ipcService.sendV2("auto-download-bs-version", infos), true ); } private startDownload(downloadInfo: DownloadSteamInfo){ return this.wrapDownload( - this.ipcService.sendV2("download-bs-version", { args: downloadInfo }) + this.ipcService.sendV2("download-bs-version", downloadInfo ) ); } private startQrCodeDownload(downloadInfo: DownloadSteamInfo){ return this.wrapDownload( - this.ipcService.sendV2("download-bs-version-qr", { args: downloadInfo }) + this.ipcService.sendV2("download-bs-version-qr", downloadInfo) ); } @@ -217,7 +217,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } this.progressBarService.show(this.downloadProgress$, true); - + const downloadPromise = (async () => { const haveDotNet = await this.isDotNet6Installed().catch(() => false); @@ -227,9 +227,9 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } const downloadInfo: DownloadSteamInfo = {bsVersion, isVerification} - + const autoDownload = await lastValueFrom(this.tryAutoDownloadBsVersion(downloadInfo)).then(() => true).catch(() => false); - + if(autoDownload){ return Promise.resolve(); } const qrCodeDownload$ = this.startQrCodeDownload(downloadInfo); @@ -262,7 +262,7 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } private sendInput(input: string){ - return lastValueFrom(this.ipcService.sendV2("send-input-bs-download", { args: input })); + return lastValueFrom(this.ipcService.sendV2("send-input-bs-download", input)); } public downloadBsVersion(version: BSVersion): Promise { @@ -274,6 +274,6 @@ export class SteamDownloaderService extends AbstractBsDownloaderService implemen } public stopDownload(): Promise{ - return lastValueFrom(this.ipcService.sendV2("stop-download-bs-version")); + return lastValueFrom(this.ipcService.sendV2("stop-download-bs-version")); } } diff --git a/src/renderer/services/bs-version-manager.service.ts b/src/renderer/services/bs-version-manager.service.ts index 313d26ad..6d65613e 100644 --- a/src/renderer/services/bs-version-manager.service.ts +++ b/src/renderer/services/bs-version-manager.service.ts @@ -8,7 +8,6 @@ import { EditVersionModal } from "renderer/components/modal/modal-types/edit-ver import { popElement } from "shared/helpers/array.helpers"; import { ImportVersionModal } from "renderer/components/modal/modal-types/import-version-modal.component"; import { Progression } from "main/helpers/fs.helpers"; -import { ImportVersionOptions } from "main/services/bs-local-version.service"; export class BSVersionManagerService { private static instance: BSVersionManagerService; @@ -48,16 +47,16 @@ export class BSVersionManagerService { } public askAvailableVersions(): Promise { - return this.ipcService.send("bs-version.get-version-dict").then(res => { - this.availableVersions$.next(res.data); - return res.data; + return lastValueFrom(this.ipcService.sendV2("bs-version.get-version-dict")).then(res => { + this.availableVersions$.next(res); + return res; }); } public askInstalledVersions(): Promise { - return this.ipcService.send("bs-version.installed-versions").then(res => { - this.setInstalledVersions(res.data); - return res.data; + return lastValueFrom(this.ipcService.sendV2("bs-version.installed-versions")).then(res => { + this.setInstalledVersions(res); + return res; }); } @@ -67,23 +66,24 @@ export class BSVersionManagerService { public async editVersion(version: BSVersion): Promise { const modalRes = await this.modalService.openModal(EditVersionModal, { version, clone: false }); + if (modalRes.exitCode !== ModalExitCode.COMPLETED) { return null; } if (modalRes.data.name?.length < 2) { return null; } - return this.ipcService.send("bs-version.edit", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => { - if (!res.success) { - this.notification.notifyError({ - title: `notifications.custom-version.errors.titles.${res.error.title}`, - ...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }), - }); - return null; - } + + return lastValueFrom(this.ipcService.sendV2("bs-version.edit", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => { this.askInstalledVersions(); - return res.data; - }); + return res; + }).catch(e => { + this.notification.notifyError({ + title: `notifications.custom-version.errors.titles.${e.error.title}`, + ...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }), + }); + return null; + }) } public async cloneVersion(version: BSVersion): Promise { @@ -97,19 +97,21 @@ export class BSVersionManagerService { if (modalRes.data.name?.length < 2) { return null; } + this.progressBar.showFake(0.01); - return this.ipcService.send("bs-version.clone", { args: { version, name: modalRes.data.name, color: modalRes.data.color } }).then(res => { - this.progressBar.hide(true); - if (!res.success) { - this.notification.notifyError({ - title: `notifications.custom-version.errors.titles.${res.error.title}`, - ...(res.error.message && { desc: `notifications.custom-version.errors.msg.${res.error.message}` }), - }); - return null; - } + + return lastValueFrom(this.ipcService.sendV2("bs-version.clone", { version, name: modalRes.data.name, color: modalRes.data.color })).then(res => { this.notification.notifySuccess({ title: "notifications.custom-version.success.titles.CloningFinished" }); this.askInstalledVersions(); - return res.data; + return res; + }).catch(e => { + this.notification.notifyError({ + title: `notifications.custom-version.errors.titles.${e.error.title}`, + ...(e.error.message && { desc: `notifications.custom-version.errors.msg.${e.error.message}` }), + }); + return null; + }).finally(() => { + this.progressBar.hide(true) }); } @@ -128,15 +130,15 @@ export class BSVersionManagerService { if(resModal.exitCode !== ModalExitCode.COMPLETED){ return; } - + const store = resModal.data; - const folderRes = await lastValueFrom(this.ipcService.sendV2<{ canceled: boolean; filePaths: string[] }>("choose-folder")); + const folderRes = await lastValueFrom(this.ipcService.sendV2("choose-folder")); if(!folderRes || folderRes.canceled || !folderRes.filePaths?.length){ return; } - const import$ = this.ipcService.sendV2, ImportVersionOptions>("import-version", { args: {fromPath: folderRes.filePaths.at(0), store} }); + const import$ = this.ipcService.sendV2("import-version", {fromPath: folderRes.filePaths.at(0), store}); subs.push(import$.subscribe(obs)); @@ -167,7 +169,7 @@ export class BSVersionManagerService { } public getVersionPath(version: BSVersion): Observable { - return this.ipcService.sendV2("get-version-full-path", { args: version }); + return this.ipcService.sendV2("get-version-full-path", version); } public static sortVersions(versions: BSVersion[]): BSVersion[] { diff --git a/src/renderer/services/ipc.service.ts b/src/renderer/services/ipc.service.ts index 996de6f5..60a17ca6 100644 --- a/src/renderer/services/ipc.service.ts +++ b/src/renderer/services/ipc.service.ts @@ -3,6 +3,7 @@ import { Observable, ReplaySubject, identity } from "rxjs"; import { IpcRequest, IpcResponse } from "shared/models/ipc"; import { deserializeError } from 'serialize-error'; import { IpcCompleteChannel, IpcErrorChannel, IpcTearDownChannel } from "shared/models/ipc/ipc-response.interface"; +import { IpcChannels, IpcRequestType, IpcResponseType } from "shared/models/ipc/ipc-routes"; export class IpcService { private static instance: IpcService; @@ -63,25 +64,23 @@ export class IpcService { // TODO : Convert all IPCs calls to V2 - public sendV2(channel: string, request?: IpcRequest, defaultValue?: T): Observable { - if (!request) { - request = { args: null, responceChannel: null }; - } + public sendV2(channel: C, data?: IpcRequestType, defaultValue?: IpcResponseType): Observable> { - if (!request.responceChannel) { - request.responceChannel = `${channel}_responce_${crypto.randomUUID()}`; - } + const request: IpcRequest> = { + args: data, + responceChannel: `${channel}_responce_${crypto.randomUUID()}` + }; const completeChannel: IpcCompleteChannel = `${request.responceChannel}_complete`; const errorChannel: IpcErrorChannel = `${request.responceChannel}_error`; const teardownChannel: IpcTearDownChannel = `${request.responceChannel}_teardown`; - const obs = new Observable(observer => { - window.electron.ipcRenderer.on(request.responceChannel, (res: T) => observer.next(res)); + const obs = new Observable>(observer => { + window.electron.ipcRenderer.on(request.responceChannel, (res: IpcResponseType) => observer.next(res)); window.electron.ipcRenderer.on(errorChannel, (err) => observer.error(deserializeError(err))); window.electron.ipcRenderer.on(completeChannel, () => observer.complete()); - window.electron.ipcRenderer.sendMessage(channel, request); + window.electron.ipcRenderer.sendMessage(channel as string, request); return () => { window.electron.ipcRenderer.removeAllListeners(request.responceChannel); diff --git a/src/renderer/services/link-opener.service.ts b/src/renderer/services/link-opener.service.ts index 919faa42..3f8d47d7 100644 --- a/src/renderer/services/link-opener.service.ts +++ b/src/renderer/services/link-opener.service.ts @@ -1,4 +1,4 @@ -import { Observable, Subject } from "rxjs"; +import { Observable, Subject, lastValueFrom } from "rxjs"; import { IpcService } from "./ipc.service"; export class LinkOpenerService { @@ -23,7 +23,7 @@ export class LinkOpenerService { if (internal) { return this._iframeLink$.next(url); } - this.ipcService.sendLazy("new-window", { args: url }); + lastValueFrom(this.ipcService.sendV2("new-window", url)); } public closeIframe() { diff --git a/src/renderer/services/maps-downloader.service.ts b/src/renderer/services/maps-downloader.service.ts index 7f321ecd..3f8d45fd 100644 --- a/src/renderer/services/maps-downloader.service.ts +++ b/src/renderer/services/maps-downloader.service.ts @@ -1,6 +1,6 @@ import { DownloadMapsModal } from "renderer/components/modal/modal-types/download-maps-modal.component"; import { map, filter } from "rxjs/operators"; -import { BehaviorSubject, timer, Observable } from "rxjs"; +import { BehaviorSubject, timer, Observable, lastValueFrom } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; import { ModalResponse, ModalService } from "./modale.service"; import { ProgressBarService } from "./progress-bar.service"; @@ -74,7 +74,7 @@ export class MapsDownloaderService { if (this.os.isOffline) { return null; } - return this.ipc.sendV2("download-map", { args: { map, version } }); + return this.ipc.sendV2("download-map", { map, version }); } public async openDownloadMapModal(version?: BSVersion, ownedMaps: BsmLocalMap[] = []): Promise> { @@ -131,12 +131,9 @@ export class MapsDownloaderService { this.downloadedListerners.splice(funcIndex, 1); } - public async oneClickInstallMap(map: BsvMapDetail): Promise { + public async oneClickInstallMap(map: BsvMapDetail): Promise { this.progressBar.showFake(0.04); - - const res = await this.ipc.send("one-click-install-map", { args: map }); - - return res.success; + return lastValueFrom(this.ipc.sendV2("one-click-install-map", map)); } public get isDownloading(): boolean { diff --git a/src/renderer/services/maps-manager.service.ts b/src/renderer/services/maps-manager.service.ts index 4c227074..1893c980 100644 --- a/src/renderer/services/maps-manager.service.ts +++ b/src/renderer/services/maps-manager.service.ts @@ -1,16 +1,14 @@ import { LinkMapsModal } from "renderer/components/modal/modal-types/link-maps-modal.component"; import { UnlinkMapsModal } from "renderer/components/modal/modal-types/unlink-maps-modal.component"; -import { Subject, Observable, of } from "rxjs"; +import { Subject, Observable, of, lastValueFrom } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; -import { BsmLocalMapsProgress, BsmLocalMap, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface"; +import { BsmLocalMapsProgress, BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"; import { IpcService } from "./ipc.service"; import { ModalExitCode, ModalService } from "./modale.service"; import { DeleteMapsModal } from "renderer/components/modal/modal-types/delete-maps-modal.component"; import { ProgressBarService } from "./progress-bar.service"; -import { OpenSaveDialogOption } from "shared/models/ipc"; import { NotificationService } from "./notification.service"; import { ConfigurationService } from "./configuration.service"; -import { ArchiveProgress } from "shared/models/archive.interface"; import { map, last, catchError } from "rxjs/operators"; import { ProgressionInterface } from "shared/models/progress-bar"; import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionType } from "./version-folder-linker.service"; @@ -48,7 +46,7 @@ export class MapsManagerService { } public getMaps(version?: BSVersion): Observable { - return this.ipcService.sendV2("load-version-maps", { args: version }, { loaded: 0, total: 0, maps: [] }); + return this.ipcService.sendV2("load-version-maps", version, { loaded: 0, total: 0, maps: [] }); } public async versionHaveMapsLinked(version: BSVersion): Promise { @@ -99,9 +97,11 @@ export class MapsManagerService { const showProgressBar = this.progressBar.require(); - const progress$ = this.ipcService.sendV2("delete-maps", { args: maps }).pipe(map(progress => (progress.deleted / progress.total) * 100)); + const progress$ = this.ipcService.sendV2("delete-maps", maps ).pipe(map(progress => (progress.deleted / progress.total) * 100)); - showProgressBar && this.progressBar.show(progress$, true); + if(showProgressBar){ + this.progressBar.show(progress$, true); + } progress$.toPromise().finally(() => this.progressBar.hide(true)); @@ -120,20 +120,15 @@ export class MapsManagerService { return; } - const resFile = await this.ipcService.send("save-file", { - args: { - filename: version ? `${version.BSVersion}Maps` : "Maps", - filters: [{ name: "zip", extensions: ["zip"] }], - }, - }); + const resFile = await lastValueFrom(this.ipcService.sendV2("save-file", { filename: version ? `${version.BSVersion}Maps` : "Maps", filters: [{ name: "zip", extensions: ["zip"] }]})).catch(() => null as string); - if (!resFile.success) { + if (!resFile) { return; } - const exportProgress$: Observable = this.ipcService.sendV2("export-maps", { args: { version, maps, outPath: resFile.data } }).pipe( + const exportProgress$: Observable = this.ipcService.sendV2("export-maps", { version, maps, outPath: resFile }).pipe( map(p => { - return { progression: (p.prossesedFiles / p.totalFiles) * 100, label: `${p.prossesedFiles} / ${p.totalFiles}` } as ProgressionInterface; + return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface; }) ); @@ -153,18 +148,15 @@ export class MapsManagerService { } public async isDeepLinksEnabled(): Promise { - const res = await this.ipcService.send("is-map-deep-links-enabled"); - return res.success ? res.data : false; + return lastValueFrom(this.ipcService.sendV2("is-map-deep-links-enabled")); } public async enableDeepLink(): Promise { - const res = await this.ipcService.send("register-maps-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipcService.sendV2("register-maps-deep-link")); } public async disableDeepLink(): Promise { - const res = await this.ipcService.send("unregister-maps-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipcService.sendV2("unregister-maps-deep-link")); } public get versionLinked$(): Observable { diff --git a/src/renderer/services/models-management/models-downloader.service.ts b/src/renderer/services/models-management/models-downloader.service.ts index a1b395a2..a5b93f22 100644 --- a/src/renderer/services/models-management/models-downloader.service.ts +++ b/src/renderer/services/models-management/models-downloader.service.ts @@ -6,7 +6,6 @@ import { ModalResponse, ModalService } from "../modale.service"; import { IpcService } from "../ipc.service"; import { DownloadModelsModal } from "renderer/components/modal/modal-types/models/download-models-modal.component"; import { ProgressBarService } from "../progress-bar.service"; -import { Progression } from "main/helpers/fs.helpers"; import { ProgressionInterface } from "shared/models/progress-bar"; import equal from "fast-deep-equal"; @@ -42,7 +41,7 @@ export class ModelsDownloaderService { } private async downloadModel(download: ModelDownload) { - const download$ = this.ipc.sendV2>("download-model", { args: download }); + const download$ = this.ipc.sendV2("download-model", download); if (!this.progress.isVisible) { const progress$: Observable = download$.pipe( @@ -124,13 +123,13 @@ export class ModelsDownloaderService { public async oneClickInstallModel(model: MSModel): Promise { this.progress.showFake(0.04); - const res = await this.ipc.send("one-click-install-model", { args: model }); + const res = await lastValueFrom(this.ipc.sendV2("one-click-install-model", model)).then(() => true).catch(() => false); this.progress.complete(); - await timer(500).toPromise(); + await lastValueFrom(timer(500)); this.progress.hide(true); - return res.success; + return res; } } diff --git a/src/renderer/services/models-management/models-manager.service.ts b/src/renderer/services/models-management/models-manager.service.ts index 0c1c230e..93ac636c 100644 --- a/src/renderer/services/models-management/models-manager.service.ts +++ b/src/renderer/services/models-management/models-manager.service.ts @@ -10,7 +10,6 @@ import { UnlinkModelsModal } from "renderer/components/modal/modal-types/models/ import { Progression } from "main/helpers/fs.helpers"; import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface"; import { ProgressBarService } from "../progress-bar.service"; -import { OpenSaveDialogOption } from "shared/models/os/dialog.model"; import { ProgressionInterface } from "shared/models/progress-bar"; import { NotificationService } from "../notification.service"; import { ConfigurationService } from "../configuration.service"; @@ -103,7 +102,7 @@ export class ModelsManagerService { } public $getModels(type: MSModelType, version?: BSVersion): Observable> { - return this.ipc.sendV2>("get-version-models", { args: { version, type } }); + return this.ipc.sendV2("get-version-models", { version, type }); } public async exportModels(models: BsmLocalModel[], version?: BSVersion) { @@ -111,18 +110,16 @@ export class ModelsManagerService { return; } - const resFile = await this.ipc.send("save-file", { - args: { - filename: version ? `${version.name ?? version.BSVersion} Models` : "Models", - filters: [{ name: "zip", extensions: ["zip"] }], - }, - }); + const resFile = await lastValueFrom(this.ipc.sendV2("save-file", { + filename: version ? `${version.name ?? version.BSVersion} Models` : "Models", + filters: [{ name: "zip", extensions: ["zip"] }] + })).catch(() => null as string); - if (!resFile.success) { + if (!resFile) { return; } - const exportProgress$: Observable = this.ipc.sendV2("export-models", { args: { version, models, outPath: resFile.data } }).pipe( + const exportProgress$ = this.ipc.sendV2("export-models", { version, models, outPath: resFile }).pipe( map(p => { return { progression: (p.current / p.total) * 100, label: `${p.current} / ${p.total}` } as ProgressionInterface; }) @@ -173,7 +170,7 @@ export class ModelsManagerService { const showProgressBar = this.progressBar.require(); - const obs$ = this.ipc.sendV2>("delete-models", { args: models }); + const obs$ = this.ipc.sendV2("delete-models", models); const progress$ = obs$.pipe(map(progress => (progress.current / progress.total) * 100)); @@ -191,16 +188,14 @@ export class ModelsManagerService { } public isDeepLinksEnabled(): Promise { - return this.ipc.send("is-models-deep-links-enabled").then(res => (res.success ? res.data : false)); + return lastValueFrom(this.ipc.sendV2("is-models-deep-links-enabled")); } public async enableDeepLink(): Promise { - const res = await this.ipc.send("register-models-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipc.sendV2("register-models-deep-link")); } public async disableDeepLink(): Promise { - const res = await this.ipc.send("unregister-models-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipc.sendV2("unregister-models-deep-link")); } } diff --git a/src/renderer/services/notification.service.ts b/src/renderer/services/notification.service.ts index c1183172..30a414bc 100644 --- a/src/renderer/services/notification.service.ts +++ b/src/renderer/services/notification.service.ts @@ -1,4 +1,4 @@ -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, Observable } from "rxjs"; import { SystemNotificationOptions } from "shared/models/notification/system-notification.model"; import { IpcService } from "./ipc.service"; import { NotificationResult, NotificationType, Notification } from "../../shared/models/notification/notification.model"; @@ -58,8 +58,8 @@ export class NotificationService { return this.notify(notification); } - public notifySystem(options: SystemNotificationOptions) { - this.ipc.sendLazy("notify-system", { args: options }); + public notifySystem(options: SystemNotificationOptions): Observable { + return this.ipc.sendV2("notify-system", options); } } diff --git a/src/renderer/services/playlist-downloader.service.ts b/src/renderer/services/playlist-downloader.service.ts index 94b761a2..0084849b 100644 --- a/src/renderer/services/playlist-downloader.service.ts +++ b/src/renderer/services/playlist-downloader.service.ts @@ -29,7 +29,7 @@ export class PlaylistDownloaderService { return throwError(() => new Error("Download already in progress")); } - const download$ = this.ipc.sendV2, string>("one-click-install-playlist", { args: bpListUrl }); + const download$ = this.ipc.sendV2("one-click-install-playlist", bpListUrl); const progress$ = download$.pipe(map(data => (data.current / data.total) * 100)); this.progress.show(progress$, true); diff --git a/src/renderer/services/playlists-manager.service.ts b/src/renderer/services/playlists-manager.service.ts index 5c81b602..d3b11385 100644 --- a/src/renderer/services/playlists-manager.service.ts +++ b/src/renderer/services/playlists-manager.service.ts @@ -1,3 +1,4 @@ +import { lastValueFrom } from "rxjs"; import { IpcService } from "./ipc.service"; export class PlaylistsManagerService { @@ -17,16 +18,14 @@ export class PlaylistsManagerService { } public isDeepLinksEnabled(): Promise { - return this.ipc.send("is-playlists-deep-links-enabled").then(res => (res.success ? res.data : false)); + return lastValueFrom(this.ipc.sendV2("is-playlists-deep-links-enabled")); } public async enableDeepLink(): Promise { - const res = await this.ipc.send("register-playlists-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipc.sendV2("register-playlists-deep-link")); } public async disableDeepLink(): Promise { - const res = await this.ipc.send("unregister-playlists-deep-link"); - return res.success ? res.data : false; + return lastValueFrom(this.ipc.sendV2("unregister-playlists-deep-link")); } } diff --git a/src/renderer/services/progress-bar.service.ts b/src/renderer/services/progress-bar.service.ts index 8d02364b..6fe6ba73 100644 --- a/src/renderer/services/progress-bar.service.ts +++ b/src/renderer/services/progress-bar.service.ts @@ -1,5 +1,5 @@ import { distinctUntilChanged, map } from "rxjs/operators"; -import { BehaviorSubject, Observable, Subscription, timer, of } from "rxjs"; +import { BehaviorSubject, Observable, Subscription, timer, of, lastValueFrom } from "rxjs"; import { IpcService } from "./ipc.service"; import { NotificationService } from "./notification.service"; import { CSSProperties } from "react"; @@ -36,7 +36,7 @@ export class ProgressBarService { } private setSystemProgression(progression: number) { - this.ipcService.sendLazy("window.progression", { args: progression }); + lastValueFrom(this.ipcService.sendV2("window.progression", progression)); } public subscribreTo(obs: Observable) { diff --git a/src/renderer/services/supporters.service.ts b/src/renderer/services/supporters.service.ts index 6614690a..dba2369c 100644 --- a/src/renderer/services/supporters.service.ts +++ b/src/renderer/services/supporters.service.ts @@ -1,5 +1,6 @@ import { Supporter } from "shared/models/supporters"; import { IpcService } from "./ipc.service"; +import { lastValueFrom } from "rxjs"; export class SupportersService { private static instance: SupportersService; @@ -18,11 +19,6 @@ export class SupportersService { } public getSupporters(): Promise { - return this.ipcService.send("get-supporters").then(res => { - if (!res.success) { - return null; - } - return res.data; - }); + return lastValueFrom(this.ipcService.sendV2("get-supporters")); } } diff --git a/src/renderer/services/thrird-partys/beat-saver.service.ts b/src/renderer/services/thrird-partys/beat-saver.service.ts index 35948518..fcf4e715 100644 --- a/src/renderer/services/thrird-partys/beat-saver.service.ts +++ b/src/renderer/services/thrird-partys/beat-saver.service.ts @@ -1,6 +1,7 @@ import { BsvMapDetail } from "shared/models/maps"; -import { BsvPlaylist, SearchParams } from "shared/models/maps/beat-saver.model"; +import { SearchParams } from "shared/models/maps/beat-saver.model"; import { IpcService } from "../ipc.service"; +import { lastValueFrom } from "rxjs"; export class BeatSaverService { private static instance: BeatSaverService; @@ -18,22 +19,14 @@ export class BeatSaverService { } public async getMapDetailsFromHashs(hashs: string[]): Promise { - const res = await this.ipc.send("bsv-get-map-details-from-hashs", { args: hashs }); - return res.data ?? []; + return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-from-hashs", hashs)); } public async getMapDetailsById(id: string): Promise { - const res = await this.ipc.send("bsv-get-map-details-by-id", { args: id }); - return res.data ?? null; + return lastValueFrom(this.ipc.sendV2("bsv-get-map-details-by-id", id)); } public async searchMaps(search: SearchParams): Promise { - const res = await this.ipc.send("bsv-search-map", { args: search }); - return res.data ?? []; - } - - public async getPlaylistDetailsById(id: string): Promise { - const res = await this.ipc.send("bsv-get-playlist-details-by-id", { args: id }); - return res.data ?? null; + return lastValueFrom(this.ipc.sendV2("bsv-search-map", search)); } } diff --git a/src/renderer/services/thrird-partys/model-saber.service.ts b/src/renderer/services/thrird-partys/model-saber.service.ts index 1a1a2870..3ab8338d 100644 --- a/src/renderer/services/thrird-partys/model-saber.service.ts +++ b/src/renderer/services/thrird-partys/model-saber.service.ts @@ -1,6 +1,6 @@ import { MSGetQuery, MSGetQueryFilter, MSGetQueryFilterType, MSModel } from "shared/models/models/model-saber.model"; import { IpcService } from "../ipc.service"; -import { Observable } from "rxjs"; +import { Observable, lastValueFrom } from "rxjs"; import { MS_QUERY_FILTER_TYPES } from "shared/models/models/constants"; export class ModelSaberService { @@ -19,16 +19,12 @@ export class ModelSaberService { this.ipc = IpcService.getInstance(); } - public async getModelById(id: number | string): Promise { - const res = await this.ipc.send("ms-get-model-by-id", { args: id }); - if (!res.success) { - return null; - } - return res.data; + public getModelById(id: number | string): Promise { + return lastValueFrom(this.ipc.sendV2("ms-get-model-by-id", id)); } public searchModels(query: MSGetQuery): Observable { - return this.ipc.sendV2("search-models", { args: query }); + return this.ipc.sendV2("search-models", query); } public parseFilter(stringFilters: string): MSGetQueryFilter[] { diff --git a/src/renderer/services/version-folder-linker.service.ts b/src/renderer/services/version-folder-linker.service.ts index 936de9d6..72aeefe4 100644 --- a/src/renderer/services/version-folder-linker.service.ts +++ b/src/renderer/services/version-folder-linker.service.ts @@ -59,7 +59,7 @@ export class VersionFolderLinkerService { } private doAction(action: VersionLinkerAction): Observable { - return this.ipcService.sendV2("link-version-folder-action", { args: action }); + return this.ipcService.sendV2("link-version-folder-action", action); } private get currentAction$(): Observable { @@ -126,7 +126,7 @@ export class VersionFolderLinkerService { } public isVersionFolderLinked(version: BSVersion, relativeFolder: string): Observable { - return this.ipcService.sendV2("is-version-folder-linked", { args: { version, relativeFolder } }); + return this.ipcService.sendV2("is-version-folder-linked", { version, relativeFolder }); } public $folderLinkedState(version: BSVersion, relativeFolder: string): Observable { @@ -136,7 +136,7 @@ export class VersionFolderLinkerService { if(currentAction && equal(currentAction.version, version) && currentAction.relativeFolder === relativeFolder) { return of(FolderLinkState.Processing) } - + if(queue.some(action => equal(action.version, version) && action.relativeFolder === relativeFolder)) { return of(FolderLinkState.Pending); } @@ -146,7 +146,7 @@ export class VersionFolderLinkerService { ); }), distinctUntilChanged(), - shareReplay(1) + shareReplay(1) ); } @@ -159,7 +159,7 @@ export class VersionFolderLinkerService { } public getLinkedFolders(version: BSVersion, options?: { relative?: boolean }): Observable { - return this.ipcService.sendV2("get-linked-folders", { args: { version, options } }); + return this.ipcService.sendV2("get-linked-folders", { version, options }); } public relinkAllVersionsFolders(): Observable { diff --git a/src/renderer/services/window-manager.service.ts b/src/renderer/services/window-manager.service.ts index a1f85709..fd6ec877 100644 --- a/src/renderer/services/window-manager.service.ts +++ b/src/renderer/services/window-manager.service.ts @@ -19,11 +19,11 @@ export class WindowManagerService { } public openThenCloseAll(window: AppWindow): Promise { - return lastValueFrom(this.ipcService.sendV2("open-window-then-close-all", { args: window })); + return lastValueFrom(this.ipcService.sendV2("open-window-then-close-all", window)); } public openWindowOrFocus(window: AppWindow): Promise { - return lastValueFrom(this.ipcService.sendV2("open-window-or-focus", { args: window })); + return lastValueFrom(this.ipcService.sendV2("open-window-or-focus", window)); } - + } diff --git a/src/renderer/windows/OneClick/OneClickDownloadMap.tsx b/src/renderer/windows/OneClick/OneClickDownloadMap.tsx index 8e30a8b1..822184b2 100644 --- a/src/renderer/windows/OneClick/OneClickDownloadMap.tsx +++ b/src/renderer/windows/OneClick/OneClickDownloadMap.tsx @@ -3,25 +3,27 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba import { BsmImage } from "renderer/components/shared/bsm-image.component"; import TitleBar from "renderer/components/title-bar/title-bar.component"; import { useTranslation } from "renderer/hooks/use-translation.hook"; -import { IpcService } from "renderer/services/ipc.service"; import { MapsDownloaderService } from "renderer/services/maps-downloader.service"; import { NotificationService } from "renderer/services/notification.service"; import { ProgressBarService } from "renderer/services/progress-bar.service"; import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service"; -import { lastValueFrom } from "rxjs"; import { BsvMapDetail } from "shared/models/maps"; import defaultImage from "../../../../assets/images/default-version-img.jpg"; import { useService } from "renderer/hooks/use-service.hook"; +import { useWindowArgs } from "renderer/hooks/use-window-args.hook"; +import { useWindowControls } from "renderer/hooks/use-window-controls.hook"; export default function OneClickDownloadMap() { - - const ipc = useService(IpcService); + const bsv = useService(BeatSaverService); const mapsDownloader = useService(MapsDownloaderService); const progressBar = useService(ProgressBarService); const notification = useService(NotificationService); + const { close: closeWindow } = useWindowControls(); + const { mapId, isHash } = useWindowArgs("mapId", "isHash"); const [mapInfo, setMapInfo] = useState(null); + const t = useTranslation(); const cover = mapInfo ? mapInfo.versions.at(0).coverURL : null; @@ -31,14 +33,16 @@ export default function OneClickDownloadMap() { progressBar.open(); - const promise = (async () => { - const ipcRes = await lastValueFrom(ipc.sendV2<{ id: string; isHash: boolean }>("one-click-map-info")); + console.log("AAAA", mapId, isHash); - const mapDetails = ipcRes.isHash ? (await bsv.getMapDetailsFromHashs([ipcRes.id])).at(0) : await bsv.getMapDetailsById(ipcRes.id); + const promise = (async () => { + + const mapDetails = isHash === "true" ? (await bsv.getMapDetailsFromHashs([mapId])).at(0) : await bsv.getMapDetailsById(mapId); + console.log(mapDetails); setMapInfo(() => mapDetails); - - const res = await mapsDownloader.oneClickInstallMap(mapDetails); + + const res = await mapsDownloader.oneClickInstallMap(mapDetails).then(() => true).catch(() => false); progressBar.complete(); @@ -57,9 +61,9 @@ export default function OneClickDownloadMap() { }); promise.finally(() => { - window.electron.window.close(); + closeWindow(); }); - + }, []); return ( diff --git a/src/renderer/windows/OneClick/OneClickDownloadModel.tsx b/src/renderer/windows/OneClick/OneClickDownloadModel.tsx index f4f5096f..d3eb6591 100644 --- a/src/renderer/windows/OneClick/OneClickDownloadModel.tsx +++ b/src/renderer/windows/OneClick/OneClickDownloadModel.tsx @@ -3,7 +3,6 @@ import { BsmProgressBar } from "renderer/components/progress-bar/bsm-progress-ba import { BsmImage } from "renderer/components/shared/bsm-image.component"; import TitleBar from "renderer/components/title-bar/title-bar.component"; import { useTranslation } from "renderer/hooks/use-translation.hook"; -import { IpcService } from "renderer/services/ipc.service"; import { NotificationService } from "renderer/services/notification.service"; import { ProgressBarService } from "renderer/services/progress-bar.service"; import { ModelSaberService } from "renderer/services/thrird-partys/model-saber.service"; @@ -11,16 +10,18 @@ import { MSModel } from "shared/models/models/model-saber.model"; import defaultImage from "../../../../assets/images/default-version-img.jpg"; import { ModelsDownloaderService } from "renderer/services/models-management/models-downloader.service"; import { useService } from "renderer/hooks/use-service.hook"; -import { lastValueFrom } from "rxjs"; +import { useWindowArgs } from "renderer/hooks/use-window-args.hook"; +import { useWindowControls } from "renderer/hooks/use-window-controls.hook"; export default function OneClickDownloadModel() { - const ipc = useService(IpcService); const modelSaber = useService(ModelSaberService); const progress = useService(ProgressBarService); const modelDownloader = useService(ModelsDownloaderService); const notification = useService(NotificationService); + const { close: closeWindow } = useWindowControls(); + const { modelId } = useWindowArgs("modelId"); const [model, setModel] = useState(null); const t = useTranslation(); @@ -30,9 +31,8 @@ export default function OneClickDownloadModel() { useEffect(() => { const promise = (async () => { - const infos = await lastValueFrom(ipc.sendV2<{ id: string; type: string }>("one-click-model-info")); - const model = await modelSaber.getModelById(infos.id); + const model = await modelSaber.getModelById(modelId); if (!model) { throw new Error("Failed to get model from ModelSaber"); @@ -58,7 +58,7 @@ export default function OneClickDownloadModel() { }); promise.finally(() => { - window.electron.window.close(); + closeWindow(); }); }, []); diff --git a/src/renderer/windows/OneClick/OneClickDownloadPlaylist.tsx b/src/renderer/windows/OneClick/OneClickDownloadPlaylist.tsx index a21bf590..2cc33340 100644 --- a/src/renderer/windows/OneClick/OneClickDownloadPlaylist.tsx +++ b/src/renderer/windows/OneClick/OneClickDownloadPlaylist.tsx @@ -13,16 +13,19 @@ import { useService } from "renderer/hooks/use-service.hook"; import { useConstant } from "renderer/hooks/use-constant.hook"; import { BPList } from "shared/models/playlists/playlist.interface"; import { useOnUpdate } from "renderer/hooks/use-on-update.hook"; +import { useWindowArgs } from "renderer/hooks/use-window-args.hook"; +import { useWindowControls } from "renderer/hooks/use-window-controls.hook"; export default function OneClickDownloadPlaylist() { - + const t = useTranslation(); const playlistDownloader = useService(PlaylistDownloaderService); const notification = useService(NotificationService); - + + const { close: closeWindow } = useWindowControls(); const mapsContainer = useRef(null); - const playlistUrl = useConstant(() => new URLSearchParams(window.location.search).get("playlistUrl")); + const { playlistUrl } = useWindowArgs("playlistUrl"); const download$ = useConstant(() => playlistDownloader.oneClickInstallPlaylist(playlistUrl)); const playlistInfos = useObservable(() => download$.pipe(filter(progress => !!progress.data?.playlistInfos), map(progress => progress.data.playlistInfos), take(1))); const downloadedMaps = useObservable(() => download$.pipe(filter(progress => !!progress.data?.downloadedMaps), map(progress => progress.data.downloadedMaps))); @@ -34,7 +37,7 @@ export default function OneClickDownloadPlaylist() { }).catch(() => { notification.notifySystem({ title: t("notifications.types.error"), body: t("notifications.playlists.one-click-install.error") }); }).finally(() => { - window.electron.window.close(); + closeWindow(); }); }, []); @@ -61,7 +64,7 @@ export default function OneClickDownloadPlaylist() {

{playlistInfos?.playlistTitle}

-
{downloadedMaps?.map(map => map?.coverUrl && +
{downloadedMaps?.map(map => map?.coverUrl && )}
diff --git a/src/renderer/windows/ShortcutLaunch.tsx b/src/renderer/windows/ShortcutLaunch.tsx index 1049676a..e5152af2 100644 --- a/src/renderer/windows/ShortcutLaunch.tsx +++ b/src/renderer/windows/ShortcutLaunch.tsx @@ -13,20 +13,22 @@ import { BsNoteFill } from "renderer/components/svgs/icons/bs-note-fill.componen import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; import { BsmButton } from "renderer/components/shared/bsm-button.component"; import { motion } from "framer-motion" -import { BSLaunchError, BSLaunchEventType, LaunchOption } from "shared/models/bs-launch"; +import { BSLaunchError, BSLaunchEventType } from "shared/models/bs-launch"; import { NotificationService } from "renderer/services/notification.service"; import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { useWindowControls } from "renderer/hooks/use-window-controls.hook"; export default function ShortcutLaunch() { - + const windows = useService(WindowManagerService); const ipc = useService(IpcService); const bsLauncher = useService(BSLauncherService); const notification = useService(NotificationService); + const { close: closeWindow } = useWindowControls(); const t = useTranslation(); const color = useThemeColor("second-color"); - const launchOptions = useObservable(() => ipc.sendV2("shortcut-launch-options").pipe(take(1)), null) + const launchOptions = useObservable(() => ipc.sendV2("shortcut-launch-options").pipe(take(1)), null) const [rotation, setRotation] = useState(0); const [status, setStatus] = useState(); @@ -57,7 +59,7 @@ export default function ShortcutLaunch() { }); sub.add(() => { - window.electron.window.close(); + closeWindow(); }); return () => sub.unsubscribe(); diff --git a/src/shared/models/ipc/ipc-request.interface.ts b/src/shared/models/ipc/ipc-request.interface.ts index 20951fa7..81c43dac 100644 --- a/src/shared/models/ipc/ipc-request.interface.ts +++ b/src/shared/models/ipc/ipc-request.interface.ts @@ -5,4 +5,4 @@ export interface IpcRequest { responceChannel?: string; } -export type IpcReplier = (data: Observable) => void; +export type IpcReplier = (data: Observable) => void; diff --git a/src/shared/models/ipc/ipc-routes.ts b/src/shared/models/ipc/ipc-routes.ts new file mode 100644 index 00000000..29f8da1c --- /dev/null +++ b/src/shared/models/ipc/ipc-routes.ts @@ -0,0 +1,134 @@ +import { Progression } from "main/helpers/fs.helpers"; +import { Observable } from "rxjs"; +import { BSVersion } from "shared/bs-version.interface"; +import { BSLaunchEventData, LaunchOption } from "shared/models/bs-launch"; +import { BsvMapDetail } from "shared/models/maps"; +import { BsmLocalMap, BsmLocalMapsProgress, DeleteMapsProgress } from "shared/models/maps/bsm-local-map.interface"; +import { SearchParams } from "../maps/beat-saver.model"; +import { ImportVersionOptions } from "main/services/bs-local-version.service"; +import { DownloadInfo, DownloadSteamInfo } from "main/services/bs-version-download/bs-steam-downloader.service"; +import { DepotDownloaderEvent } from "../bs-version-download/depot-downloader.model"; +import { MSGetQuery, MSModel, MSModelType } from "../models/model-saber.model"; +import { ModelDownload } from "renderer/services/models-management/models-downloader.service"; +import { BsmLocalModel } from "../models/bsm-local-model.interface"; +import { InstallModsResult, Mod, UninstallModsResult } from "../mods"; +import { DownloadPlaylistProgressionData } from "../playlists/playlist.interface"; +import { VersionLinkerAction } from "renderer/services/version-folder-linker.service"; +import { FileFilter, OpenDialogReturnValue } from "electron"; +import { SystemNotificationOptions } from "../notification/system-notification.model"; +import { Supporter } from "../supporters"; +import { AppWindow } from "../window-manager/app-window.model"; + +export type IpcReplier = (data: Observable) => void; + +export interface IpcChannelMapping extends Record { + + /* ** bs-download-ipcs ** */ + "import-version": { request: ImportVersionOptions, response: Progression}; + "is-dotnet-6-installed": { request: void, response: boolean}; + "bs-download.installation-folder": { request: void, response: string}; + "bs-download.set-installation-folder": { request: string, response: string}; + "auto-download-bs-version": { request: DownloadSteamInfo, response: DepotDownloaderEvent}; + "download-bs-version": { request: DownloadSteamInfo, response: DepotDownloaderEvent}; + "download-bs-version-qr": { request: DownloadSteamInfo, response: DepotDownloaderEvent}; + "stop-download-bs-version": { request: void, response: void}; + "send-input-bs-download": { request: string, response: boolean}; + "bs-oculus-download": { request: DownloadInfo, response: Progression}; + "bs-oculus-stop-download": { request: void, response: void}; + + /* ** beat-saver-ipcs ** */ + "bsv-search-map": {request: SearchParams, response: BsvMapDetail[]}; + "bsv-get-map-details-from-hashs": {request: string[], response: BsvMapDetail[]}; + "bsv-get-map-details-by-id": {request: string, response: BsvMapDetail}; + + /* ** bs-launcher-ipcs ** */ + "create-launch-shortcut": { request: LaunchOption, response: boolean }; + "bs-launch.need-start-as-admin": { request: void, response: boolean }; + "bs-launch.launch": { request: LaunchOption, response: BSLaunchEventData }; + "bs-launch.restore-steamvr": { request: void, response: void }; + + /* ** bs-maps-ipcs ** */ + "load-version-maps": { request: BSVersion, response: BsmLocalMapsProgress}; + "delete-maps": { request: BsmLocalMap[], response: DeleteMapsProgress }; + "export-maps": { request: { version: BSVersion; maps: BsmLocalMap[]; outPath: string }, response: Progression }; + "download-map": { request: { map: BsvMapDetail; version: BSVersion }, response: BsmLocalMap }; + "one-click-install-map": { request: BsvMapDetail, response: void }; + "register-maps-deep-link": { request: void, response: boolean }; + "unregister-maps-deep-link": { request: void, response: boolean }; + "is-map-deep-links-enabled": { request: void, response: boolean }; + + /* ** bs-model-ipcs ** */ + "one-click-install-model": { request: MSModel, response: void }; + "register-models-deep-link": { request: void, response: boolean }; + "unregister-models-deep-link": { request: void, response: boolean }; + "is-models-deep-links-enabled": { request: void, response: boolean }; + "download-model": { request: ModelDownload, response: Progression }; + "get-version-models": { request: { version: BSVersion; type: MSModelType }, response: Progression }; + "export-models": { request: { version: BSVersion; models: BsmLocalModel[]; outPath: string }, response: Progression }; + "delete-models": { request: BsmLocalModel[], response: Progression }; + + /* ** bs-mods-ipcs ** */ + "get-available-mods": { request: BSVersion, response: Mod[] }; + "get-installed-mods": { request: BSVersion, response: Mod[] }; + "install-mods": { request: { mods: Mod[]; version: BSVersion }, response: InstallModsResult }; + "uninstall-mods": { request: { mods: Mod[]; version: BSVersion }, response: UninstallModsResult }; + "uninstall-all-mods": { request: BSVersion, response: UninstallModsResult }; + + /* ** bs-playlist-ipcs ** */ + "one-click-install-playlist": { request: string, response: Progression }; + "register-playlists-deep-link": { request: void, response: boolean }; + "unregister-playlists-deep-link": { request: void, response: boolean }; + "is-playlists-deep-links-enabled": { request: void, response: boolean }; + + /* ** bs-uninstall-ipcs ** */ + "bs.uninstall": { request: BSVersion, response: boolean }; + + /* ** bs-version-ipcs ** */ + "bs-version.get-version-dict": { request: void, response: BSVersion[] }; + "bs-version.installed-versions": { request: void, response: BSVersion[] }; + "bs-version.open-folder": { request: BSVersion, response: void }; + "bs-version.edit": { request: { version: BSVersion; name: string; color: string }, response: BSVersion }; + "bs-version.clone": { request: { version: BSVersion; name: string; color: string }, response: BSVersion }; + "get-version-full-path": { request: BSVersion, response: string }; + "full-version-path-to-relative": { request: { version: BSVersion; fullPath: string }, response: string }; + "get-linked-folders": { request: { version: BSVersion; options?: { relative?: boolean } }, response: string[] }; + "link-version-folder-action": { request: VersionLinkerAction, response: boolean }; + "is-version-folder-linked": { request: { version: BSVersion; relativeFolder: string }, response: boolean }; + "relink-all-versions-folders": { request: void, response: void }; + + /* ** launcher-ipcs ** */ + "download-update": { request: void, response: boolean }; + "check-update": { request: void, response: boolean }; + "install-update": { request: void, response: void }; + + /* ** model-saber.ipcs ** */ + "ms-get-model-by-id": { request: string | number, response: MSModel }; + "search-models": { request: MSGetQuery, response: MSModel[] }; + + /* ** os-controls-ipcs ** */ + "new-window": { request: string, response: void }; + "choose-folder": { request: string, response: OpenDialogReturnValue }; + "window.progression": { request: number, response: void }; + "save-file": { request: { filename?: string; filters?: FileFilter[] }, response: string }; + "current-version": { request: void, response: string }; + "open-logs": { request: void, response: string }; + "notify-system": { request: SystemNotificationOptions, response: void }; + + /* ** supporters-ipcs ** */ + "get-supporters": { request: void, response: Supporter[] }; + + /* **window-manager-ipcs ** */ + "close-window": { request: void, response: void }; + "maximise-window": { request: void, response: void }; + "minimise-window": { request: void, response: void }; + "unmaximise-window": { request: void, response: void }; + "open-window-then-close-all": { request: AppWindow, response: void }; + "open-window-or-focus": { request: AppWindow, response: void }; + + /* ** OTHERS (if your IPC channel is not in a "-ipcs" file, put it here) ** */ + "shortcut-launch-options": { request: void, response: LaunchOption }; +} + +export type IpcRequestType = IpcChannelMapping[Channel]['request']; +export type IpcResponseType = IpcChannelMapping[Channel]['response']; +export type IpcChannels = keyof IpcChannelMapping;