import { createSocket } from "dgram"; import { debugDump } from "./HexUtil.js"; import { promisify } from "util"; import Logger from "./Logger.js"; export default class GlobalUdpSocket { constructor({port}) { this.socket = null; this.callbacks = new Set(); this.debuggingCallbacks = new Set(); this.logger = new Logger(); this.port = port; } async _getSocket() { if (!this.socket) { const udpSocket = createSocket({ type: 'udp4', reuseAddr: true }); udpSocket.unref(); udpSocket.on('message', (buffer, rinfo) => { const fromAddress = rinfo.address; const fromPort = rinfo.port; this.logger.debug(log => { log(fromAddress + ':' + fromPort + " <--UDP(" + this.port + ")"); log(debugDump(buffer)); }); for (const callback of this.callbacks) { callback(fromAddress, fromPort, buffer); } }); udpSocket.on('error', e => { this.logger.debug("UDP ERROR:", e); }); await promisify(udpSocket.bind).bind(udpSocket)(this.port); this.port = udpSocket.address().port; this.socket = udpSocket; } return this.socket; } async send(buffer, address, port, debug) { const socket = await this._getSocket(); if (debug) { this.logger._print(log => { log(address + ':' + port + " UDP(" + this.port + ")-->"); log(debugDump(buffer)); }); } await promisify(socket.send).bind(socket)(buffer,0,buffer.length,port,address); } addCallback(callback, debug) { this.callbacks.add(callback); if (debug) { this.debuggingCallbacks.add(callback); this.logger.debugEnabled = true; } } removeCallback(callback) { this.callbacks.delete(callback); this.debuggingCallbacks.delete(callback); this.logger.debugEnabled = this.debuggingCallbacks.size > 0; } }