diff --git a/src/service-worker-custom.ts b/src/service-worker-custom.ts index f6f7110f..45e8b52d 100644 --- a/src/service-worker-custom.ts +++ b/src/service-worker-custom.ts @@ -1,5 +1,7 @@ import { registerRoute } from "workbox-routing"; +import { CacheExpiration } from "workbox-expiration"; +// Queue of requests to fetch preview images interface FetchPreviewObject { url: URL; fileid: number; @@ -8,11 +10,20 @@ interface FetchPreviewObject { } let fetchPreviewQueue: FetchPreviewObject[] = []; +// Cache for preview images +const cacheName = "images"; let imageCache: Cache; (async () => { - imageCache = await caches.open("images"); + imageCache = await caches.open(cacheName); })(); +// Expiration for cache +const expirationManager = new CacheExpiration(cacheName, { + maxAgeSeconds: 3600 * 24 * 7, // days + maxEntries: 20000, // 20k images +}); + +// Start fetching with multipreview let fetchPreviewTimer: any; async function flushPreviewQueue() { if (fetchPreviewQueue.length === 0) return; @@ -21,6 +32,13 @@ async function flushPreviewQueue() { const fetchPreviewQueueCopy = fetchPreviewQueue; fetchPreviewQueue = []; + // Check if only one request + if (fetchPreviewQueueCopy.length === 1) { + const p = fetchPreviewQueueCopy[0]; + return p.callback(await fetch(p.url)); + } + + // Create aggregated request body const files = fetchPreviewQueueCopy.map((p) => ({ fileid: p.fileid, x: Number(p.url.searchParams.get("x")), @@ -41,11 +59,13 @@ async function flushPreviewQueue() { url.searchParams.delete("a"); url.searchParams.delete("c"); + // Fetch multipreview const res = await fetch(url, { method: "POST", body: JSON.stringify(files), }); + // Get blob if (res.status !== 200) throw new Error("Error fetching multi-preview"); const blob = await res.blob(); @@ -85,7 +105,7 @@ async function flushPreviewQueue() { }); } } catch (e) { - console.error(e); + console.error("Multipreview error", e); } // Initiate callbacks for failed requests @@ -99,9 +119,10 @@ async function flushPreviewQueue() { }); } +// Intercept preview requests registerRoute( /^.*\/apps\/memories\/api\/image\/preview\/.*/, - async ({ url }) => { + async ({ url, request }) => { // Check if in cache const cache = await imageCache?.match(url); if (cache) return cache; @@ -122,13 +143,20 @@ registerRoute( } }); + // Fallback to single request if (res.status !== 200) { res = await fetch(url); } // Cache response if (res.status === 200) { - imageCache?.put(url, res.clone()); + imageCache?.put(request, res.clone()); + expirationManager.updateTimestamp(request.url); + } + + // Run expiration once in every 20 requests + if (Math.random() < 0.05) { + expirationManager.expireEntries(); } return res;