@toolpad/utils
Version:
Shared utilities used by Toolpad packages.
95 lines (92 loc) • 2.52 kB
JavaScript
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();
}