source: node_modules/undici/lib/agent.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 4.5 KB
Line 
1'use strict'
2
3const { InvalidArgumentError } = require('./core/errors')
4const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require('./core/symbols')
5const DispatcherBase = require('./dispatcher-base')
6const Pool = require('./pool')
7const Client = require('./client')
8const util = require('./core/util')
9const createRedirectInterceptor = require('./interceptor/redirectInterceptor')
10const { WeakRef, FinalizationRegistry } = require('./compat/dispatcher-weakref')()
11
12const kOnConnect = Symbol('onConnect')
13const kOnDisconnect = Symbol('onDisconnect')
14const kOnConnectionError = Symbol('onConnectionError')
15const kMaxRedirections = Symbol('maxRedirections')
16const kOnDrain = Symbol('onDrain')
17const kFactory = Symbol('factory')
18const kFinalizer = Symbol('finalizer')
19const kOptions = Symbol('options')
20
21function defaultFactory (origin, opts) {
22 return opts && opts.connections === 1
23 ? new Client(origin, opts)
24 : new Pool(origin, opts)
25}
26
27class Agent extends DispatcherBase {
28 constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
29 super()
30
31 if (typeof factory !== 'function') {
32 throw new InvalidArgumentError('factory must be a function.')
33 }
34
35 if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') {
36 throw new InvalidArgumentError('connect must be a function or an object')
37 }
38
39 if (!Number.isInteger(maxRedirections) || maxRedirections < 0) {
40 throw new InvalidArgumentError('maxRedirections must be a positive number')
41 }
42
43 if (connect && typeof connect !== 'function') {
44 connect = { ...connect }
45 }
46
47 this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent)
48 ? options.interceptors.Agent
49 : [createRedirectInterceptor({ maxRedirections })]
50
51 this[kOptions] = { ...util.deepClone(options), connect }
52 this[kOptions].interceptors = options.interceptors
53 ? { ...options.interceptors }
54 : undefined
55 this[kMaxRedirections] = maxRedirections
56 this[kFactory] = factory
57 this[kClients] = new Map()
58 this[kFinalizer] = new FinalizationRegistry(/* istanbul ignore next: gc is undeterministic */ key => {
59 const ref = this[kClients].get(key)
60 if (ref !== undefined && ref.deref() === undefined) {
61 this[kClients].delete(key)
62 }
63 })
64
65 const agent = this
66
67 this[kOnDrain] = (origin, targets) => {
68 agent.emit('drain', origin, [agent, ...targets])
69 }
70
71 this[kOnConnect] = (origin, targets) => {
72 agent.emit('connect', origin, [agent, ...targets])
73 }
74
75 this[kOnDisconnect] = (origin, targets, err) => {
76 agent.emit('disconnect', origin, [agent, ...targets], err)
77 }
78
79 this[kOnConnectionError] = (origin, targets, err) => {
80 agent.emit('connectionError', origin, [agent, ...targets], err)
81 }
82 }
83
84 get [kRunning] () {
85 let ret = 0
86 for (const ref of this[kClients].values()) {
87 const client = ref.deref()
88 /* istanbul ignore next: gc is undeterministic */
89 if (client) {
90 ret += client[kRunning]
91 }
92 }
93 return ret
94 }
95
96 [kDispatch] (opts, handler) {
97 let key
98 if (opts.origin && (typeof opts.origin === 'string' || opts.origin instanceof URL)) {
99 key = String(opts.origin)
100 } else {
101 throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.')
102 }
103
104 const ref = this[kClients].get(key)
105
106 let dispatcher = ref ? ref.deref() : null
107 if (!dispatcher) {
108 dispatcher = this[kFactory](opts.origin, this[kOptions])
109 .on('drain', this[kOnDrain])
110 .on('connect', this[kOnConnect])
111 .on('disconnect', this[kOnDisconnect])
112 .on('connectionError', this[kOnConnectionError])
113
114 this[kClients].set(key, new WeakRef(dispatcher))
115 this[kFinalizer].register(dispatcher, key)
116 }
117
118 return dispatcher.dispatch(opts, handler)
119 }
120
121 async [kClose] () {
122 const closePromises = []
123 for (const ref of this[kClients].values()) {
124 const client = ref.deref()
125 /* istanbul ignore else: gc is undeterministic */
126 if (client) {
127 closePromises.push(client.close())
128 }
129 }
130
131 await Promise.all(closePromises)
132 }
133
134 async [kDestroy] (err) {
135 const destroyPromises = []
136 for (const ref of this[kClients].values()) {
137 const client = ref.deref()
138 /* istanbul ignore else: gc is undeterministic */
139 if (client) {
140 destroyPromises.push(client.destroy(err))
141 }
142 }
143
144 await Promise.all(destroyPromises)
145 }
146}
147
148module.exports = Agent
Note: See TracBrowser for help on using the repository browser.