codekingpro/portable-devtools
114k
1'use strict'
2
3const {
4 PoolBase,
5 kClients,
6 kNeedDrain,
7 kAddClient,
8 kGetDispatcher
9} = require('./pool-base')
10const Client = require('./client')
11const {
12 InvalidArgumentError
13} = require('../core/errors')
14const util = require('../core/util')
15const { kUrl, kInterceptors } = require('../core/symbols')
16const buildConnector = require('../core/connect')
17
18const kOptions = Symbol('options')
19const kConnections = Symbol('connections')
20const kFactory = Symbol('factory')
21
22function defaultFactory (origin, opts) {
23 return new Client(origin, opts)
24}
25
26class Pool extends PoolBase {
27 constructor (origin, {
28 connections,
29 factory = defaultFactory,
30 connect,
31 connectTimeout,
32 tls,
33 maxCachedSessions,
34 socketPath,
35 autoSelectFamily,
36 autoSelectFamilyAttemptTimeout,
37 allowH2,
38 ...options
39 } = {}) {
40 if (connections != null && (!Number.isFinite(connections) || connections < 0)) {
41 throw new InvalidArgumentError('invalid connections')
42 }
43
44 if (typeof factory !== 'function') {
45 throw new InvalidArgumentError('factory must be a function.')
46 }
47
48 if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') {
49 throw new InvalidArgumentError('connect must be a function or an object')
50 }
51
52 if (typeof connect !== 'function') {
53 connect = buildConnector({
54 ...tls,
55 maxCachedSessions,
56 allowH2,
57 socketPath,
58 timeout: connectTimeout,
59 ...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
60 ...connect
61 })
62 }
63
64 super(options)
65
66 this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool)
67 ? options.interceptors.Pool
68 : []
69 this[kConnections] = connections || null
70 this[kUrl] = util.parseOrigin(origin)
71 this[kOptions] = { ...util.deepClone(options), connect, allowH2 }
72 this[kOptions].interceptors = options.interceptors
73 ? { ...options.interceptors }
74 : undefined
75 this[kFactory] = factory
76
77 this.on('connectionError', (origin, targets, error) => {
78 // If a connection error occurs, we remove the client from the pool,
79 // and emit a connectionError event. They will not be re-used.
80 // Fixes https://github.com/nodejs/undici/issues/3895
81 for (const target of targets) {
82 // Do not use kRemoveClient here, as it will close the client,
83 // but the client cannot be closed in this state.
84 const idx = this[kClients].indexOf(target)
85 if (idx !== -1) {
86 this[kClients].splice(idx, 1)
87 }
88 }
89 })
90 }
91
92 [kGetDispatcher] () {
93 for (const client of this[kClients]) {
94 if (!client[kNeedDrain]) {
95 return client
96 }
97 }
98
99 if (!this[kConnections] || this[kClients].length < this[kConnections]) {
100 const dispatcher = this[kFactory](this[kUrl], this[kOptions])
101 this[kAddClient](dispatcher)
102 return dispatcher
103 }
104 }
105}
106
107module.exports = Pool
108 