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