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" } ] 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 762ab6b7..b492d6f9 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/maps/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 7a7eaa3b..29bf8ae3 100644 --- a/src/main/ipcs/bs-playlist-ipcs.ts +++ b/src/main/ipcs/bs-playlist-ipcs.ts @@ -1,63 +1,46 @@ -import { BSVersion } from "shared/bs-version.interface"; import { LocalPlaylistsManagerService } from "../services/additional-content/local-playlists-manager.service"; import { IpcService } from "../services/ipc.service"; -import { of, throwError } from "rxjs"; -import { BPList } from "shared/models/playlists/playlist.interface"; +import { of } from "rxjs"; const ipc = IpcService.getInstance(); -ipc.on("one-click-install-playlist", (req, reply) => { - const playlists = LocalPlaylistsManagerService.getInstance(); - reply(playlists.oneClickInstallPlaylist(req.args)); +ipc.on("one-click-install-playlist", (args, reply) => { + const mapsManager = LocalPlaylistsManagerService.getInstance(); + reply(mapsManager.oneClickInstallPlaylist(args)); }); -ipc.on<{playlist: BPList, version: BSVersion}>("install-playlist", (req, reply) => { +ipc.on("register-playlists-deep-link", (args, reply) => { + const maps = LocalPlaylistsManagerService.getInstance(); + reply(of(maps.enableDeepLinks())); +}); + +ipc.on("unregister-playlists-deep-link", (args, reply) => { + const maps = LocalPlaylistsManagerService.getInstance(); + reply(of(maps.disableDeepLinks())); +}); + +ipc.on("is-playlists-deep-links-enabled", (args, reply) => { + const maps = LocalPlaylistsManagerService.getInstance(); + reply(of(maps.isDeepLinksEnabled())); +}); + +ipc.on("install-playlist", (args, reply) => { const playlists = LocalPlaylistsManagerService.getInstance(); - if(req.args.playlist?.customData?.syncURL){ - return reply(playlists.downloadPlaylist(req.args.playlist.customData.syncURL, req.args.version)); + if(args.playlist?.customData?.syncURL){ + return reply(playlists.downloadPlaylist(args.playlist.customData.syncURL, args.version)); } - reply(playlists.downloadPlaylistSongs(req.args.playlist.songs, req.args.version)); + reply(playlists.downloadPlaylistSongs(args.playlist.songs, args.version)); }); -ipc.on("register-playlists-deep-link", (_, reply) => { +ipc.on("get-version-playlists-details", (args, reply) => { const playlists = LocalPlaylistsManagerService.getInstance(); - - try { - reply(of(playlists.enableDeepLinks())); - } catch (e) { - reply(throwError(() => e)); - } + reply(playlists.getVersionPlaylistsDetails(args)); }); -ipc.on("unregister-playlists-deep-link", (_, reply) => { +ipc.on("delete-playlist", (args, reply) => { const playlists = LocalPlaylistsManagerService.getInstance(); - - try { - reply(of(playlists.disableDeepLinks())); - } catch (e) { - reply(throwError(() => e)); - } -}); - -ipc.on("is-playlists-deep-links-enabled", (_, reply) => { - const playlists = LocalPlaylistsManagerService.getInstance(); - - try { - reply(of(playlists.isDeepLinksEnabled())); - } catch (e) { - reply(throwError(() => e)); - } -}); - -ipc.on("get-version-playlists-details", (req, reply) => { - const playlists = LocalPlaylistsManagerService.getInstance(); - reply(playlists.getVersionPlaylistsDetails(req.args)); -}); - -ipc.on<{path: string, deleteMaps?: boolean}>("delete-playlist", (req, reply) => { - const playlists = LocalPlaylistsManagerService.getInstance(); - reply(playlists.deletePlaylist(req.args)); + reply(playlists.deletePlaylist(args)); }); 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 309450d4..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/maps/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 d15eed28..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,53 +7,37 @@ import { from, of } from "rxjs"; const ipc = IpcService.getInstance(); -ipcMain.on("new-window", (event, request: IpcRequest) => { - shell.openExternal(request.args); +ipc.on("new-window", (args, reply) => { + reply(from(shell.openExternal(args))); }); -ipc.on("choose-folder", (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 ?? "" }))); }); -ipc.on("view-path-in-explorer", (req, reply) => { - reply(of(shell.showItemInFolder(req.args))); +ipc.on("window.progression",(args, reply, sender) => { + BrowserWindow.fromWebContents(sender)?.setProgressBar(args / 100); + reply(of(undefined)); }); -ipcMain.on("window.progression", async (event, request: IpcRequest) => { - BrowserWindow.fromWebContents(event.sender)?.setProgressBar(request.args / 100); -}); - -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/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-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 11c33dfe..cea24bf8 100644 --- a/src/main/services/additional-content/local-playlists-manager.service.ts +++ b/src/main/services/additional-content/local-playlists-manager.service.ts @@ -62,7 +62,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}`); }); this.fileAssociation.registerFileAssociation(".bplist", filePath => { diff --git a/src/main/services/additional-content/maps/local-maps-manager.service.ts b/src/main/services/additional-content/maps/local-maps-manager.service.ts index 8b1a1405..fa03ff75 100644 --- a/src/main/services/additional-content/maps/local-maps-manager.service.ts +++ b/src/main/services/additional-content/maps/local-maps-manager.service.ts @@ -14,18 +14,18 @@ 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"; import { SongDetailsCacheService } from "./song-details-cache.service"; -import { sToMs } from "shared/helpers/time.helpers"; import { SongCacheService } from "./song-cache.service"; +import { IpcService } from "../../ipc.service"; import { pathToFileURL } from "url"; +import { sToMs } from "../../../../shared/helpers/time.helpers"; export class LocalMapsManagerService { private static instance: LocalMapsManagerService; @@ -53,10 +53,10 @@ export class LocalMapsManagerService { private readonly reqService: RequestService; private readonly deepLink: DeepLinkService; private readonly windows: WindowManagerService; - private readonly ipc: IpcService; private readonly linker: FolderLinkerService; private readonly songDetailsCache: SongDetailsCacheService; private readonly songCache: SongCacheService; + private readonly ipc: IpcService; private constructor() { this.localVersion = BSLocalVersionService.getInstance(); @@ -66,18 +66,22 @@ export class LocalMapsManagerService { this.deepLink = DeepLinkService.getInstance(); this.windows = WindowManagerService.getInstance(); this.linker = FolderLinkerService.getInstance(); - this.ipc = IpcService.getInstance(); this.songDetailsCache = SongDetailsCacheService.getInstance(); this.songCache = SongCacheService.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); }); } @@ -157,14 +161,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, @@ -307,7 +303,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/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 d503d7a1..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, IpcMainEvent, 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: 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,24 +55,26 @@ export class IpcService { complete: () => this.send(this.getCompleteChannel(channel), window) }) - const unsubscribeOnDestroy = () => sub.unsubscribe(); + const unsubscribe = () => sub.unsubscribe(); - window.webContents.once("destroyed", unsubscribeOnDestroy); - window.webContents.ipc.once(this.getTearDownChannel(channel), () => sub.unsubscribe()); + window.webContents.once("destroyed", unsubscribe); + window.webContents.ipc.once(this.getTearDownChannel(channel), unsubscribe); sub.add(() => { - window.webContents.removeListener("destroyed", unsubscribeOnDestroy); 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 330d9900..fb336d33 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 @@ -241,7 +246,9 @@ export class BsModsManagerService { })) : extracted; - res && this.nbInstalledMods++; + if(res){ + this.nbInstalledMods++; + } return res; } diff --git a/src/main/services/request.service.ts b/src/main/services/request.service.ts index ca800730..15f30c6c 100644 --- a/src/main/services/request.service.ts +++ b/src/main/services/request.service.ts @@ -1,11 +1,13 @@ -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 got, { GotOptions } from "got"; +import got, { Options } from "got"; import { IncomingMessage } from "http"; +import { app } from "electron"; +import os from "os"; export class RequestService { private static instance: RequestService; @@ -17,16 +19,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}`); @@ -52,7 +71,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 => { @@ -69,9 +88,9 @@ export class RequestService { }).pipe(tap({ error: e => log.error(e, url, dest) }), shareReplay(1)); } - public downloadBuffer(url: string, options?: GotOptions): Observable> { - return new Observable>(subscriber => { - const progress: Progression = { + public downloadBuffer(url: string, options?: Options & { isStream?: true }): Observable> { + return new Observable>(subscriber => { + const progress: Progression = { current: 0, total: 0, data: null, @@ -113,6 +132,6 @@ export class RequestService { req.destroy(); } - }).pipe(tap({ error: e => log.error(e) }), shareReplay(1)); + }).pipe(tap({ error: log.error }), shareReplay(1)) } } 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 c770efa9..104b2deb 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")} /> +
+ +
+
{t("modals.clone-version.inputs.color.label")} 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 e098e3e0..3538179e 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 = ({ options: {data} }) => { @@ -45,14 +46,14 @@ export const ShareFoldersModal: ModalComponent = ({ options: {d }, [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; diff --git a/src/renderer/components/title-bar/title-bar.component.tsx b/src/renderer/components/title-bar/title-bar.component.tsx index 13c12717..6d0ca49f 100644 --- a/src/renderer/components/title-bar/title-bar.component.tsx +++ b/src/renderer/components/title-bar/title-bar.component.tsx @@ -10,11 +10,13 @@ import { BsmIconType } from "../svgs/bsm-icon.component"; import "./title-bar.component.css"; import { useService } from "renderer/hooks/use-service.hook"; import { lastValueFrom } from "rxjs"; +import { useWindowControls } from "renderer/hooks/use-window-controls.hook"; export default function TitleBar({ template = "index.html" }: { template: AppWindow }) { - + const ipcService = useService(IpcService); const audio = useService(AudioPlayerService); + const windowControls = useWindowControls(); const volume = useObservable(() => 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 04d5332a..37064991 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 f250da0f..8a1d464b 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 1e7fdff8..3bad1d2e 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 b48eb747..f6f81f93 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 512bdfb0..612f6bf3 100644 --- a/src/renderer/services/bs-version-download/steam-downloader.service.ts +++ b/src/renderer/services/bs-version-download/steam-downloader.service.ts @@ -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 @@ -177,7 +177,7 @@ 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)}) @@ -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) ); } @@ -260,7 +260,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 { @@ -272,6 +272,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 5faf00ee..986d91bb 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; }); } @@ -73,17 +72,17 @@ export class BSVersionManagerService { 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 +96,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) }); } @@ -131,12 +132,12 @@ export class BSVersionManagerService { 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 +168,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 1a577df0..be27349b 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 95db40de..b67e85ed 100644 --- a/src/renderer/services/maps-downloader.service.ts +++ b/src/renderer/services/maps-downloader.service.ts @@ -75,7 +75,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> { @@ -132,12 +132,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 a63ca2c3..42a95543 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 } 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 { @@ -97,7 +95,7 @@ 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)); if (showProgressBar) { this.progressBar.show(progress$, true); @@ -120,20 +118,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 +146,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 48ecf1e6..a8ec3c0c 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 39837c11..d1e075d6 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"; @@ -101,7 +100,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) { @@ -109,18 +108,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; }) @@ -171,7 +168,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)); @@ -189,16 +186,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 5e72fd06..74724ae9 100644 --- a/src/renderer/services/playlist-downloader.service.ts +++ b/src/renderer/services/playlist-downloader.service.ts @@ -37,7 +37,7 @@ export class PlaylistDownloaderService { return new Observable>(subscriber => { (async () => { const playlist = await lastValueFrom(this.playlistQueue$.pipe(map(queue => queue.at(0)), filter(p => equal(bpList, p)), take(1))); - const download$ = this.ipc.sendV2, unknown>("install-playlist", { args: { version, playlist } }); + const download$ = this.ipc.sendV2("install-playlist", { version, playlist }); await lastValueFrom(download$.pipe(tap(subscriber))); })() @@ -50,7 +50,7 @@ export class PlaylistDownloaderService { public oneClickInstallPlaylist(bpListUrl: string): Observable> { - 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 e18ab895..2516044c 100644 --- a/src/renderer/services/playlists-manager.service.ts +++ b/src/renderer/services/playlists-manager.service.ts @@ -31,11 +31,11 @@ export class PlaylistsManagerService { } public getVersionPlaylistsDetails(version: BSVersion): Observable> { - return this.ipc.sendV2("get-version-playlists-details", { args: version }); + return this.ipc.sendV2("get-version-playlists-details", version); } public deletePlaylist(opt: {path: string, deleteMaps?: boolean}): Observable { - return this.ipc.sendV2("delete-playlist", { args: opt }); + return this.ipc.sendV2("delete-playlist", opt); } public async linkVersion(version: BSVersion): Promise { @@ -67,15 +67,15 @@ export class PlaylistsManagerService { } public isDeepLinksEnabled(): Promise { - return lastValueFrom(this.ipc.sendV2("is-playlists-deep-links-enabled")); + return lastValueFrom(this.ipc.sendV2("is-playlists-deep-links-enabled")); } public enableDeepLink(): Promise { - return lastValueFrom(this.ipc.sendV2("register-playlists-deep-link")); + return lastValueFrom(this.ipc.sendV2("register-playlists-deep-link")); } public disableDeepLink(): Promise { - return lastValueFrom(this.ipc.sendV2("unregister-playlists-deep-link")); + return lastValueFrom(this.ipc.sendV2("unregister-playlists-deep-link")); } public $playlistsFolderLinkState(version: BSVersion): Observable { 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 dcc2df4a..330db668 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 { @@ -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..8a33bd8f --- /dev/null +++ b/src/shared/models/ipc/ipc-routes.ts @@ -0,0 +1,138 @@ +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 { BPList, 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"; +import { LocalBPListsDetails } from "../playlists/local-playlist.models"; + +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 }; + "install-playlist": {request: {playlist: BPList, version: BSVersion}, response: Progression}; + "get-version-playlists-details": {request: BSVersion, response: Progression}; + "delete-playlist": {request: {path: string, deleteMaps?: boolean}, response: Progression}; + + /* ** 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;