atagen

malice

public
Star0
Watch0
6381c09db9bfd2f6f31341eb87efa1dfcf65d2e0
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/avatar-cache.tsTypescript43 lines1.1 KB
1
export interface AvatarCache {
2
  match(key: string): Promise<Response | undefined>;
3
  put(key: string, response: Response): Promise<void>;
4
}
5
6
export function createAvatarLoader(
7
  cache: () => Promise<AvatarCache>,
8
  load: (query: string) => Promise<Response>
9
): (key: string, query: string) => Promise<Response> {
10
  const pending = new Map<string, Promise<Response>>();
11
12
  return async (key, query) => {
13
    const active = pending.get(key);
14
    if (active) return (await active).clone();
15
16
    const request = (async () => {
17
      let store: AvatarCache | null = null;
18
      try {
19
        store = await cache();
20
        const cached = await store.match(key);
21
        if (cached) return cached;
22
      } catch {
23
        store = null;
24
      }
25
26
      const response = await load(query);
27
      if (response.ok && store) {
28
        try {
29
          await store.put(key, response.clone());
30
        } catch {
31
          return response;
32
        }
33
      }
34
      return response;
35
    })();
36
    pending.set(key, request);
37
    try {
38
      return (await request).clone();
39
    } finally {
40
      if (pending.get(key) === request) pending.delete(key);
41
    }
42
  };
43
}