"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.connectInParallel = connectInParallel;
exports.connectInSequence = connectInSequence;
exports.lookupAllAddresses = lookupAllAddresses;
var _net = _interopRequireDefault(require("net"));
var _nodeUrl = _interopRequireDefault(require("node:url"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
async function connectInParallel(options, lookup, signal) {
  signal.throwIfAborted();
  const addresses = await lookupAllAddresses(options.host, lookup, signal);
  return await new Promise((resolve, reject) => {
    const sockets = new Array(addresses.length);
    const errors = [];
    function onError(err) {
      errors.push(err);
      this.removeListener('error', onError);
      this.removeListener('connect', onConnect);
      this.destroy();
      if (errors.length === addresses.length) {
        signal.removeEventListener('abort', onAbort);
        reject(new AggregateError(errors, 'Could not connect (parallel)'));
      }
    }
    function onConnect() {
      signal.removeEventListener('abort', onAbort);
      for (let j = 0; j < sockets.length; j++) {
        const socket = sockets[j];
        if (this === socket) {
          continue;
        }
        socket.removeListener('error', onError);
        socket.removeListener('connect', onConnect);
        socket.destroy();
      }
      resolve(this);
    }
    const onAbort = () => {
      for (let j = 0; j < sockets.length; j++) {
        const socket = sockets[j];
        socket.removeListener('error', onError);
        socket.removeListener('connect', onConnect);
        socket.destroy();
      }
      reject(signal.reason);
    };
    for (let i = 0, len = addresses.length; i < len; i++) {
      const socket = sockets[i] = _net.default.connect({
        ...options,
        host: addresses[i].address,
        family: addresses[i].family
      });
      socket.on('error', onError);
      socket.on('connect', onConnect);
    }
    signal.addEventListener('abort', onAbort, {
      once: true
    });
  });
}
async function connectInSequence(options, lookup, signal) {
  signal.throwIfAborted();
  const errors = [];
  const addresses = await lookupAllAddresses(options.host, lookup, signal);
  for (const address of addresses) {
    try {
      return await new Promise((resolve, reject) => {
        const socket = _net.default.connect({
          ...options,
          host: address.address,
          family: address.family
        });
        const onAbort = () => {
          socket.removeListener('error', onError);
          socket.removeListener('connect', onConnect);
          socket.destroy();
          reject(signal.reason);
        };
        const onError = err => {
          signal.removeEventListener('abort', onAbort);
          socket.removeListener('error', onError);
          socket.removeListener('connect', onConnect);
          socket.destroy();
          reject(err);
        };
        const onConnect = () => {
          signal.removeEventListener('abort', onAbort);
          socket.removeListener('error', onError);
          socket.removeListener('connect', onConnect);
          resolve(socket);
        };
        signal.addEventListener('abort', onAbort, {
          once: true
        });
        socket.on('error', onError);
        socket.on('connect', onConnect);
      });
    } catch (err) {
      // If the signal was aborted, re-throw the error.
      signal.throwIfAborted();
      errors.push(err);
      continue;
    }
  }
  throw new AggregateError(errors, 'Could not connect (sequence)');
}

/**
 * Look up all addresses for the given hostname.
 */
async function lookupAllAddresses(host, lookup, signal) {
  signal.throwIfAborted();
  if (_net.default.isIPv6(host)) {
    return [{
      address: host,
      family: 6
    }];
  } else if (_net.default.isIPv4(host)) {
    return [{
      address: host,
      family: 4
    }];
  } else {
    return await new Promise((resolve, reject) => {
      const onAbort = () => {
        reject(signal.reason);
      };
      signal.addEventListener('abort', onAbort);
      const domainInASCII = _nodeUrl.default.domainToASCII(host);
      lookup(domainInASCII === '' ? host : domainInASCII, {
        all: true
      }, (err, addresses) => {
        signal.removeEventListener('abort', onAbort);
        err ? reject(err) : resolve(addresses);
      });
    });
  }
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 13396 characters]