brainy/src/utils/workerUtils.ts
2025-06-23 14:46:26 -07:00

137 lines
4 KiB
TypeScript

/**
* Utility functions for working with Web Workers and Worker Threads
*/
import { isNode, isBrowser } from './environment.js';
/**
* Execute a function in a Web Worker (browser environment)
*
* @param fn The function to execute
* @param args The arguments to pass to the function
* @returns A promise that resolves with the result of the function
*/
export function executeInWebWorker<T>(fn: Function, ...args: any[]): Promise<T> {
return new Promise((resolve, reject) => {
// Create a blob URL for the worker script
const fnString = fn.toString();
const workerScript = `
self.onmessage = function(e) {
try {
const fn = ${fnString};
const result = fn(...e.data);
self.postMessage({ success: true, data: result });
} catch (error) {
self.postMessage({
success: false,
error: error instanceof Error ? error.message : String(error)
});
}
};
`;
const blob = new Blob([workerScript], { type: 'application/javascript' });
const blobURL = URL.createObjectURL(blob);
// Create a worker
const worker = new Worker(blobURL);
// Set up message handling
worker.onmessage = function(e: MessageEvent<{ success: boolean; data: T; error?: string }>) {
URL.revokeObjectURL(blobURL); // Clean up
worker.terminate(); // Terminate the worker
if (e.data.success) {
resolve(e.data.data);
} else {
reject(new Error(e.data.error));
}
};
worker.onerror = function(error: ErrorEvent) {
URL.revokeObjectURL(blobURL); // Clean up
worker.terminate(); // Terminate the worker
reject(error);
};
// Start the worker
worker.postMessage(args);
});
}
/**
* Execute a function in a Worker Thread (Node.js environment)
*
* @param fn The function to execute
* @param args The arguments to pass to the function
* @returns A promise that resolves with the result of the function
*/
export function executeInWorkerThread<T>(fn: Function, ...args: any[]): Promise<T> {
return new Promise((resolve, reject) => {
try {
// Dynamic import to avoid errors in browser environments
const { Worker } = require('worker_threads');
// Create a worker script
const fnString = fn.toString();
const workerScript = `
const { parentPort } = require('worker_threads');
parentPort.once('message', (data) => {
try {
const fn = ${fnString};
const result = fn(...data);
parentPort.postMessage({ success: true, data: result });
} catch (error) {
parentPort.postMessage({
success: false,
error: error instanceof Error ? error.message : String(error)
});
}
});
`;
// Create a worker
const worker = new Worker(workerScript, { eval: true });
// Set up message handling
worker.on('message', (data: { success: boolean; data: T; error?: string }) => {
worker.terminate(); // Terminate the worker
if (data.success) {
resolve(data.data);
} else {
reject(new Error(data.error));
}
});
worker.on('error', (error: Error) => {
worker.terminate(); // Terminate the worker
reject(error);
});
// Start the worker
worker.postMessage(args);
} catch (error) {
reject(error);
}
});
}
/**
* Execute a function in a separate thread based on the environment
*
* @param fn The function to execute
* @param args The arguments to pass to the function
* @returns A promise that resolves with the result of the function
*/
export function executeInThread<T>(fn: Function, ...args: any[]): Promise<T> {
if (isBrowser()) {
return executeInWebWorker<T>(fn, ...args);
} else if (isNode()) {
return executeInWorkerThread<T>(fn, ...args);
} else {
// Fall back to executing in the main thread
return Promise.resolve(fn(...args) as T);
}
}