const logger = require('./logger.js'); const { spawn } = require('child_process'); const cmds = new Map(); async function execute(endpoint) { if (endpoint === undefined) { return; } if (endpoint.options?.unique && isCommandActive(endpoint)) { if (!endpoint.options?.restart) { logger.info('not executing unique command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') because it is already active'); throw new Error('command is already active'); } logger.info('killing and restarting unique command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')'); await killCommand(endpoint); } return new Promise((resolve, reject) => { logger.info('executing command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')...'); var cmd = spawn(endpoint.command, endpoint.args); cmd.timestamp = new Date().getTime(); let result = ''; let error = ''; cmd.stdout.on('data', (data) => { result += data; }); cmd.stderr.on('data', (data) => { error += data; }); cmd.on('spawn', () => { logger.info('spawned command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')'); addCommand(cmd, endpoint); if (endpoint.options?.detach) { resolve(); } }); cmd.on('error', (err) => { error += err; removeCommand(endpoint); if (endpoint.options?.detach) { reject(); } }); cmd.on('exit', (code) => { if (code === null) { code = 0; } removeCommand(endpoint); let fn = logger.info; let msg = 'command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - cmd.timestamp) + 'ms'; if (error !== undefined && error.length > 0) { error = error.trim(); msg += ' > error: ' + error; fn = logger.error; reject(error); } if (result !== undefined && result.length > 0) { result = result.trim(); msg += ' > data: ' + result; } fn(msg); resolve(result); }); }); } function addCommand(command, endpoint) { if (command === undefined || endpoint === undefined) { return; } cmds.set(endpoint, command); } function removeCommand(endpoint) { if (endpoint === undefined) { return; } cmds.delete(endpoint); } function isCommandActive(endpoint) { return endpoint !== undefined && cmds.has(endpoint); } async function killCommand(endpoint) { if (endpoint === undefined) { return; } const command = cmds.get(endpoint); if (command === undefined) { return; } process.kill(command.pid, 'SIGINT'); while(isCommandActive(endpoint)) { await sleep(100); } } async function sleep(milliseconds) { return new Promise((resolve, reject) => { setTimeout(resolve, milliseconds); }); } module.exports = { execute }