UNPKG

@signalk/streams

Version:

Utilities for handling streams of Signal K data

102 lines (101 loc) 3.82 kB
"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;