From 9696c85a8edddd8175a3658e417d23c91d006011 Mon Sep 17 00:00:00 2001 From: nobswebdev Date: Sat, 31 Oct 2026 00:17:12 +0100 Subject: [PATCH] Cache zeroperl.wasm in the ExifTool worker after first fetch. Avoid repeat multi-megabyte downloads when Tor/Firefox do not HTTP-cache worker WASM responses. --- frontend/src/workers/exiftoolWorker.ts | 31 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/frontend/src/workers/exiftoolWorker.ts b/frontend/src/workers/exiftoolWorker.ts index 7b8e839..0f80021 100644 --- a/frontend/src/workers/exiftoolWorker.ts +++ b/frontend/src/workers/exiftoolWorker.ts @@ -6,8 +6,31 @@ import type { ExiftoolWorkerJob } from '@/types/workers/exiftoolWorkerJob'; import { resolveErrorMessage } from '@/utils/resolveErrorMessage'; import { toArrayBuffer } from '@/utils/toArrayBuffer'; +let cachedZeroperlWasm: ArrayBuffer | null = null; + +/** + * Load `zeroperl.wasm` once per worker lifetime. Tor/Firefox often skip HTTP cache for + * worker fetches and may not store responses above the memory-cache entry size limit. + */ +const fetchZeroperlWasm = async (): Promise => { + if (!cachedZeroperlWasm) { + const response = await fetch(zeroperlWasmUrl); + + if (!response.ok) { + throw new Error(`Failed to load zeroperl.wasm: HTTP ${response.status}`); + } + + cachedZeroperlWasm = await response.arrayBuffer(); + } + + return new Response(cachedZeroperlWasm, { + status: 200, + headers: { 'Content-Type': 'application/wasm' } + }); +}; + /** Custom fetch function for `@uswriting/exiftool` to load `zeroperl.wasm` from the worker. */ -const exiftoolParseOptions = { fetch: () => fetch(zeroperlWasmUrl) }; +const exiftoolParseOptions = { fetch: fetchZeroperlWasm }; const jobQueue: ExiftoolWorkerJob[] = []; let drainPromise: Promise | null = null; @@ -137,11 +160,7 @@ const processJob = async (job: ExiftoolWorkerJob): Promise => { try { await initializeWorker(); - const result = await writeMetadata( - job.file, - {}, - { args: ['-all='], ...exiftoolParseOptions } - ); + const result = await writeMetadata(job.file, {}, { args: ['-all='], ...exiftoolParseOptions }); if (!result.success) { const message = result.error ?? 'Could not strip image metadata';