UNPKG

@imqueue/core

Version:

Simple JSON-based messaging queue for inter service communication

173 lines 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /*! * UDP message listener for cluster managing: Worker for processing * messages * * I'm Queue Software Project * Copyright (C) 2025 imqueue.com <support@imqueue.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * If you want to use this code in a closed source (commercial) project, you can * purchase a proprietary commercial license. Please contact us at * <support@imqueue.com> to get commercial licensing options. */ const worker_threads_1 = require("worker_threads"); const dgram_1 = require("dgram"); const os_1 = require("os"); const uuid_1 = require("./uuid"); process.setMaxListeners(10000); var MessageType; (function (MessageType) { MessageType["Up"] = "up"; MessageType["Down"] = "down"; })(MessageType || (MessageType = {})); class UDPClusterWorker { constructor(options, messagePort) { this.options = options; this.messagePort = messagePort; this.servers = new Map(); this.setupMessageHandlers(); this.setupProcessHandlers(); this.socket = (0, dgram_1.createSocket)({ type: 'udp4', reuseAddr: true, reusePort: true, }).bind(this.options.port, this.selectNetworkInterface()); this.socket.on('message', message => this.processMessage(this.parseMessage(message))); } static getServerKey(message) { return message.id; } setupMessageHandlers() { this.messagePort.on('message', message => { if (message.type === 'stop') { this.stop(); } }); } setupProcessHandlers() { process.on('SIGTERM', this.cleanup); process.on('SIGINT', this.cleanup); process.on('SIGABRT', this.cleanup); } addServer(message) { this.messagePort.postMessage({ type: 'cluster:add', server: UDPClusterWorker.mapMessage(message), }); this.serverAliveWait(message); } removeServer(message) { this.servers.delete(UDPClusterWorker.getServerKey(message)); this.messagePort.postMessage({ type: 'cluster:remove', server: UDPClusterWorker.mapMessage(message), }); } static mapMessage(message) { return { id: message.id, name: message.name, type: message.type, host: message.host, port: message.port, timeout: message.timeout, }; } serverAliveWait(message) { var _a; const stamp = (0, uuid_1.uuid)(); const correction = (_a = this.options.aliveTimeoutCorrection) !== null && _a !== void 0 ? _a : 0; const effectiveTimeout = message.timeout + correction + 1; const key = UDPClusterWorker.getServerKey(message); this.servers.set(key, stamp); const t = setTimeout(() => setImmediate(() => { if (this.servers.get(key) === stamp) { this.removeServer(message); } }), effectiveTimeout); // Avoid keeping the event loop alive due to pending timers try { if (t && typeof t.unref === 'function') { t.unref(); } } catch ( /* ignore */_b) { /* ignore */ } } processMessage(message) { if (message.type === MessageType.Down) { return this.removeServer(message); } if (message.type === MessageType.Up) { return this.addServer(message); } } selectNetworkInterface() { const interfaces = (0, os_1.networkInterfaces)(); const broadcastAddress = this.options.address || this.options.limitedAddress; const defaultAddress = '0.0.0.0'; if (!broadcastAddress || broadcastAddress === this.options.limitedAddress) { return defaultAddress; } for (const key in interfaces) { if (!interfaces[key]) { continue; } for (const net of interfaces[key]) { const shouldBeSelected = net.family === 'IPv4' && net.address.startsWith(broadcastAddress.replace(/\.255/g, '')); if (shouldBeSelected) { return net.address; } } } return defaultAddress; } parseMessage(input) { const [name, id, type, address = '', timeout = '0',] = input.toString().split('\t'); const [host, port] = address.split(':'); return { id, name, type: type.toLowerCase(), host, port: parseInt(port), timeout: parseFloat(timeout) * 1000, }; } stop() { this.cleanup(); if (this.socket) { this.socket.close(() => { this.messagePort.postMessage({ type: 'stopped' }); }); return; } this.messagePort.postMessage({ type: 'stopped' }); } cleanup() { this.servers.clear(); if (this.socket) { this.socket.removeAllListeners(); } } } if (!worker_threads_1.isMainThread && worker_threads_1.parentPort) { new UDPClusterWorker(worker_threads_1.workerData, worker_threads_1.parentPort); } //# sourceMappingURL=UDPWorker.js.map