@signalk/streams
Version:
Utilities for handling streams of Signal K data
102 lines (101 loc) • 3.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const stream_1 = require("stream");
const canboatjs_1 = require("@canboat/canboatjs");
class Execute extends stream_1.Transform {
options;
debug;
childProcess;
pipeTo = null;
lastStartupTime = 0;
stopped = false;
constructor(options) {
super({});
this.options = options;
const createDebug = options.createDebug ?? require('debug');
this.debug = options.debug ?? createDebug('signalk:streams:execute');
}
_transform(chunk, encoding, done) {
this.childProcess.stdin?.write(chunk.toString());
done();
}
pipe(pipeTo) {
this.pipeTo = pipeTo;
this.startProcess(this.options.command);
const stdOutEvent = this.options.toChildProcess ?? 'toChildProcess';
this.debug('Using event ' + stdOutEvent + " for output to child process's stdin");
this.options.app.on(stdOutEvent, (d) => {
try {
this.childProcess.stdin?.write(d + '\n');
}
catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.log('execute:' + message);
}
});
if (stdOutEvent === 'nmea2000out') {
this.options.app.on('nmea2000JsonOut', (pgn) => {
this.childProcess.stdin?.write((0, canboatjs_1.pgnToActisenseSerialFormat)(pgn) + '\r\n');
});
this.options.app.emit('nmea2000OutAvailable');
}
super.pipe(pipeTo);
return pipeTo;
}
end() {
this.debug('end, killing child process');
this.stopped = true;
this.childProcess.kill();
if (this.pipeTo) {
this.pipeTo.end();
}
return this;
}
startProcess(command) {
this.debug(`starting |${command}|`);
if (process.platform === 'win32') {
this.childProcess = (0, child_process_1.spawn)('cmd', ['/c', command]);
}
else {
this.childProcess = (0, child_process_1.spawn)('sh', ['-c', command]);
}
this.lastStartupTime = Date.now();
this.options.app.setProviderStatus(this.options.providerId, 'Started');
this.childProcess.stderr?.on('data', (data) => {
const msg = data.toString();
this.options.app.setProviderError(this.options.providerId, msg);
console.error(msg);
});
this.childProcess.stdout?.on('data', (data) => {
if (this.debug.enabled) {
this.debug(data.toString());
}
this.push(data);
});
this.childProcess.on('close', (code) => {
const msg = `|${command}| exited with ${code}`;
console.error(msg);
if (this.stopped)
return;
if (this.options.restartOnClose === undefined ||
this.options.restartOnClose) {
const throttleTime = (this.options.restartThrottleTime ?? 60) * 1000;
const sinceLast = Date.now() - this.lastStartupTime;
if (sinceLast > throttleTime) {
this.startProcess(command);
}
else {
const nextStart = throttleTime - sinceLast;
const waitMsg = `Waiting ${nextStart / 1000} seconds to restart`;
this.options.app.setProviderStatus(this.options.providerId, waitMsg);
this.debug(waitMsg);
setTimeout(() => {
this.startProcess(command);
}, nextStart);
}
}
});
}
}
exports.default = Execute;