11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { ERR_CHILD_CLOSED_BEFORE_REPLY } = require('internal/errors').codes;
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst EventEmitter = require('events');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// This object keeps track of the sockets that are sent
81cb0ef41Sopenharmony_ciclass SocketListSend extends EventEmitter {
91cb0ef41Sopenharmony_ci  constructor(child, key) {
101cb0ef41Sopenharmony_ci    super();
111cb0ef41Sopenharmony_ci    this.key = key;
121cb0ef41Sopenharmony_ci    this.child = child;
131cb0ef41Sopenharmony_ci    child.once('exit', () => this.emit('exit', this));
141cb0ef41Sopenharmony_ci  }
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci  _request(msg, cmd, swallowErrors, callback) {
171cb0ef41Sopenharmony_ci    const self = this;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci    if (!this.child.connected) return onclose();
201cb0ef41Sopenharmony_ci    this.child._send(msg, undefined, swallowErrors);
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci    function onclose() {
231cb0ef41Sopenharmony_ci      self.child.removeListener('internalMessage', onreply);
241cb0ef41Sopenharmony_ci      callback(new ERR_CHILD_CLOSED_BEFORE_REPLY());
251cb0ef41Sopenharmony_ci    }
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci    function onreply(msg) {
281cb0ef41Sopenharmony_ci      if (!(msg.cmd === cmd && msg.key === self.key)) return;
291cb0ef41Sopenharmony_ci      self.child.removeListener('disconnect', onclose);
301cb0ef41Sopenharmony_ci      self.child.removeListener('internalMessage', onreply);
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci      callback(null, msg);
331cb0ef41Sopenharmony_ci    }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci    this.child.once('disconnect', onclose);
361cb0ef41Sopenharmony_ci    this.child.on('internalMessage', onreply);
371cb0ef41Sopenharmony_ci  }
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  close(callback) {
401cb0ef41Sopenharmony_ci    this._request({
411cb0ef41Sopenharmony_ci      cmd: 'NODE_SOCKET_NOTIFY_CLOSE',
421cb0ef41Sopenharmony_ci      key: this.key,
431cb0ef41Sopenharmony_ci    }, 'NODE_SOCKET_ALL_CLOSED', true, callback);
441cb0ef41Sopenharmony_ci  }
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  getConnections(callback) {
471cb0ef41Sopenharmony_ci    this._request({
481cb0ef41Sopenharmony_ci      cmd: 'NODE_SOCKET_GET_COUNT',
491cb0ef41Sopenharmony_ci      key: this.key,
501cb0ef41Sopenharmony_ci    }, 'NODE_SOCKET_COUNT', false, (err, msg) => {
511cb0ef41Sopenharmony_ci      if (err) return callback(err);
521cb0ef41Sopenharmony_ci      callback(null, msg.count);
531cb0ef41Sopenharmony_ci    });
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci// This object keeps track of the sockets that are received
591cb0ef41Sopenharmony_ciclass SocketListReceive extends EventEmitter {
601cb0ef41Sopenharmony_ci  constructor(child, key) {
611cb0ef41Sopenharmony_ci    super();
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    this.connections = 0;
641cb0ef41Sopenharmony_ci    this.key = key;
651cb0ef41Sopenharmony_ci    this.child = child;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    function onempty(self) {
681cb0ef41Sopenharmony_ci      if (!self.child.connected) return;
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci      self.child._send({
711cb0ef41Sopenharmony_ci        cmd: 'NODE_SOCKET_ALL_CLOSED',
721cb0ef41Sopenharmony_ci        key: self.key,
731cb0ef41Sopenharmony_ci      }, undefined, true);
741cb0ef41Sopenharmony_ci    }
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci    this.child.on('internalMessage', (msg) => {
771cb0ef41Sopenharmony_ci      if (msg.key !== this.key) return;
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci      if (msg.cmd === 'NODE_SOCKET_NOTIFY_CLOSE') {
801cb0ef41Sopenharmony_ci        // Already empty
811cb0ef41Sopenharmony_ci        if (this.connections === 0) return onempty(this);
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci        // Wait for sockets to get closed
841cb0ef41Sopenharmony_ci        this.once('empty', onempty);
851cb0ef41Sopenharmony_ci      } else if (msg.cmd === 'NODE_SOCKET_GET_COUNT') {
861cb0ef41Sopenharmony_ci        if (!this.child.connected) return;
871cb0ef41Sopenharmony_ci        this.child._send({
881cb0ef41Sopenharmony_ci          cmd: 'NODE_SOCKET_COUNT',
891cb0ef41Sopenharmony_ci          key: this.key,
901cb0ef41Sopenharmony_ci          count: this.connections,
911cb0ef41Sopenharmony_ci        });
921cb0ef41Sopenharmony_ci      }
931cb0ef41Sopenharmony_ci    });
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  add(obj) {
971cb0ef41Sopenharmony_ci    this.connections++;
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci    // Notify the previous owner of the socket about its state change
1001cb0ef41Sopenharmony_ci    obj.socket.once('close', () => {
1011cb0ef41Sopenharmony_ci      this.connections--;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci      if (this.connections === 0) this.emit('empty', this);
1041cb0ef41Sopenharmony_ci    });
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_cimodule.exports = { SocketListSend, SocketListReceive };
109