moleculer
Version:
Fast & powerful microservices framework for Node.JS
152 lines (123 loc) • 3.16 kB
JavaScript
/*
* moleculer
* Copyright (c) 2023 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/
"use strict";
const net = require("net");
const EventEmitter = require("events");
const Parser = require("./parser");
/**
* Import types
*
* @typedef {import("./tcp-reader")} TcpReaderClass
* @typedef {import("net").Socket} Socket
*/
/**
* TCP Reader for TcpTransporter
*
* @class TcpReader
* @extends {EventEmitter}
* @implements {TcpReaderClass}
*/
class TcpReader extends EventEmitter {
/**
* Creates an instance of TcpReader.
*
* @param {any} transporter
* @param {any} opts
* @memberof TcpReader
*/
constructor(transporter, opts) {
super();
this.server = null;
this.opts = opts;
this.transporter = transporter;
this.Promise = transporter.broker.Promise;
this.logger = transporter.logger;
this.sockets = [];
}
/**
* Listening a TCP port
*
* @returns {Promise}
* @memberof TcpReader
*/
listen() {
return new this.Promise((resolve, reject) => {
const server = net.createServer(socket => this.onTcpClientConnected(socket));
server.on("error", err => {
this.logger.error("Server error.", err);
if (reject) reject(err);
});
const h = { port: this.opts.port, exclusive: true };
// Listening
server.listen(h, () => {
this.opts.port = /** @type {import("net").AddressInfo} */ (
this.server.address()
).port;
this.logger.info(`TCP server is listening on port ${this.opts.port}`);
this.connected = true;
resolve(this.opts.port);
reject = null;
});
this.server = server;
});
}
/**
* New TCP socket is received.
*
* @param {Socket} socket
* @memberof TcpReader
*/
onTcpClientConnected(socket) {
this.sockets.push(socket);
socket.setNoDelay(true);
const address = socket.remoteAddress;
//this.logger.info(address);
this.logger.debug(`New TCP client connected from '${address}'`);
const parser = new Parser(undefined, this.opts.maxPacketSize);
socket.pipe(parser);
parser.on("data", (type, message) => {
//this.logger.info(`TCP data received from '${address}'. Type:`, type);
//this.logger.info(message.toString());
this.transporter.onIncomingMessage(type, message, socket);
});
parser.on("error", err => {
this.logger.warn("Packet parser error!", err);
this.closeSocket(socket);
});
socket.on("error", err => {
this.logger.debug(`TCP client '${address}' error!`, err);
this.closeSocket(socket);
});
socket.on("close", hadError => {
this.logger.debug(`TCP client disconnected from '${address}'! Had error:`, !!hadError);
this.closeSocket(socket);
});
this.emit("connect", socket);
}
/**
* Close a client socket
*
* @param {Socket} socket
*/
closeSocket(socket) {
socket.destroy();
this.sockets.splice(this.sockets.indexOf(socket), 1);
}
/**
* Close the TCP server.
*
* @memberof TcpReader
*/
close() {
if (this.server && this.server.listening) {
this.server.close();
// Close all live sockets
this.sockets.forEach(socket => socket.destroy());
this.sockets = [];
}
}
}
module.exports = TcpReader;