UNPKG

@signalk/streams

Version:

Utilities for handling streams of Signal K data

131 lines 5.32 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const net_1 = __importDefault(require("net")); const stream_1 = require("stream"); const reconnect_core_1 = __importDefault(require("reconnect-core")); const BUFFER_LIMIT = process.env.BACKPRESSURE_ENTER ? parseInt(process.env.BACKPRESSURE_ENTER, 10) : 512 * 1024; class TcpStream extends stream_1.Transform { options; debug; debugData; static DEFAULT_TIMEOUT_SECONDS = 60; noDataReceivedTimeout; tcpStream; reconnector = null; constructor(options) { super(); this.options = options; const parsedTimeout = Number.parseInt((this.options.noDataReceivedTimeout + '').trim()); this.noDataReceivedTimeout = (isNaN(parsedTimeout) ? TcpStream.DEFAULT_TIMEOUT_SECONDS : parsedTimeout) * 1000; const createDebug = options.createDebug ?? require('debug'); this.debug = createDebug('signalk:streams:tcp'); this.debug(`noDataReceivedTimeout:${this.noDataReceivedTimeout}`); this.debugData = createDebug('signalk:streams:tcp-data'); } pipe(pipeTo) { if (this.options.outEvent) { this.options.app.on(this.options.outEvent, (d) => { if (this.tcpStream) { if (this.tcpStream.writableLength > BUFFER_LIMIT) { this.debug('outEvent write skipped, buffer full: %d', this.tcpStream.writableLength); return; } this.debug('sending %s', d); this.tcpStream.write(d); setImmediate(() => { this.options.app.emit('connectionwrite', { providerId: this.options.providerId }); }); } }); } const stdOutEvent = this.options.toStdout; if (stdOutEvent) { const events = Array.isArray(stdOutEvent) ? stdOutEvent : [stdOutEvent]; for (const stdEvent of events) { this.options.app.on(stdEvent, (d) => { if (this.tcpStream) { if (this.tcpStream.writableLength > BUFFER_LIMIT) { this.debug('toStdout write skipped for %s, buffer full: %d', stdEvent, this.tcpStream.writableLength); return; } this.tcpStream.write(d + '\r\n'); this.debug('event %s sending %s', stdEvent, d); } }); } } this.reconnector = (0, reconnect_core_1.default)((opts) => { return net_1.default.connect(opts); })({ maxDelay: 5 * 1000 }, (tcpStream) => { if (this.noDataReceivedTimeout > 0) { tcpStream.setTimeout(this.noDataReceivedTimeout); this.debug(`Setting socket idle timeout ${this.options.host}:${this.options.port} ${this.noDataReceivedTimeout}`); tcpStream.on('timeout', () => { this.debug(`Idle timeout, closing socket ${this.options.host}:${this.options.port}`); tcpStream.end(); }); } tcpStream.on('data', (data) => { if (this.debugData.enabled) { this.debugData(data.toString()); } this.write(data); }); }) .on('connect', (con) => { this.tcpStream = con; const msg = `Connected to ${this.options.host} ${this.options.port}`; this.options.app.setProviderStatus(this.options.providerId, msg); this.debug(msg); }) .on('reconnect', (n, delay) => { const msg = `Reconnect ${this.options.host} ${this.options.port} retry ${n} delay ${delay}`; this.options.app.setProviderError(this.options.providerId, msg); this.debug(msg); }) .on('disconnect', () => { this.tcpStream = undefined; const msg = `Disconnected ${this.options.host} ${this.options.port}`; this.options.app.setProviderError(this.options.providerId, msg); this.debug(msg); }) .on('error', (err) => { let msg; if (err.message && err.message.length > 0) { msg = err.message; } else if (err.errors) { msg = err.errors.toString(); } else { msg = err.toString(); } this.options.app.setProviderError(this.options.providerId, msg); console.error('TcpProvider:' + msg); }) .connect(this.options); super.pipe(pipeTo); return pipeTo; } end() { if (this.reconnector) { this.reconnector.disconnect(); } return this; } _transform(data, encoding, callback) { callback(null, data); } } exports.default = TcpStream; //# sourceMappingURL=tcp.js.map