@signalk/streams
Version:
Utilities for handling streams of Signal K data
131 lines • 5.32 kB
JavaScript
"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