1'use strict'; 2 3const { ERR_CHILD_CLOSED_BEFORE_REPLY } = require('internal/errors').codes; 4 5const EventEmitter = require('events'); 6 7// This object keeps track of the sockets that are sent 8class SocketListSend extends EventEmitter { 9 constructor(child, key) { 10 super(); 11 this.key = key; 12 this.child = child; 13 child.once('exit', () => this.emit('exit', this)); 14 } 15 16 _request(msg, cmd, swallowErrors, callback) { 17 const self = this; 18 19 if (!this.child.connected) return onclose(); 20 this.child._send(msg, undefined, swallowErrors); 21 22 function onclose() { 23 self.child.removeListener('internalMessage', onreply); 24 callback(new ERR_CHILD_CLOSED_BEFORE_REPLY()); 25 } 26 27 function onreply(msg) { 28 if (!(msg.cmd === cmd && msg.key === self.key)) return; 29 self.child.removeListener('disconnect', onclose); 30 self.child.removeListener('internalMessage', onreply); 31 32 callback(null, msg); 33 } 34 35 this.child.once('disconnect', onclose); 36 this.child.on('internalMessage', onreply); 37 } 38 39 close(callback) { 40 this._request({ 41 cmd: 'NODE_SOCKET_NOTIFY_CLOSE', 42 key: this.key 43 }, 'NODE_SOCKET_ALL_CLOSED', true, callback); 44 } 45 46 getConnections(callback) { 47 this._request({ 48 cmd: 'NODE_SOCKET_GET_COUNT', 49 key: this.key 50 }, 'NODE_SOCKET_COUNT', false, (err, msg) => { 51 if (err) return callback(err); 52 callback(null, msg.count); 53 }); 54 } 55} 56 57 58// This object keeps track of the sockets that are received 59class SocketListReceive extends EventEmitter { 60 constructor(child, key) { 61 super(); 62 63 this.connections = 0; 64 this.key = key; 65 this.child = child; 66 67 function onempty(self) { 68 if (!self.child.connected) return; 69 70 self.child._send({ 71 cmd: 'NODE_SOCKET_ALL_CLOSED', 72 key: self.key 73 }, undefined, true); 74 } 75 76 this.child.on('internalMessage', (msg) => { 77 if (msg.key !== this.key) return; 78 79 if (msg.cmd === 'NODE_SOCKET_NOTIFY_CLOSE') { 80 // Already empty 81 if (this.connections === 0) return onempty(this); 82 83 // Wait for sockets to get closed 84 this.once('empty', onempty); 85 } else if (msg.cmd === 'NODE_SOCKET_GET_COUNT') { 86 if (!this.child.connected) return; 87 this.child._send({ 88 cmd: 'NODE_SOCKET_COUNT', 89 key: this.key, 90 count: this.connections 91 }); 92 } 93 }); 94 } 95 96 add(obj) { 97 this.connections++; 98 99 // Notify the previous owner of the socket about its state change 100 obj.socket.once('close', () => { 101 this.connections--; 102 103 if (this.connections === 0) this.emit('empty', this); 104 }); 105 } 106} 107 108module.exports = { SocketListSend, SocketListReceive }; 109