ti3x-m's picture
Publish verified Laya WebGPU release
3fd5cc1 verified
Raw History Blame Contribute Delete
2.12 kB
import type { LoadProgress } from "./shared/types";
const CACHE = "laya-webgpu-v1";
async function sha256(bytes: ArrayBuffer): Promise<string> {
const hash = await crypto.subtle.digest("SHA-256", bytes);
return [...new Uint8Array(hash)].map((part) => part.toString(16).padStart(2, "0")).join("");
}
export async function fetchVerified(
url: string,
expectedHash?: string,
onProgress?: (progress: LoadProgress) => void,
signal?: AbortSignal,
): Promise<ArrayBuffer> {
const cache = "caches" in globalThis ? await caches.open(CACHE).catch(() => undefined) : undefined;
const cached = await cache?.match(url).catch(() => undefined);
if (cached) {
const bytes = await cached.arrayBuffer();
if (!expectedHash || await sha256(bytes) === expectedHash.toLowerCase()) return bytes;
await cache?.delete(url).catch(() => false);
}
const response = await fetch(url, { signal });
if (!response.ok) throw new Error(`Download failed (${response.status}) for ${url}`);
const total = Number(response.headers.get("content-length")) || undefined;
if (!response.body) {
const bytes = await response.arrayBuffer();
if (expectedHash && await sha256(bytes) !== expectedHash.toLowerCase()) throw new Error(`SHA-256 mismatch for ${url}`);
return bytes;
}
const reader = response.body.getReader();
const chunks: Uint8Array[] = [];
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
loaded += value.byteLength;
onProgress?.({ phase: "model", loaded, total, detail: url });
}
const joined = new Uint8Array(loaded);
let offset = 0;
for (const chunk of chunks) { joined.set(chunk, offset); offset += chunk.length; }
if (expectedHash && await sha256(joined.buffer) !== expectedHash.toLowerCase()) throw new Error(`SHA-256 mismatch for ${url}`);
await cache?.put(url, new Response(joined, { headers: response.headers })).catch(() => undefined);
return joined.buffer;
}
export async function clearModelCache(): Promise<void> {
if ("caches" in globalThis) await caches.delete(CACHE);
}