UNPKG

domotz-remote-pawn

Version:

Domotz Agent

176 lines (155 loc) 5.96 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz Ltd * * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * * Created by Tommaso Latini <tommaso@domotz.com> on 20/09/16. */ const PROMISE = 0; const COMMAND = 1; const ARGS = 2; const OPTIONS = 3; const SPAWN_HARD_TIMEOUT = 180000; var startTime; module.exports = function (index, childProcess, lodash, myConsole) { var prefix = 'EXECUTOR - (' + index + '):', queue = [], current = null; function describe(command, args, options) { return command + (args ? ' ' + args.join(' ') + '' : '') + (options ? '. Options: ' + JSON.stringify(options) : ''); } function finalize(id) { clearTimeout(id); dequeue(); } function resolve(deferred, response, id) { deferred.resolve(response); finalize(id); } function reject(deferred, error, id) { deferred.reject(error); finalize(id); } function enqueue(task) { queue.push(task); if (!current) { dequeue(); } } function dequeue() { current = queue.shift(); if (!current) { myConsole.verbose('%s Empty queue.', prefix); return; } var options = current[OPTIONS] || {}; var timeOut; if (options.timeout === undefined && options.ttl === undefined) { timeOut = SPAWN_HARD_TIMEOUT; } else { timeOut = options.timeout || options.ttl || null; } var deferred = current[PROMISE], command = current[COMMAND], args = current[ARGS] || [], description = (options && options.description) || describe(command, args, options), id = null, err = null, stdout = '', stderr = '', pid = undefined, child = undefined; try { startTime = new Date(); child = childProcess.spawn(command, args, options); pid = child.pid; } catch (err) { myConsole.warn('%s Process pid:%s "%s" exited with unexpected error', prefix, pid, description); reject(deferred, err.stack, undefined); return; } if (child) { if (timeOut) { myConsole.debug('%s pid:%s Set timeOut %s to %s', prefix, pid, timeOut, description); id = setTimeout(function () { myConsole.debug('Timeout expired for pid:%s', pid); child.kill(); err = new Error(prefix + ' - Process "' + description + '" killed after timeout: ' + timeOut); reject(deferred, err, id); }, timeOut); } else { myConsole.info('%s Spawned child pid: %s. Path: %s', prefix, pid, description); } if (child.stdout) { child.stdout.on('data', function (data) { stdout += data; if (options.onStdout) { options.onStdout(data, deferred); } }); } if (child.stderr) { child.stderr.on('data', function (data) { stderr += data; if (options.onStderr) { options.onStderr(data, deferred); } }); } child.on('error', function (err) { myConsole.warn('%s Process pid:%s "%s" exited with unexpected error', prefix, pid, description); reject(deferred, err, id); }); child.on('close', function (code) { var duration = new Date() - startTime; myConsole.debug('%s Process with pid:%s exited after %dms', prefix, pid, duration); if (stdout.length > 0) { myConsole.verbose('%s pid:%s STDOUT: %s ', prefix, pid, stdout); } if (stderr.length > 0) { myConsole.verbose('%s pid:%s STDERR: %s ', prefix, pid, stderr); } if (code !== 0 || (stderr && !stdout)) { stderr = stderr.toString().trim(); err = new Error(stderr); err.code = code; err.message = stderr || stdout; myConsole.error('%s Process with pid:%s "%s" exited with code: %s. "%s"', prefix, pid, description, code, stderr); reject(deferred, err, id); } else { stdout = stdout.toString().trim(); resolve(deferred, stdout, id); } }); } } function status() { var length = queue.length; if (current) { var processTimeout = lodash.get(current, '[' + OPTIONS + '].timeout', undefined); if (processTimeout === null) { myConsole.debug('%s Executor %s is busy with long running process', prefix, index); return null; } } return current ? length + 1 : length; } function getIndex() { return index; } this.enqueue = enqueue; this.dequeue = dequeue; this.status = status; this.getIndex = getIndex; };