// Runs the Python/trimesh sidecar scripts one at a time. Loading a large mesh // can take hundreds of MB, so a preview conversion and background // fingerprinting never run at once. Jobs someone is waiting on (previews) go // ahead of queued background work. const path = require('path'); const { execFile } = require('child_process'); const PYTHON = process.env.PYTHON_BIN || path.join(__dirname, '..', 'tools', 'venv', 'bin', 'python'); const TOOLS = path.join(__dirname, '..', 'tools'); const urgent = []; const background = []; let busy = false; // Resolves { err, stdout, stderr } — never rejects, so callers can use partial // output from a run that failed part-way. function runScript(script, args, { timeout = 120000, isBackground = false } = {}) { return new Promise((resolve) => { (isBackground ? background : urgent).push({ script, args, timeout, resolve }); next(); }); } function next() { if (busy) return; const job = urgent.shift() || background.shift(); if (!job) return; busy = true; execFile( PYTHON, [path.join(TOOLS, job.script), ...job.args], { maxBuffer: 16 * 1024 * 1024, timeout: job.timeout }, (err, stdout, stderr) => { busy = false; job.resolve({ err, stdout: String(stdout || ''), stderr: String(stderr || '') }); next(); } ); } module.exports = { PYTHON, runScript };