@minimaltech/node-infra
Version:
Minimal Technology NodeJS Infrastructure - Loopback 4 Framework
156 lines • 6.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseNetworkTcpServer = void 0;
const base_helper_1 = require("../../base/base.helper");
const utilities_1 = require("../../utilities");
const date_utility_1 = require("../../utilities/date.utility");
const parse_utility_1 = require("../../utilities/parse.utility");
const omit_1 = __importDefault(require("lodash/omit"));
class BaseNetworkTcpServer extends base_helper_1.BaseHelper {
constructor(opts) {
var _a, _b, _c;
super({
scope: (_b = (_a = opts.scope) !== null && _a !== void 0 ? _a : opts.identifier) !== null && _b !== void 0 ? _b : BaseNetworkTcpServer.name,
identifier: opts.identifier,
});
this.serverOptions = {};
this.listenOptions = {};
this.clients = Object.assign({});
this.serverOptions = opts.serverOptions;
this.listenOptions = opts.listenOptions;
this.authenticateOptions = opts.authenticateOptions;
if (this.authenticateOptions.required &&
(!this.authenticateOptions.duration || this.authenticateOptions.duration < 0)) {
throw (0, utilities_1.getError)({
message: 'TCP Server | Invalid authenticate duration | Required duration for authenticateOptions',
});
}
this.extraEvents = (_c = opts.extraEvents) !== null && _c !== void 0 ? _c : {};
this.createServerFn = opts.createServerFn;
this.onServerReady = opts.onServerReady;
this.onClientConnected = opts.onClientConnected;
this.onClientData = opts.onClientData;
this.onClientClose = opts.onClientClose;
this.configure();
}
configure() {
this.server = this.createServerFn(this.serverOptions, socket => {
this.onNewConnection({ socket });
});
this.server.listen(this.listenOptions, () => {
var _a;
this.logger.info('[configure] TCP Socket Server is now listening | Options: %j', this.listenOptions);
(_a = this.onServerReady) === null || _a === void 0 ? void 0 : _a.call(this, { server: this.server });
});
}
onNewConnection(opts) {
var _a;
const { socket } = opts;
const id = (0, parse_utility_1.getUID)();
socket.on('data', (data) => {
var _a;
(_a = this.onClientData) === null || _a === void 0 ? void 0 : _a.call(this, { id, socket, data });
});
socket.on('error', (error) => {
var _a;
this.logger.error('[onClientConnect][error] ID: %s | Error: %s', id, error);
(_a = this.onClientError) === null || _a === void 0 ? void 0 : _a.call(this, { id, socket, error });
socket.end();
});
socket.on('close', (hasError) => {
var _a;
this.logger.info('[onClientConnect][close] ID: %s | hasError: %s', id, hasError);
(_a = this.onClientClose) === null || _a === void 0 ? void 0 : _a.call(this, { id, socket });
this.clients = (0, omit_1.default)(this.clients, [id]);
});
for (const extraEvent in this.extraEvents) {
socket.on(extraEvent, args => {
this.extraEvents[extraEvent]({ id, socket, args });
});
}
this.clients[id] = {
id,
socket,
state: this.authenticateOptions.required ? 'unauthorized' : 'authenticated',
subscriptions: new Set([]),
storage: {
connectedAt: (0, date_utility_1.dayjs)(),
authenticatedAt: this.authenticateOptions.required ? null : (0, date_utility_1.dayjs)(),
},
};
this.logger.info('[onClientConnect] New TCP SocketClient | Client: %s | authenticateOptions: %s %s', `${id} - ${socket.remoteAddress} - ${socket.remotePort} - ${socket.remoteFamily}`, this.authenticateOptions.required, this.authenticateOptions.duration);
(_a = this.onClientConnected) === null || _a === void 0 ? void 0 : _a.call(this, { id, socket });
// Check client authentication
if (this.authenticateOptions.required &&
this.authenticateOptions.duration &&
this.authenticateOptions.duration > 0) {
setTimeout(() => {
const client = this.getClient({ id });
if (!client) {
return;
}
if (client.state === 'authenticated') {
return;
}
this.emit({ clientId: id, payload: 'Unauthorized Client' });
client.socket.end();
}, this.authenticateOptions.duration);
}
}
getClients() {
return this.clients;
}
getClient(opts) {
var _a;
return (_a = this.clients) === null || _a === void 0 ? void 0 : _a[opts.id];
}
getServer() {
return this.server;
}
doAuthenticate(opts) {
const { id, state } = opts;
const client = this.getClient({ id });
if (!client) {
this.logger.error('[authenticateClient][%s] Client %s NOT FOUND', id);
return;
}
client.state = state;
switch (state) {
case 'unauthorized':
case 'authenticating': {
client.storage.authenticatedAt = null;
break;
}
case 'authenticated': {
client.storage.authenticatedAt = (0, date_utility_1.dayjs)();
break;
}
default: {
break;
}
}
}
emit(opts) {
const { clientId, payload } = opts;
const client = this.getClient({ id: clientId });
if (!client) {
this.logger.error('[emit][%s] Client %s NOT FOUND', clientId);
return;
}
const { socket } = client;
if (!socket.writable) {
this.logger.error('[emit][%s] Client %s NOT WRITABLE', clientId);
return;
}
if (!(payload === null || payload === void 0 ? void 0 : payload.length)) {
this.logger.info('[emit][%s] Client %s | Invalid payload to write to TCP Socket!', this.identifier, clientId);
return;
}
socket.write(payload);
}
}
exports.BaseNetworkTcpServer = BaseNetworkTcpServer;
//# sourceMappingURL=base-tcp-server.helper.js.map