135 lines
5.8 KiB
JavaScript
Executable File
135 lines
5.8 KiB
JavaScript
Executable File
const fs = require('fs');
|
|
const path = require('path');
|
|
const { exec } = require('child_process');
|
|
const { logSnapshot } = require('./log');
|
|
|
|
|
|
function snapshot(outDir, cam0, cam1, ws){
|
|
|
|
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
const picDate = Date.now();
|
|
const name0 = `snapshot_video0_${picDate}.jpg`;
|
|
const name1 = `snapshot_video1_${picDate}.jpg`;
|
|
cam0.snapshot(path.join(outDir, name0));
|
|
cam1.snapshot(path.join(outDir, name1));
|
|
|
|
|
|
strFile0 = path.join(outDir, name0);
|
|
strFile1 = path.join(outDir, name1);
|
|
|
|
const relUrl = `/snapshots/${name0}`;
|
|
const relUrlApp = `/snapshots/${name0.replace('.jpg','_two_cam_annotated.jpg')}`;
|
|
// The Python postprocessor writes an overlay named "_two_cam_overlay.png" and a CSV named "_two_cam.csv"
|
|
const relOverlay = `/snapshots/${name0.replace('.jpg','_two_cam_overlay.png')}`;
|
|
const relOverlayCSV = `/snapshots/${name0.replace('.jpg','_two_cam.csv')}`;
|
|
|
|
const annotatedPath = path.join(outDir, name0.replace('.jpg','_two_cam_annotated.jpg'));
|
|
const overlayPath = path.join(outDir, name0.replace('.jpg','_two_cam_overlay.png'));
|
|
const csvPath = path.join(outDir, name0.replace('.jpg','_two_cam.csv'));
|
|
|
|
|
|
|
|
const command = `python3 /usr/src/app/programs/readTwoImages.py -i ${strFile0} -i ${strFile1} -npz /usr/src/app/data/settings/callibration_cam0.npz -npz /usr/src/app/data/settings/callibration_cam1.npz -settings /usr/src/app/data/settings/settings.json`;
|
|
console.log("Executing Python " + command);
|
|
|
|
// Run the Python post-processing and send the snapshot response only
|
|
// after the annotated files are present to avoid transient 404s in the browser.
|
|
exec(command, (error, stdout, stderr) => {
|
|
try {
|
|
if (error) {
|
|
console.error(`Error: ${error.message}`);
|
|
// Capture which generated files actually exist for debugging
|
|
const files = {
|
|
annotated: fs.existsSync(annotatedPath),
|
|
overlay: fs.existsSync(overlayPath),
|
|
csv: fs.existsSync(csvPath)
|
|
};
|
|
// Log full details server-side for diagnosis
|
|
const detailed = {
|
|
type: 'snapshot',
|
|
ok: false,
|
|
error: error.message,
|
|
stdout: String(stdout).slice(0, 4096),
|
|
stderr: String(stderr).slice(0, 4096),
|
|
files
|
|
};
|
|
logSnapshot(command, JSON.stringify(detailed));
|
|
|
|
// Send a short, user-friendly error to the client (no large stdout/stderr)
|
|
const shortError = String(stderr || error.message || '').includes('Corrupt JPEG')
|
|
? 'postprocessor failed: corrupt JPEG input'
|
|
: 'postprocessor failed';
|
|
try { ws.send(JSON.stringify({ type: 'snapshot', ok: false, error: shortError })); } catch (e) {}
|
|
return;
|
|
}
|
|
|
|
if (stderr) {
|
|
// Log stderr but don't fail outright; sometimes tools output warnings on stderr.
|
|
if (String(stderr).trim()) console.error(`Stderr: ${stderr}`);
|
|
}
|
|
|
|
console.log(`Output:\n${stdout}`);
|
|
|
|
// Wait up to ~1s (10 * 100ms) for the generated files to appear on disk.
|
|
const waitForFiles = (paths, attempts = 10, delayMs = 100) => new Promise((resolve) => {
|
|
let tries = 0;
|
|
(function poll() {
|
|
const ok = paths.every(p => fs.existsSync(p));
|
|
if (ok || tries >= attempts) return resolve(ok);
|
|
tries++;
|
|
setTimeout(poll, delayMs);
|
|
})();
|
|
});
|
|
|
|
waitForFiles([annotatedPath, overlayPath, csvPath]).then((found) => {
|
|
if (!found) {
|
|
const files = {
|
|
annotated: fs.existsSync(annotatedPath),
|
|
overlay: fs.existsSync(overlayPath),
|
|
csv: fs.existsSync(csvPath)
|
|
};
|
|
// Log details server-side
|
|
const detailed = {
|
|
type: 'snapshot',
|
|
ok: false,
|
|
url: relUrl,
|
|
urlApp: relUrlApp,
|
|
overlay: relOverlay,
|
|
overlayCSV: relOverlayCSV,
|
|
files
|
|
};
|
|
logSnapshot(command, JSON.stringify(detailed));
|
|
// Send a concise error to the client
|
|
try { ws.send(JSON.stringify({ type: 'snapshot', ok: false, error: 'postprocessor incomplete (missing outputs)' })); } catch (e) {}
|
|
return;
|
|
}
|
|
|
|
const response = JSON.stringify({
|
|
type: 'snapshot',
|
|
ok: found,
|
|
url: relUrl,
|
|
urlApp: relUrlApp,
|
|
overlay: relOverlay,
|
|
overlayCSV: relOverlayCSV
|
|
});
|
|
logSnapshot(command, response);
|
|
try { ws.send(response); } catch (e) {}
|
|
}).catch((waitErr) => {
|
|
console.error('waitForFiles failed:', waitErr);
|
|
const response = JSON.stringify({ type: 'snapshot', ok: false, error: String(waitErr) });
|
|
logSnapshot(command, response);
|
|
try { ws.send(response); } catch (e) {}
|
|
});
|
|
} catch (handlerErr) {
|
|
console.error('snapshot handler error:', handlerErr);
|
|
const response = JSON.stringify({ type: 'snapshot', ok: false, error: String(handlerErr) });
|
|
logSnapshot(command, response);
|
|
try { ws.send(response); } catch (e) {}
|
|
}
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
module.exports = { snapshot }; |