11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { InvalidArgumentError } = require('./core/errors')
41cb0ef41Sopenharmony_ciconst { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require('./core/symbols')
51cb0ef41Sopenharmony_ciconst DispatcherBase = require('./dispatcher-base')
61cb0ef41Sopenharmony_ciconst Pool = require('./pool')
71cb0ef41Sopenharmony_ciconst Client = require('./client')
81cb0ef41Sopenharmony_ciconst util = require('./core/util')
91cb0ef41Sopenharmony_ciconst createRedirectInterceptor = require('./interceptor/redirectInterceptor')
101cb0ef41Sopenharmony_ciconst { WeakRef, FinalizationRegistry } = require('./compat/dispatcher-weakref')()
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst kOnConnect = Symbol('onConnect')
131cb0ef41Sopenharmony_ciconst kOnDisconnect = Symbol('onDisconnect')
141cb0ef41Sopenharmony_ciconst kOnConnectionError = Symbol('onConnectionError')
151cb0ef41Sopenharmony_ciconst kMaxRedirections = Symbol('maxRedirections')
161cb0ef41Sopenharmony_ciconst kOnDrain = Symbol('onDrain')
171cb0ef41Sopenharmony_ciconst kFactory = Symbol('factory')
181cb0ef41Sopenharmony_ciconst kFinalizer = Symbol('finalizer')
191cb0ef41Sopenharmony_ciconst kOptions = Symbol('options')
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cifunction defaultFactory (origin, opts) {
221cb0ef41Sopenharmony_ci  return opts && opts.connections === 1
231cb0ef41Sopenharmony_ci    ? new Client(origin, opts)
241cb0ef41Sopenharmony_ci    : new Pool(origin, opts)
251cb0ef41Sopenharmony_ci}
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciclass Agent extends DispatcherBase {
281cb0ef41Sopenharmony_ci  constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
291cb0ef41Sopenharmony_ci    super()
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    if (typeof factory !== 'function') {
321cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('factory must be a function.')
331cb0ef41Sopenharmony_ci    }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci    if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') {
361cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('connect must be a function or an object')
371cb0ef41Sopenharmony_ci    }
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci    if (!Number.isInteger(maxRedirections) || maxRedirections < 0) {
401cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('maxRedirections must be a positive number')
411cb0ef41Sopenharmony_ci    }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    if (connect && typeof connect !== 'function') {
441cb0ef41Sopenharmony_ci      connect = { ...connect }
451cb0ef41Sopenharmony_ci    }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent)
481cb0ef41Sopenharmony_ci      ? options.interceptors.Agent
491cb0ef41Sopenharmony_ci      : [createRedirectInterceptor({ maxRedirections })]
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci    this[kOptions] = { ...util.deepClone(options), connect }
521cb0ef41Sopenharmony_ci    this[kOptions].interceptors = options.interceptors
531cb0ef41Sopenharmony_ci      ? { ...options.interceptors }
541cb0ef41Sopenharmony_ci      : undefined
551cb0ef41Sopenharmony_ci    this[kMaxRedirections] = maxRedirections
561cb0ef41Sopenharmony_ci    this[kFactory] = factory
571cb0ef41Sopenharmony_ci    this[kClients] = new Map()
581cb0ef41Sopenharmony_ci    this[kFinalizer] = new FinalizationRegistry(/* istanbul ignore next: gc is undeterministic */ key => {
591cb0ef41Sopenharmony_ci      const ref = this[kClients].get(key)
601cb0ef41Sopenharmony_ci      if (ref !== undefined && ref.deref() === undefined) {
611cb0ef41Sopenharmony_ci        this[kClients].delete(key)
621cb0ef41Sopenharmony_ci      }
631cb0ef41Sopenharmony_ci    })
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci    const agent = this
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    this[kOnDrain] = (origin, targets) => {
681cb0ef41Sopenharmony_ci      agent.emit('drain', origin, [agent, ...targets])
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    this[kOnConnect] = (origin, targets) => {
721cb0ef41Sopenharmony_ci      agent.emit('connect', origin, [agent, ...targets])
731cb0ef41Sopenharmony_ci    }
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    this[kOnDisconnect] = (origin, targets, err) => {
761cb0ef41Sopenharmony_ci      agent.emit('disconnect', origin, [agent, ...targets], err)
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    this[kOnConnectionError] = (origin, targets, err) => {
801cb0ef41Sopenharmony_ci      agent.emit('connectionError', origin, [agent, ...targets], err)
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  get [kRunning] () {
851cb0ef41Sopenharmony_ci    let ret = 0
861cb0ef41Sopenharmony_ci    for (const ref of this[kClients].values()) {
871cb0ef41Sopenharmony_ci      const client = ref.deref()
881cb0ef41Sopenharmony_ci      /* istanbul ignore next: gc is undeterministic */
891cb0ef41Sopenharmony_ci      if (client) {
901cb0ef41Sopenharmony_ci        ret += client[kRunning]
911cb0ef41Sopenharmony_ci      }
921cb0ef41Sopenharmony_ci    }
931cb0ef41Sopenharmony_ci    return ret
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  [kDispatch] (opts, handler) {
971cb0ef41Sopenharmony_ci    let key
981cb0ef41Sopenharmony_ci    if (opts.origin && (typeof opts.origin === 'string' || opts.origin instanceof URL)) {
991cb0ef41Sopenharmony_ci      key = String(opts.origin)
1001cb0ef41Sopenharmony_ci    } else {
1011cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.')
1021cb0ef41Sopenharmony_ci    }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    const ref = this[kClients].get(key)
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci    let dispatcher = ref ? ref.deref() : null
1071cb0ef41Sopenharmony_ci    if (!dispatcher) {
1081cb0ef41Sopenharmony_ci      dispatcher = this[kFactory](opts.origin, this[kOptions])
1091cb0ef41Sopenharmony_ci        .on('drain', this[kOnDrain])
1101cb0ef41Sopenharmony_ci        .on('connect', this[kOnConnect])
1111cb0ef41Sopenharmony_ci        .on('disconnect', this[kOnDisconnect])
1121cb0ef41Sopenharmony_ci        .on('connectionError', this[kOnConnectionError])
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci      this[kClients].set(key, new WeakRef(dispatcher))
1151cb0ef41Sopenharmony_ci      this[kFinalizer].register(dispatcher, key)
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    return dispatcher.dispatch(opts, handler)
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  async [kClose] () {
1221cb0ef41Sopenharmony_ci    const closePromises = []
1231cb0ef41Sopenharmony_ci    for (const ref of this[kClients].values()) {
1241cb0ef41Sopenharmony_ci      const client = ref.deref()
1251cb0ef41Sopenharmony_ci      /* istanbul ignore else: gc is undeterministic */
1261cb0ef41Sopenharmony_ci      if (client) {
1271cb0ef41Sopenharmony_ci        closePromises.push(client.close())
1281cb0ef41Sopenharmony_ci      }
1291cb0ef41Sopenharmony_ci    }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci    await Promise.all(closePromises)
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  async [kDestroy] (err) {
1351cb0ef41Sopenharmony_ci    const destroyPromises = []
1361cb0ef41Sopenharmony_ci    for (const ref of this[kClients].values()) {
1371cb0ef41Sopenharmony_ci      const client = ref.deref()
1381cb0ef41Sopenharmony_ci      /* istanbul ignore else: gc is undeterministic */
1391cb0ef41Sopenharmony_ci      if (client) {
1401cb0ef41Sopenharmony_ci        destroyPromises.push(client.destroy(err))
1411cb0ef41Sopenharmony_ci      }
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    await Promise.all(destroyPromises)
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_cimodule.exports = Agent
149