worker-factory
Version:
A little factory function to create a JSON-RPC based Web Worker implementation.
53 lines (43 loc) • 2.26 kB
text/typescript
import { IBrokerEvent, IErrorNotification, IErrorResponse, IReceiver, IRequest, IWorkerDefinition } from '../interfaces';
import { TMessageReceiverWithParams, TMessageReceiverWithoutParams, TWorkerImplementation } from '../types';
import { renderMethodNotFoundError, renderMissingResponseError, renderUnexpectedResultError } from './error-renderers';
export const createMessageHandler = <WorkerDefinition extends IWorkerDefinition>(
receiver: IReceiver,
workerImplementation: TWorkerImplementation<WorkerDefinition>
) => {
return async ({ data: { id, method, params } }: IBrokerEvent<WorkerDefinition>) => {
const messageHandler = workerImplementation[method];
try {
if (messageHandler === undefined) {
throw renderMethodNotFoundError(method);
}
const response =
params === undefined
? (messageHandler as TMessageReceiverWithoutParams<WorkerDefinition[typeof method]['response']>)()
: (
messageHandler as TMessageReceiverWithParams<
WorkerDefinition[typeof method]['params'],
WorkerDefinition[typeof method]['response']
>
)(params);
if (response === undefined) {
throw renderMissingResponseError(method);
}
const synchronousResponse = response instanceof Promise ? await response : response;
if (id === null) {
if (synchronousResponse.result !== undefined) {
throw renderUnexpectedResultError(method);
}
} else {
if (synchronousResponse.result === undefined) {
throw renderUnexpectedResultError(method);
}
const { result, transferables = [] } = <IRequest['response']>synchronousResponse;
receiver.postMessage({ id, result }, transferables);
}
} catch (err) {
const { message, status = -32603 } = err;
receiver.postMessage(<IErrorNotification | IErrorResponse>{ error: { code: status, message }, id });
}
};
};