[qol] change use hash cache to load installed mods faster

This commit is contained in:
MathieuG-P
2024-07-13 17:17:43 +02:00
parent 198002238e
commit 51549161cd
3 changed files with 65 additions and 32 deletions
@@ -14,6 +14,7 @@ export class BeatModsApiService {
private readonly aliasesCache = new Map<string, BSVersion[]>();
private readonly versionModsCache = new Map<string, Mod[]>();
private readonly modsHashCache = new Map<string, Mod>();
private allModsCache: Mod[];
@@ -66,6 +67,29 @@ export class BeatModsApiService {
return mod;
}
private updateModsHashCache(mods: Mod[]): void {
if(!Array.isArray(mods)){
return;
}
for (const mod of mods) {
for (const downloads of (mod.downloads ?? [])) {
for (const hashMd5 of (downloads.hashMd5 ?? [])) {
this.modsHashCache.set(hashMd5.hash, mod);
}
}
for (const dep of (mod.dependencies ?? [])) {
for (const downloads of (dep.downloads ?? [])) {
for (const hashMd5 of (downloads.hashMd5 ?? [])) {
this.modsHashCache.set(hashMd5.hash, dep);
}
}
}
}
}
public async getVersionMods(version: BSVersion): Promise<Mod[]> {
if (this.versionModsCache.has(version.BSVersion)) {
return this.versionModsCache.get(version.BSVersion);
@@ -76,6 +100,9 @@ export class BeatModsApiService {
return this.requestService.getJSON<Mod[]>(this.getVersionModsUrl(alias)).then(mods => {
mods = mods.map(mod => this.asignDependencies(mod, mods));
this.versionModsCache.set(version.BSVersion, mods);
this.updateModsHashCache(mods);
return mods;
});
}
@@ -89,4 +116,15 @@ export class BeatModsApiService {
return this.allModsCache;
});
}
public getModByHash(hash: string): Promise<Mod> {
if (this.modsHashCache.has(hash)) {
return Promise.resolve(this.modsHashCache.get(hash));
}
return this.requestService.getJSON<Mod[]>(`${this.BEAT_MODS_API_URL}mod?hash=${hash}`).then(mods => {
this.updateModsHashCache(mods);
return mods.at(0);
});
}
}
@@ -48,23 +48,14 @@ export class BsModsManagerService {
}
private async getModFromHash(hash: string): Promise<Mod> {
const allMods = await this.beatModsApi.getAllMods();
return allMods.find(mod => {
if (mod.name.toLowerCase() === "bsipa") {
return false;
}
return mod.downloads.some(download => download.hashMd5.some(md5 => md5.hash === hash));
});
}
private async getIpaFromHash(hash: string): Promise<Mod> {
const allMods = await this.beatModsApi.getAllMods();
return allMods.find(mod => {
if (mod.name.toLowerCase() !== "bsipa") {
return false;
}
return mod.downloads.some(download => download.hashMd5.some(md5 => md5.hash === hash));
});
const mod = await this.beatModsApi.getModByHash(hash);
if(mod?.name?.toLowerCase() === "bsipa"){
return undefined;
}
return mod;
}
private async getModsInDir(version: BSVersion, modsDir: ModsInstallFolder): Promise<Mod[]> {
@@ -84,7 +75,6 @@ export class BsModsManagerService {
return undefined;
}
const hash = await md5File(filePath);
const mod = await this.getModFromHash(hash);
if (!mod) {
@@ -107,7 +97,7 @@ export class BsModsManagerService {
});
const mods = await Promise.all(promises);
return mods.filter(Boolean);
return mods.filter(Boolean);
}
private async getBsipaInstalled(version: BSVersion): Promise<Mod> {
@@ -117,7 +107,7 @@ export class BsModsManagerService {
return undefined;
}
const injectorMd5 = await md5File(injectorPath);
return this.getIpaFromHash(injectorMd5);
return this.beatModsApi.getModByHash(injectorMd5);
}
private async downloadZip(zipUrl: string): Promise<JSZip> {
@@ -322,8 +312,10 @@ export class BsModsManagerService {
public async getInstalledMods(version: BSVersion): Promise<Mod[]> {
this.manifestMatches = [];
await this.beatModsApi.getAllMods();
const bsipa = await this.getBsipaInstalled(version);
return Promise.all([this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING), this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING), this.getModsInDir(version, ModsInstallFolder.PLUGINS), this.getModsInDir(version, ModsInstallFolder.LIBS)]).then(dirMods => {
const modsDict = new Map<string, Mod>();
@@ -9,8 +9,8 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component";
import BeatWaitingImg from "../../../../../../assets/images/apngs/beat-waiting.png";
import BeatConflictImg from "../../../../../../assets/images/apngs/beat-conflict.png";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { skip, filter, map } from "rxjs/operators";
import { Observable, Subscription, combineLatest, lastValueFrom, noop } from "rxjs";
import { skip, filter } from "rxjs/operators";
import { Subscription, lastValueFrom, noop } from "rxjs";
import { useTranslation } from "renderer/hooks/use-translation.hook";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import { useInView } from "framer-motion";
@@ -96,24 +96,27 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
});
modsManager.installMods(modsToInstall, version).then(() => {
lastValueFrom(loadMods());
loadMods();
});
};
const loadMods = (): Observable<void> => {
const loadMods = (): Promise<void> => {
if (os.isOffline) {
return new Observable<void>(subscriber => subscriber.complete());
return Promise.resolve();
}
return combineLatest([
modsManager.getAvailableMods(version),
modsManager.getInstalledMods(version)
]).pipe(map(([available, installed]) => {
const promise = async () => {
const available = await lastValueFrom(modsManager.getAvailableMods(version));
const installed = await lastValueFrom(modsManager.getInstalledMods(version));
return [available, installed];
}
return promise().then(([available, installed]) => {
const defaultMods = configService.get<string[]>("default_mods" as DefaultConfigKey);
setModsAvailable(() => modsToCategoryMap(available));
setModsSelected(() => available.filter(m => m.required || defaultMods.some(d => m.name.toLowerCase() === d.toLowerCase()) || installed.some(i => m.name === i.name)));
setModsInstalled(() => modsToCategoryMap(installed));
}));
});
};
useEffect(() => {
@@ -141,14 +144,14 @@ export function ModsSlide({ version, onDisclamerDecline }: { version: BSVersion;
return onDisclamerDecline?.();
}
subs.push(loadMods().subscribe());
loadMods();
subs.push(
modsManager.isUninstalling$.pipe(
skip(1),
filter(uninstalling => !uninstalling)
).subscribe(() => {
subs.push(loadMods().subscribe());
loadMods();
})
);
});