domotz-remote-pawn
Version:
Domotz Agent
136 lines (117 loc) • 4.41 kB
JavaScript
/** 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;
module.exports = function(index, childProcess) {
var name = 'EXECUTOR - (' + index + '):',
queue = [],
current = null;
function getCmdForLog(command, args, options) {
return command + (args ? ' ' + args.join(' ') + '' : '') + (options ? '. Options: ' + JSON.stringify(options) : '');
}
function resolve(deferred, response, id) {
deferred.resolve(response);
clearTimeout(id);
dequeue();
}
function reject(deferred, error, id) {
deferred.reject(error);
clearTimeout(id);
dequeue();
}
function enqueue(task) {
console.silly(name + ' Enqueue');
queue.push(task);
if (!current) {
dequeue();
}
}
function dequeue() {
console.silly(name + ' Dequeue');
current = queue.shift();
if (!current) {
console.debug(name + ' Empty queue.');
return;
}
var deferred = current[PROMISE],
command = current[COMMAND],
args = current[ARGS],
options = current[OPTIONS],
timeout = options ? options.timeout || options.ttl : null,
id = null,
err = null,
stdout = '',
stderr = '',
descr = getCmdForLog(command, args, options),
child = childProcess.spawn(command, args, options);
console.info('%s $> %s', name, descr);
if (timeout) {
console.debug('%s Set timeout to %s. Spawned child pid: %s. Path: %s',
name, timeout, child.pid, process.env.PATH);
id = setTimeout(function () {
console.verbose('Timeout expired for process: %d', child.pid);
child.kill();
err = new Error(name + ' - Process "' + descr +
'" killed after timeout: ' + timeout);
reject(deferred, err, id);
}, timeout);
} else {
console.debug('%s Spawned child pid: %s. Path: %s',
name, child.pid, process.env.PATH);
}
child.stdout.on('data', function (data) {
stdout += data;
});
child.stderr.on('data', function (data) {
stderr += data;
});
child.on('error', function (err) {
console.warn(name + ' Process "' + descr + '" exited with unexpected error');
reject(deferred, err, id);
});
child.on('close', function (code) {
console.verbose(name + ' Process "' + descr + '" terminates with code: ' + code);
console.silly('STDOUT: ' + stdout);
console.silly('STDERR: ' + stderr);
if (code !== 0) {
console.alert(name + ' Process "' + descr + '" exited with code: ' + code);
err = new Error(code);
} else if (stderr && !stdout) {
var msg = stderr.toString('utf8').trim();
console.alert(name + ' Process "' + descr + '" ' + msg);
err = new Error(msg);
}
if (err) {
reject(deferred, err, id);
} else {
resolve(deferred, stdout.toString('utf8').trim(), id);
}
});
}
function status() {
var length = queue.length;
return current ? length + 1 : length;
}
this.enqueue = enqueue;
this.dequeue = dequeue;
this.status = status;
};