'use strict'; const { internalBinding } = require('internal/test/binding'); const { JSUDPWrap } = internalBinding('js_udp_wrap'); const EventEmitter = require('events'); // FakeUDPWrap is a testing utility that emulates a UDP connection // for the sake of making UDP tests more deterministic. class FakeUDPWrap extends EventEmitter { constructor() { super(); this._handle = new JSUDPWrap(); this._handle.onreadstart = () => this._startReading(); this._handle.onreadstop = () => this._stopReading(); this._handle.onwrite = (wrap, buffers, addr) => this._write(wrap, buffers, addr); this._handle.getsockname = (obj) => { Object.assign(obj, { address: '127.0.0.1', family: 'IPv4', port: 1337 }); return 0; }; this.reading = false; this.bufferedReceived = []; this.emitBufferedImmediate = null; } _emitBuffered = () => { if (!this.reading) return; if (this.bufferedReceived.length > 0) { this.emitReceived(this.bufferedReceived.shift()); this.emitBufferedImmediate = setImmediate(this._emitBuffered); } else { this.emit('wantRead'); } }; _startReading() { this.reading = true; this.emitBufferedImmediate = setImmediate(this._emitBuffered); } _stopReading() { this.reading = false; clearImmediate(this.emitBufferedImmediate); } _write(wrap, buffers, addr) { this.emit('send', { buffers, addr }); setImmediate(() => this._handle.onSendDone(wrap, 0)); } afterBind() { this._handle.onAfterBind(); } emitReceived(info) { if (!this.reading) { this.bufferedReceived.push(info); return; } const { buffers, addr: { family = 4, address = '127.0.0.1', port = 1337, }, flags = 0, } = info; let familyInt; switch (family) { case 'IPv4': familyInt = 4; break; case 'IPv6': familyInt = 6; break; default: throw new Error('bad family'); } for (const buffer of buffers) { this._handle.emitReceived(buffer, familyInt, address, port, flags); } } } function makeUDPPair() { const serverSide = new FakeUDPWrap(); const clientSide = new FakeUDPWrap(); serverSide.on('send', (chk) => setImmediate(() => clientSide.emitReceived(chk))); clientSide.on('send', (chk) => setImmediate(() => serverSide.emitReceived(chk))); return { serverSide, clientSide }; } module.exports = { FakeUDPWrap, makeUDPPair, };