WaveCut's picture
Release v1.1.3 scored WebGPU evidence
3fd9ca4 verified
Raw
History Blame Contribute Delete
5.26 kB
import { EngineRuntimeError } from './errors';
import type {
EngineErrorPayload,
EngineEvent,
EngineMethod,
EngineRequest,
EngineResponse,
EngineResponseMap,
EngineWorkerMessage,
} from './protocol';
import { BrowserEngineRuntime } from './runtime';
interface WorkerScope {
onmessage: ((event: MessageEvent<EngineRequest>) => void) | null;
postMessage(message: EngineWorkerMessage): void;
}
interface ActiveOperation {
controller: AbortController;
promise: Promise<unknown>;
}
const scope = globalThis as unknown as WorkerScope;
const runtime = new BrowserEngineRuntime();
const active = new Map<string, ActiveOperation>();
let quiescing = false;
function postEvent(event: EngineEvent): void {
scope.postMessage(event);
}
function postSuccess<Method extends EngineMethod>(
request: { requestId: string; method: Method },
result: EngineResponseMap[Method],
): void {
scope.postMessage({
type: 'response',
requestId: request.requestId,
method: request.method,
ok: true,
result,
} as EngineResponse);
}
function errorPayload(error: unknown): EngineErrorPayload {
if (error instanceof EngineRuntimeError) {
return {
code: error.code,
message: error.message,
...(error.details === undefined ? {} : { details: error.details }),
};
}
if (error instanceof DOMException && error.name === 'AbortError') {
return { code: 'ABORTED', message: error.message };
}
if (error instanceof Error) {
return {
code: error.name === 'AbortError' ? 'ABORTED' : 'ENGINE_ERROR',
message: error.message,
};
}
return { code: 'ENGINE_ERROR', message: String(error) };
}
function postFailure(request: { requestId: string; method: EngineMethod }, error: unknown): void {
scope.postMessage({
type: 'response',
requestId: request.requestId,
method: request.method,
ok: false,
error: errorPayload(error),
} as EngineResponse);
}
async function runExclusive<Result>(
requestId: string,
operation: (signal: AbortSignal) => Promise<Result>,
): Promise<Result> {
if (quiescing || active.size > 0) {
throw new EngineRuntimeError(
'ENGINE_BUSY',
quiescing
? 'The engine is unloading or clearing storage.'
: `Another mutable engine operation is active (${[...active.keys()].join(', ')}).`,
);
}
const controller = new AbortController();
const promise = operation(controller.signal);
active.set(requestId, { controller, promise });
try {
return await promise;
} finally {
active.delete(requestId);
}
}
async function stopActiveOperations(): Promise<void> {
const operations = [...active.values()];
for (const operation of operations) {
operation.controller.abort();
}
await Promise.allSettled(operations.map((operation) => operation.promise));
}
async function runQuiesced<Result>(operation: () => Promise<Result>): Promise<Result> {
if (quiescing) {
throw new EngineRuntimeError('ENGINE_BUSY', 'The engine is already unloading or clearing storage.');
}
quiescing = true;
try {
await stopActiveOperations();
return await operation();
} finally {
quiescing = false;
}
}
async function handleRequest(request: EngineRequest): Promise<void> {
try {
switch (request.method) {
case 'capabilities':
postSuccess(request, await runtime.capabilities());
return;
case 'loadModel':
postSuccess(
request,
await runExclusive(request.requestId, (signal) => (
runtime.loadModel(request.requestId, request.params, signal, postEvent)
)),
);
return;
case 'generate':
postSuccess(
request,
await runExclusive(request.requestId, (signal) => (
runtime.generate(request.requestId, request.params, signal, postEvent)
)),
);
return;
case 'scoreSequence':
postSuccess(
request,
await runExclusive(request.requestId, (signal) => (
runtime.scoreSequence(request.params, signal)
)),
);
return;
case 'abort': {
const operation = active.get(request.params.targetRequestId);
const aborted = operation !== undefined && !operation.controller.signal.aborted;
operation?.controller.abort();
postSuccess(request, { targetRequestId: request.params.targetRequestId, aborted });
return;
}
case 'unload':
postSuccess(request, await runQuiesced(() => runtime.unload()));
return;
case 'backendReport':
postSuccess(request, await runtime.backendReport());
return;
case 'storageEstimate':
postSuccess(request, await runtime.storageEstimate());
return;
case 'storagePersist':
postSuccess(request, await runtime.storagePersist());
return;
case 'storageClear':
postSuccess(request, await runQuiesced(() => runtime.storageClear()));
return;
}
} catch (error) {
postFailure(request, error);
}
}
scope.onmessage = (event) => {
const request = event.data;
if (request?.type === 'request' && typeof request.requestId === 'string') {
void handleRequest(request);
}
};