|
1 | 1 | {{>licenseInfo}} |
2 | 2 | 'use strict'; |
3 | 3 |
|
| 4 | +// Module-level agent pool for connection reuse |
| 5 | +const agentPool = new Map(); |
| 6 | + |
4 | 7 | (function(root, factory) { |
5 | 8 | if (typeof define === 'function' && define.amd) { |
6 | 9 | // AMD. Register as an anonymous module. |
7 | | - define(['axios', 'axios-cookiejar-support', 'https-proxy-agent', 'https', 'querystring', 'Authentication/MerchantConfig', 'Authentication/Logger', 'Authentication/Constants', 'Authentication/Authorization', 'Authentication/PayloadDigest'], factory); |
| 10 | + define(['axios', 'axios-cookiejar-support', 'https-proxy-agent', 'https', 'querystring', 'agentkeepalive', 'crypto', 'Authentication/MerchantConfig', 'Authentication/Logger', 'Authentication/Constants', 'Authentication/Authorization', 'Authentication/PayloadDigest'], factory); |
8 | 11 | } else if (typeof module === 'object' && module.exports) { |
9 | 12 | // CommonJS-like environments that support module.exports, like Node. |
10 | | - module.exports = factory(require('axios'), require('axios-cookiejar-support'), require('https-proxy-agent'), require('https'), require('querystring'), require('./authentication/core/MerchantConfig'), require('./authentication/logging/Logger'), require('./authentication/util/Constants'), require('./authentication/core/Authorization'), require('./authentication/payloadDigest/DigestGenerator')); |
| 13 | + module.exports = factory(require('axios'), require('axios-cookiejar-support'), require('https-proxy-agent'), require('https'), require('querystring'), require('agentkeepalive'), require('crypto'), require('./authentication/core/MerchantConfig'), require('./authentication/logging/Logger'), require('./authentication/util/Constants'), require('./authentication/core/Authorization'), require('./authentication/payloadDigest/DigestGenerator')); |
11 | 14 | } else { |
12 | 15 | // Browser globals (root is window) |
13 | 16 | if (!root.{{moduleName}}) { |
14 | 17 | root.{{moduleName}} = {}; |
15 | 18 | } |
16 | | - root.{{moduleName}}.ApiClient = factory(root.axios, root.axiosCookieJar, root.httpsProxyAgent, root.https, root.querystring, root.Authentication.MerchantConfig, root.Authentication.Logger, root.Authentication.Constants, root.Authentication.Authorization, root.Authentication.PayloadDigest); |
| 19 | + root.{{moduleName}}.ApiClient = factory(root.axios, root.axiosCookieJar, root.httpsProxyAgent, root.https, root.querystring, root.AgentKeepAlive, root.crypto, root.Authentication.MerchantConfig, root.Authentication.Logger, root.Authentication.Constants, root.Authentication.Authorization, root.Authentication.PayloadDigest); |
17 | 20 | } |
18 | | -}(this, function(axios, axiosCookieJar, { HttpsProxyAgent }, https, querystring, MerchantConfig, Logger, Constants, Authorization, PayloadDigest) { |
| 21 | +}(this, function(axios, axiosCookieJar, HttpsProxyAgent, https, querystring, AgentKeepAlive, crypto, MerchantConfig, Logger, Constants, Authorization, PayloadDigest) { |
19 | 22 | {{#emitJSDoc}} /** |
20 | 23 | * @module {{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient |
21 | 24 | * @version {{projectVersion}} |
|
440 | 443 | return tester; |
441 | 444 | } |
442 | 445 |
|
| 446 | + /** |
| 447 | + * Generates a configuration hash for agent caching |
| 448 | + * @param {Object} config - Configuration object with connection parameters |
| 449 | + * @returns {String} - Hash string representing the configuration |
| 450 | + */ |
| 451 | + function generateConfigHash(config) { |
| 452 | + const hashParts = []; |
| 453 | + |
| 454 | + // Add relevant configuration properties to the hash |
| 455 | + if (config.useProxy) { |
| 456 | + hashParts.push(`proxyUrl:${config.proxyUrl}`); |
| 457 | + } |
| 458 | + if (config.disableSSLVerification !== undefined) hashParts.push(`sslVerify:${!config.disableSSLVerification}`); |
| 459 | + if (config.sslCaCert) hashParts.push(`sslCaCert:${config.sslCaCert}`); |
| 460 | + if (config.enableClientCert) hashParts.push(`clientCert:${config.certFile}:${config.keyFile}`); |
| 461 | + if (config.maxIdleSockets !== undefined) hashParts.push(`maxIdleSockets:${config.maxIdleSockets}`); |
| 462 | + if (config.freeSocketTimeout !== undefined) hashParts.push(`freeSocketTimeout:${config.freeSocketTimeout}`); |
| 463 | + |
| 464 | + const concatenated = hashParts.join('|'); |
| 465 | + return crypto.createHash('sha256').update(concatenated).digest('hex'); |
| 466 | + } |
| 467 | + |
| 468 | + /** |
| 469 | + * Gets or creates an HTTPS agent based on configuration |
| 470 | + * @param {Object} config - Configuration object with connection parameters |
| 471 | + * @returns {https.Agent} - HTTPS agent instance |
| 472 | + */ |
| 473 | + function getOrCreateAgent(config) { |
| 474 | + const configHash = generateConfigHash(config); |
| 475 | + |
| 476 | + if (agentPool.has(configHash)) { |
| 477 | + return agentPool.get(configHash); |
| 478 | + } |
| 479 | + |
| 480 | + const fs = require('fs'); |
| 481 | + |
| 482 | + // Create agent options with keepAlive enabled |
| 483 | + const agentOptions = { |
| 484 | + keepAlive: true, // By default, keepAlive is true in agentkeepalive |
| 485 | + maxSockets: config.maxIdleSockets, |
| 486 | + freeSocketTimeout: config.freeSocketTimeout, |
| 487 | + rejectUnauthorized: !config.disableSSLVerification, |
| 488 | + }; |
| 489 | + |
| 490 | + // Add SSL certificate if provided |
| 491 | + if (config.sslCaCert) { |
| 492 | + agentOptions.ca = fs.readFileSync(config.sslCaCert); |
| 493 | + } |
| 494 | + |
| 495 | + // Add client certificates if enabled |
| 496 | + if (config.enableClientCert) { |
| 497 | + agentOptions.cert = fs.readFileSync(config.certFile); |
| 498 | + agentOptions.key = fs.readFileSync(config.keyFile); |
| 499 | + } |
| 500 | + |
| 501 | + // Use the HttpsAgent from the agentkeepalive package |
| 502 | + const agent = new AgentKeepAlive.HttpsAgent(agentOptions); |
| 503 | + agentPool.set(configHash, agent); |
| 504 | + return agent; |
| 505 | + } |
| 506 | + |
| 507 | + /** |
| 508 | + * Gets or creates an HTTPS proxy agent based on configuration |
| 509 | + * @param {String} proxyAddress - Proxy server address |
| 510 | + * @param {Number} proxyPort - Proxy server port |
| 511 | + * @param {String} proxyUser - Proxy authentication username (optional) |
| 512 | + * @param {String} proxyPassword - Proxy authentication password (optional) |
| 513 | + * @returns {HttpsProxyAgent} - HTTPS proxy agent instance |
| 514 | + */ |
| 515 | + function getOrCreateProxyAgent(proxyAddress, proxyPort, proxyUser, proxyPassword, maxIdleSockets) { |
| 516 | + const { HttpsProxyAgent } = require('https-proxy-agent'); |
| 517 | + |
| 518 | + let proxyUrl; |
| 519 | + if (proxyUser && proxyPassword) { |
| 520 | + proxyUrl = `http://${proxyUser}:${proxyPassword}@${proxyAddress}:${proxyPort}`; |
| 521 | + } else { |
| 522 | + proxyUrl = `http://${proxyAddress}:${proxyPort}`; |
| 523 | + } |
| 524 | + |
| 525 | + const configHash = generateConfigHash({ |
| 526 | + useProxy: true, |
| 527 | + proxyUrl: proxyUrl, |
| 528 | + maxIdleSockets: maxIdleSockets |
| 529 | + }); |
| 530 | + |
| 531 | + if (agentPool.has(configHash)) { |
| 532 | + return agentPool.get(configHash); |
| 533 | + } |
| 534 | + |
| 535 | + // Apply the same connection pooling settings as the regular HTTPS agent |
| 536 | + const agentOptions = { |
| 537 | + keepAlive: true, // Keep the connection alive |
| 538 | + maxSockets: maxIdleSockets |
| 539 | + }; |
| 540 | + |
| 541 | + const agent = new HttpsProxyAgent(proxyUrl, agentOptions); |
| 542 | + agentPool.set(configHash, agent); |
| 543 | + return agent; |
| 544 | + } |
| 545 | + |
443 | 546 | // Code added by Infosys dev team |
444 | 547 |
|
445 | 548 | /** |
|
590 | 693 | headers: {} |
591 | 694 | }; |
592 | 695 |
|
| 696 | + // Use module-level connection pooling with keepAlive |
593 | 697 | if (useProxy && (proxyAddress != null && proxyAddress != '')) { |
594 | | - if ((proxyUser != null && proxyUser != '') && (proxyPassword!= null && proxyPassword != '')) { |
595 | | - var proxy = process.env.http_proxy || 'http://' + proxyUser + ':' + proxyPassword + '@' + proxyAddress + ':' + proxyPort; |
596 | | - } |
597 | | - else { |
598 | | - var proxy = process.env.http_proxy || 'http://' + proxyAddress + ':' + proxyPort; |
599 | | - } |
600 | | - |
601 | | - var agent = new HttpsProxyAgent(proxy); |
602 | | - axiosConfig.httpsAgent = agent; |
| 698 | + // Get or create a proxy agent from the pool |
| 699 | + axiosConfig.httpsAgent = getOrCreateProxyAgent(proxyAddress, proxyPort, proxyUser, proxyPassword, this.merchantConfig.getMaxIdleSockets()); |
603 | 700 | } else { |
604 | | - if (sslCaCert) { |
605 | | - axiosConfig.httpsAgent = new https.Agent({ |
606 | | - rejectUnauthorized: !isSslVerificationDisabled, |
607 | | - ca: fslib.readFileSync(sslCaCert) |
608 | | - }); |
609 | | - } else { |
610 | | - axiosConfig.httpsAgent = new https.Agent({ |
611 | | - rejectUnauthorized: !isSslVerificationDisabled |
612 | | - }); |
613 | | - } |
614 | | - } |
615 | | - |
616 | | - if(enableClientCert) { |
617 | | - var certFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getSSLClientCert())); |
618 | | - var keyFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getPrivateKey())); |
619 | | -
|
620 | | - if (axiosConfig.httpsAgent) { |
621 | | - axiosConfig.httpsAgent.cert = fslib.readFileSync(certFile); |
622 | | - axiosConfig.httpsAgent.key = fslib.readFileSync(keyFile); |
623 | | - } else { |
624 | | - axiosConfig.httpsAgent = new https.Agent({ |
625 | | - rejectUnauthorized: !isSslVerificationDisabled, |
626 | | - cert: fslib.readFileSync(certFile), |
627 | | - key: fslib.readFileSync(keyFile) |
628 | | - }); |
| 701 | + // Get or create an HTTPS agent from the pool |
| 702 | + var certFile, keyFile; |
| 703 | + |
| 704 | + if (enableClientCert) { |
| 705 | + certFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getSSLClientCert())); |
| 706 | + keyFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getPrivateKey())); |
629 | 707 | } |
| 708 | + |
| 709 | + axiosConfig.httpsAgent = getOrCreateAgent({ |
| 710 | + disableSSLVerification: isSslVerificationDisabled, |
| 711 | + sslCaCert: sslCaCert, |
| 712 | + enableClientCert: enableClientCert, |
| 713 | + certFile: certFile, |
| 714 | + keyFile: keyFile, |
| 715 | + useProxy: false, |
| 716 | + maxIdleSockets: this.merchantConfig.getMaxIdleSockets(), |
| 717 | + freeSocketTimeout: this.merchantConfig.getFreeSocketTimeout() |
| 718 | + }); |
630 | 719 | } |
631 | 720 |
|
632 | 721 | // apply authentications |
|
0 commit comments