UNPKG

@toolpad/utils

Version:

Shared utilities used by Toolpad packages.

95 lines (92 loc) 2.52 kB
import { MessageChannel } from 'worker_threads'; import { errorFrom, serializeError } from "./errors.js"; /** * Helpers that are intended to set up rpc between a Node.js worker thread and the main thread. * Create the worker and pass a port in the workerData. * * On the main thread: * * const rpcChannel = new MessageChannel() * const worker = new Worker('./myWorker.js', { * workerData: { rpcPort: rpcChannel.port1 }, * transferList: [rpcChannel.port1] * }) * * // Depending of the direction of communication, either * const client = createRpcClient(rpcChannel.port2) * // or * serveRpc(rpcChannel.port2, { * myMethod * }) * * On the worker thread: * * // Depending of the direction of communication, either * const client = createRpcClient(workerData.rpcPort) * // or * serveRpc(workerData.rpcPort, { * myMethod * }) * * Use multiple channels for bidirectional communication. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export function createRpcClient(port, { timeout = 30000 } = {}) { return new Proxy({}, { get: (target, prop) => { if (typeof prop !== 'string') { return Reflect.get(target, prop); } return (...args) => { return new Promise((resolve, reject) => { const { port1, port2 } = new MessageChannel(); const timeoutId = setTimeout(() => { port1.close(); }, timeout); port1.on('message', msg => { clearTimeout(timeoutId); if (msg.error) { reject(msg.error); } else { resolve(msg.result); } }); port1.start(); port.postMessage({ method: prop, args, port: port2 }, [port2]); }); }; } }); } export function serveRpc(port, methods) { const methodMap = new Map(Object.entries(methods)); port.on('message', async msg => { const method = methodMap.get(msg.method); if (method) { try { const result = await method(...msg.args); msg.port.postMessage({ result }); } catch (rawError) { msg.port.postMessage({ error: serializeError(errorFrom(rawError)) }); } } else { msg.port.postMessage({ error: new Error(`Method "${msg.method}" not found`) }); } }); port.start(); }