All files / lib/internal socket_list.js

24.07% Statements 26/108
100% Branches 1/1
0% Functions 0/6
24.07% Lines 26/108

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 10992x 92x 92x 92x 92x 92x 92x 92x 92x           92x 92x                                           92x 92x           92x 92x                 92x 92x 92x 92x 92x 92x                                                                     92x 92x                   92x 92x 92x  
'use strict';
 
const { ERR_CHILD_CLOSED_BEFORE_REPLY } = require('internal/errors').codes;
 
const EventEmitter = require('events');
 
// This object keeps track of the sockets that are sent
class SocketListSend extends EventEmitter {
  constructor(child, key) {
    super();
    this.key = key;
    this.child = child;
    child.once('exit', () => this.emit('exit', this));
  }
 
  _request(msg, cmd, swallowErrors, callback) {
    const self = this;

    if (!this.child.connected) return onclose();
    this.child._send(msg, undefined, swallowErrors);

    function onclose() {
      self.child.removeListener('internalMessage', onreply);
      callback(new ERR_CHILD_CLOSED_BEFORE_REPLY());
    }

    function onreply(msg) {
      if (!(msg.cmd === cmd && msg.key === self.key)) return;
      self.child.removeListener('disconnect', onclose);
      self.child.removeListener('internalMessage', onreply);

      callback(null, msg);
    }

    this.child.once('disconnect', onclose);
    this.child.on('internalMessage', onreply);
  }
 
  close(callback) {
    this._request({
      cmd: 'NODE_SOCKET_NOTIFY_CLOSE',
      key: this.key
    }, 'NODE_SOCKET_ALL_CLOSED', true, callback);
  }
 
  getConnections(callback) {
    this._request({
      cmd: 'NODE_SOCKET_GET_COUNT',
      key: this.key
    }, 'NODE_SOCKET_COUNT', false, (err, msg) => {
      if (err) return callback(err);
      callback(null, msg.count);
    });
  }
}
 
 
// This object keeps track of the sockets that are received
class SocketListReceive extends EventEmitter {
  constructor(child, key) {
    super();

    this.connections = 0;
    this.key = key;
    this.child = child;

    function onempty(self) {
      if (!self.child.connected) return;

      self.child._send({
        cmd: 'NODE_SOCKET_ALL_CLOSED',
        key: self.key
      }, undefined, true);
    }

    this.child.on('internalMessage', (msg) => {
      if (msg.key !== this.key) return;

      if (msg.cmd === 'NODE_SOCKET_NOTIFY_CLOSE') {
        // Already empty
        if (this.connections === 0) return onempty(this);

        // Wait for sockets to get closed
        this.once('empty', onempty);
      } else if (msg.cmd === 'NODE_SOCKET_GET_COUNT') {
        if (!this.child.connected) return;
        this.child._send({
          cmd: 'NODE_SOCKET_COUNT',
          key: this.key,
          count: this.connections
        });
      }
    });
  }
 
  add(obj) {
    this.connections++;

    // Notify the previous owner of the socket about its state change
    obj.socket.once('close', () => {
      this.connections--;

      if (this.connections === 0) this.emit('empty', this);
    });
  }
}
 
module.exports = { SocketListSend, SocketListReceive };