diff --git a/src/main/services/mods/beat-mods-api.service.ts b/src/main/services/mods/beat-mods-api.service.ts index c8e4bfd6..c0136b96 100644 --- a/src/main/services/mods/beat-mods-api.service.ts +++ b/src/main/services/mods/beat-mods-api.service.ts @@ -70,17 +70,17 @@ export class BeatModsApiService { }); } - public getModByHash(hash: string): Promise { + public async getModByHash(hash: string): Promise { if (this.modsHashCache.has(hash)) { return Promise.resolve(this.modsHashCache.get(hash)); } - return this.requestService.getJSON<{ modVersions: BbmModVersion[] }>(`${this.MODS_REPO_API_URL}/hashlookup?hash=${hash}`).then(({ data }) => { + return this.requestService.getJSON<{ modVersions: BbmModVersion[] }>( + `${this.MODS_REPO_API_URL}/hashlookup?hash=${hash}`, + { silentError: true } + ).then(({ data }) => { this.updateModsHashCache(data?.modVersions ?? []); return data?.modVersions?.at(0); - }).catch((): undefined => { - log.error(`Failed to get mod by hash: ${hash}`); - return undefined; }); } } diff --git a/src/main/services/mods/bs-mods-manager.service.ts b/src/main/services/mods/bs-mods-manager.service.ts index 089fa2df..ccc1f13c 100644 --- a/src/main/services/mods/bs-mods-manager.service.ts +++ b/src/main/services/mods/bs-mods-manager.service.ts @@ -28,8 +28,6 @@ export class BsModsManagerService { private readonly linuxService: LinuxService; private readonly requestService: RequestService; - private manifestMatches: BbmModVersion[]; - public static getInstance(): BsModsManagerService { if (!BsModsManagerService.instance) { BsModsManagerService.instance = new BsModsManagerService(); @@ -45,7 +43,11 @@ export class BsModsManagerService { } private async getModFromHash(hash: string): Promise { - const mod = await this.beatModsApi.getModByHash(hash); + const mod: BbmModVersion | undefined = await this.beatModsApi.getModByHash(hash) + .catch((error) => { + log.warn("Could not get mod with hash", hash, "cause", error?.message); + return undefined; + }); if(mod?.contentHashes?.some(content => content.path.includes("IPA.exe"))){ return undefined; @@ -55,7 +57,11 @@ export class BsModsManagerService { } - private async getModsInDir(version: BSVersion, modsDir: ModsInstallFolder): Promise { + private async getModsInDir( + version: BSVersion, + modsDir: ModsInstallFolder, + manifestMatches: BbmModVersion[] + ): Promise { const bsPath = await this.bsLocalService.getVersionPath(version); const modsPath = path.join(bsPath, modsDir); @@ -66,34 +72,35 @@ export class BsModsManagerService { const files = await recursiveReadDir(modsPath); const promises = files.map(async filePath => { - const ext = path.extname(filePath); + const ext = path.extname(filePath); + if (ext !== ".dll" && ext !== ".exe" && ext !== ".manifest") { + return undefined; + } - if (ext !== ".dll" && ext !== ".exe" && ext !== ".manifest") { - return undefined; - } - const hash = await md5File(filePath); - const mod = await this.getModFromHash(hash); + log.info("Getting mod manifest", filePath); + const hash = await md5File(filePath); + const mod = await this.getModFromHash(hash); - if (!mod) { + if (!mod) { + return undefined; + } + + if (ext === ".manifest") { + manifestMatches.push(mod); + return undefined; + } + + if (modsDir === ModsInstallFolder.LIBS || modsDir === ModsInstallFolder.LIBS_PENDING) { + const manifestIndex = manifestMatches.findIndex(m => m.id === mod.id); + if (manifestIndex < 0) { + log.warn("No matching manifest for", `"${filePath}"`, "with hash:", hash); return undefined; } - if (ext === ".manifest") { - this.manifestMatches.push(mod); - return undefined; - } + manifestMatches.splice(manifestIndex, 1); + } - if (filePath.toLowerCase().includes("libs")) { - const manifestIndex = this.manifestMatches.findIndex(m => m.id === mod.id); - - if (manifestIndex < 0) { - return undefined; - } - - this.manifestMatches.splice(manifestIndex, 1); - } - - return mod; + return mod; }); const results = await Promise.allSettled(promises); @@ -101,6 +108,8 @@ export class BsModsManagerService { return results.reduce((mods, mod) => { if (mod?.status === "fulfilled" && mod?.value) { mods.push(mod.value); + } else if (mod?.status === "rejected") { + log.error("MOD FAILED", mod); } return mods; }, [] as BbmModVersion[]); @@ -113,7 +122,10 @@ export class BsModsManagerService { return undefined; } const injectorMd5 = await md5File(injectorPath); - return this.beatModsApi.getModByHash(injectorMd5); + return this.beatModsApi.getModByHash(injectorMd5).catch((error) => { + log.error("Could not get bsipa mod", error?.message); + return undefined; + }); } private async downloadZip(zipUrl: string): Promise { @@ -345,12 +357,17 @@ export class BsModsManagerService { } public async getInstalledMods(version: BSVersion): Promise { - this.manifestMatches = []; - const bsipa = await this.getBsipaInstalled(version); - const pluginsMods = await Promise.all([this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING), this.getModsInDir(version, ModsInstallFolder.PLUGINS)]); - const libsMods = await Promise.all([this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING), this.getModsInDir(version, ModsInstallFolder.LIBS)]); + const manifestMatches: BbmModVersion[] = []; + const pluginsMods = await Promise.all([ + this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING, manifestMatches), + this.getModsInDir(version, ModsInstallFolder.PLUGINS, manifestMatches) + ]); + const libsMods = await Promise.all([ + this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING, manifestMatches), + this.getModsInDir(version, ModsInstallFolder.LIBS, manifestMatches) + ]); const dirMods = pluginsMods.flat().concat(libsMods.flat()); diff --git a/src/main/services/request.service.ts b/src/main/services/request.service.ts index a8c19887..8ade56ce 100644 --- a/src/main/services/request.service.ts +++ b/src/main/services/request.service.ts @@ -28,14 +28,18 @@ export class RequestService { private constructor() {} - public async getJSON(url: string): Promise<{ data: T; headers: IncomingHttpHeaders }> { + public async getJSON(url: string, options?: { + silentError?: boolean + }): Promise<{ data: T; headers: IncomingHttpHeaders }> { try { // @ts-ignore (ESM is not well supported in this project, We need to move out electron-react-boilerplate, and use Vite) const res = await got(url, { responseType: 'json', headers: this.baseHeaders }); return { data: res.body as T, headers: res.headers }; } catch (err) { - log.error(`Failed to get JSON from URL: ${url}`, err); + if (options?.silentError !== true) { + log.error(`Failed to get JSON from URL: ${url}`, err); + } throw err; } }