@bazilio-san/af-stream
Version:
Data stream from database table
196 lines • 7.2 kB
JavaScript
/* eslint-disable class-methods-use-this */
import * as net from 'net';
import { Buffer } from 'buffer';
import AbstractSender from './AbstractSender';
class TCPJSONSender extends AbstractSender {
constructor(options) {
super(options);
this.isReady = true;
this.socket = null;
}
async connect() {
const self = this;
const { echo, logger } = this.options;
const { port = -1, host = 'unknown' } = self.senderConfig;
return new Promise((resolve) => {
if (self.isConnected()) {
resolve(true);
return;
}
self.socket = new net.Socket();
const { socket } = self;
const msg = `(${host}:${port})`;
socket.on('error', (err) => {
const { code, message } = err;
if (code === 'ECONNREFUSED') {
echo.error(message);
}
else {
logger.error(err);
}
socket.destroy();
resolve(false);
});
socket.on('timeout', () => {
socket.destroy();
echo.error(`Timeout exceed ${msg}`);
resolve(false);
});
socket.on('close', (eee) => {
echo.info(`TCP connection closed: ${msg} ${eee}`);
});
socket.on('data', ( /* data */) => {
// console.log(`WSO2 Says : ${data}`);
});
socket.connect(port, host, () => {
echo.info(`
======================= TCP JSON Sender ========================
Connection established with ${msg}
================================================================`);
socket.setKeepAlive(true, 5000);
const { readyState } = socket;
if (readyState === 'open') {
return resolve(true);
}
echo.error(`readyState = ${readyState} ${msg}`);
resolve(false);
});
});
}
async reconnect() {
if (this.isConnected()) {
try {
this.shutdown();
}
catch (err) {
this.options.logger.error(err);
}
}
return this.connect();
}
async tryConnect() {
if (this.isConnected()) {
return true;
}
return this.connect();
}
isConnected() {
const { socket } = this;
return (socket === null || socket === void 0 ? void 0 : socket.readyState) === 'open'; // VVQ
}
shutdown() {
if (this.socket) {
this.socket.destroy();
}
}
canSendNext() {
return this.isReady && this.isConnected();
}
getTcpHeaderLength({ sessionId, streamId }) {
return 1 + 4 + 4 + Buffer.byteLength(sessionId) + 4 + Buffer.byteLength(streamId) + 4;
}
/**
* Encoding a JSON message containing 1 or more events into a buffer ready to be sent over TCP to WSO2
*/
encodeMessage(eventComposite) {
const { sessionId, streamId, json } = eventComposite;
if (!sessionId || !streamId || !json) {
return null;
}
const sessionIdSize = Buffer.byteLength(sessionId);
const streamIdSize = Buffer.byteLength(streamId);
const jsonSize = Buffer.byteLength(json);
const messageSize = 4 + sessionIdSize + 4 + streamIdSize + 4 + jsonSize;
const buffer = Buffer.alloc(5 + messageSize);
buffer.writeInt8(2);
let offset = 1;
buffer.writeUInt32BE(messageSize, offset);
offset += 4;
buffer.writeUInt32BE(sessionIdSize, offset);
offset += 4;
buffer.write(sessionId, offset);
offset += sessionIdSize;
buffer.writeUInt32BE(streamIdSize, offset);
offset += 4;
buffer.write(streamId, offset);
offset += streamIdSize;
buffer.writeUInt32BE(jsonSize, offset);
offset += 4;
buffer.write(json, offset);
return buffer;
}
/**
* Sending an event package to WSO2
*
* @return - buffer.length if the message has been sent, "false" otherwise
*/
async _sendEventsPacket(recordsComposite) {
var _a;
const { sessionId, streamId, eventsPacket } = recordsComposite;
const json = JSON.stringify(eventsPacket);
const buffer = this.encodeMessage({ sessionId, streamId, json });
const isConnected = await this.tryConnect();
if (!isConnected) {
return false;
}
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.write(buffer);
return (buffer === null || buffer === void 0 ? void 0 : buffer.length) || 0;
}
/**
* Sending events to WSO2
*/
async sendEvents(recordsComposite) {
const MAX_PACKET_SIZE = 32000;
const { streamId, eventsPacket, isSingleRecordAsObject, first } = recordsComposite;
if (!eventsPacket.length) {
return false;
}
let { sessionId } = recordsComposite;
if (!sessionId) {
sessionId = `sid${+(new Date())}`; // VVQ add \00\00 before sid
}
const MAX_DATA_SIZE = MAX_PACKET_SIZE - this.getTcpHeaderLength({ sessionId, streamId }) - 1;
let stop = false;
recordsComposite.sentBufferLength = 0;
recordsComposite.sendCount = 0;
recordsComposite.last = first;
while (!stop && eventsPacket.length > 0) {
let dataLen = 0;
let isEnough = false;
const packet = [];
while (!isEnough && eventsPacket.length) {
const itemLen = Buffer.byteLength(JSON.stringify(eventsPacket[0])) + 1;
if (dataLen + itemLen >= MAX_DATA_SIZE) {
isEnough = true;
}
else {
packet.push(eventsPacket.shift());
dataLen += itemLen;
}
}
const pl = packet.length;
if (pl) {
const data = {
dataLen,
sessionId,
streamId,
eventsPacket: pl === 1 && isSingleRecordAsObject ? packet[0] : packet,
};
// eslint-disable-next-line no-await-in-loop
const sentBufferLength = await this._sendEventsPacket(data);
stop = !sentBufferLength;
if (stop) {
eventsPacket.splice(0, 0, ...packet);
}
else {
recordsComposite.sentBufferLength += sentBufferLength;
recordsComposite.sendCount += pl;
recordsComposite.last = packet[pl - 1];
}
}
}
return true;
}
}
export default TCPJSONSender;
//# sourceMappingURL=TCPJSONSender.js.map