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    super()
41
42    if (connections != null && (!Number.isFinite(connections) || connections < 0)) {
43      throw new InvalidArgumentError('invalid connections')
44    }
45
46    if (typeof factory !== 'function') {
47      throw new InvalidArgumentError('factory must be a function.')
48    }
49
50    if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') {
51      throw new InvalidArgumentError('connect must be a function or an object')
52    }
53
54    if (typeof connect !== 'function') {
55      connect = buildConnector({
56        ...tls,
57        maxCachedSessions,
58        allowH2,
59        socketPath,
60        timeout: connectTimeout,
61        ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
62        ...connect
63      })
64    }
65
66    this[kInterceptors] = options.interceptors && 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
78  [kGetDispatcher] () {
79    let dispatcher = this[kClients].find(dispatcher => !dispatcher[kNeedDrain])
80
81    if (dispatcher) {
82      return dispatcher
83    }
84
85    if (!this[kConnections] || this[kClients].length < this[kConnections]) {
86      dispatcher = this[kFactory](this[kUrl], this[kOptions])
87      this[kAddClient](dispatcher)
88    }
89
90    return dispatcher
91  }
92}
93
94module.exports = Pool
95