• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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