import path from 'path'; import { Worker } from 'worker_threads'; const WORKER_PATH = path.resolve(process.cwd(), 'assets/app/workers/unionWorker.js'); // The app's own npm dependencies (installed by `meteor build`) live in // programs/server/npm/node_modules — a directory that's a SIBLING of // programs/server/assets, not an ancestor of it. Node's require() only walks // up parent directories looking for node_modules, so a plain // require('@turf/circle') from the worker script (a raw asset, not part of // Meteor's own module system that knows about this layout) can never find it // and fails with "Cannot find module '@turf/circle'". Resolving the absolute // path here, where Meteor's own module system already knows how to find it, // and handing it to the worker sidesteps that entirely. const NPM_MODULES = path.resolve(process.cwd(), 'npm/node_modules'); const turfPaths = { circle: path.join(NPM_MODULES, '@turf/circle'), union: path.join(NPM_MODULES, '@turf/union'), truncate: path.join(NPM_MODULES, '@turf/truncate') }; /** * Circle-union of already-validated, already-decorated subscriptions, run in a * worker thread so the main event loop (DDP/HTTP) stays free regardless of * how long any single turf.union call takes. subs must be an array of plain * { location: { lat, lon }, distance } objects. If baseUnion is given, subs * are merged into it instead of a union computed from scratch. */ const calcUnionAsync = (subs, baseUnion = null) => new Promise((resolve, reject) => { const worker = new Worker(WORKER_PATH, { workerData: { subs, baseUnion, turfPaths } }); worker.once('message', (msg) => { worker.terminate(); if (msg.error) { reject(new Error(msg.error)); } else { resolve(msg.union); } }); worker.once('error', (err) => { worker.terminate(); reject(err); }); }); export default calcUnionAsync;