feat: add Deduplicator class for managing unique promises and implement icon library generator

This commit is contained in:
2026-03-17 16:07:24 +07:00 Unverified
parent b28ac7b9db
commit 54c8f48a4f
7 changed files with 3247 additions and 34 deletions
+6 -2
View File
@@ -3,11 +3,13 @@ import { join } from "node:path";
import { file, hash, write } from "bun";
import { TTLCache } from "enka.ts";
import { AvatarStore, EnkaLocs, RelicStore, WeaponStore } from "@/type/enka";
import { Deduplicator } from "./dedupe";
export const cache = new TTLCache();
export class AssetManager {
private cache = new Map<string, ArrayBuffer>();
private deduper = new Deduplicator<ArrayBuffer>();
async getMissingAssets() {
const avatars = await getEnkaAvatarStore();
@@ -51,8 +53,10 @@ export class AssetManager {
const local = file(join("store", hash(path).toString(36)));
if (await local.exists()) return local.arrayBuffer();
const data = await fetch(new URL(path, "https://enka.network")).then(
(res) => res.arrayBuffer(),
const data = await this.deduper.acquire(path, () =>
fetch(new URL(path, "https://enka.network")).then((res) =>
res.arrayBuffer(),
),
);
this.cache.set(path, data);
queueMicrotask(() => write(local, data));
+24
View File
@@ -0,0 +1,24 @@
export class Deduplicator<T> {
// biome-ignore lint/suspicious/noExplicitAny: This is a generic class, so we need to use any here.
private map: Map<string, Promise<any>> = new Map();
has(key: string): boolean {
return this.map.has(key);
}
get<C = T>(key: string): Promise<C> | undefined {
return this.map.get(key);
}
acquire<C = T>(key: string, factory: () => Promise<C>): Promise<C> {
if (this.map.has(key)) {
return this.map.get(key)!;
}
const value = factory();
this.map.set(key, value);
value.finally(() => {
this.map.delete(key);
});
return value;
}
}