Skip to content

Commit 4c2d30e

Browse files
Merge remote-tracking branch 'origin/future' into mle-for-response
2 parents 1c55d18 + fd9a29b commit 4c2d30e

File tree

5 files changed

+290
-77
lines changed

5 files changed

+290
-77
lines changed

generator/cybersource-javascript-template/ApiClient.mustache

Lines changed: 127 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
{{>licenseInfo}}
22
'use strict';
33

4+
// Module-level agent pool for connection reuse
5+
const agentPool = new Map();
6+
47
(function(root, factory) {
58
if (typeof define === 'function' && define.amd) {
69
// 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', 'Authentication/MLEUtility'], factory);
10+
define(['axios', 'axios-cookiejar-support', 'https-proxy-agent', 'https', 'querystring', 'agentkeepalive', 'crypto', 'Authentication/MerchantConfig', 'Authentication/Logger', 'Authentication/Constants', 'Authentication/Authorization', 'Authentication/PayloadDigest', 'Authentication/MLEUtility'], factory);
811
} else if (typeof module === 'object' && module.exports) {
912
// 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'), require('./authentication/util/MLEUtility'));
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'), require('./authentication/util/MLEUtility'));
1114
} else {
1215
// Browser globals (root is window)
1316
if (!root.{{moduleName}}) {
1417
root.{{moduleName}} = {};
1518
}
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, root.Authentication.MLEUtility);
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, root.Authentication.MLEUtility);
1720
}
18-
}(this, function(axios, axiosCookieJar, { HttpsProxyAgent }, https, querystring, MerchantConfig, Logger, Constants, Authorization, PayloadDigest, MLEUtility) {
21+
}(this, function(axios, axiosCookieJar, HttpsProxyAgent, https, querystring, AgentKeepAlive, crypto, MerchantConfig, Logger, Constants, Authorization, PayloadDigest, MLEUtility) {
1922
{{#emitJSDoc}} /**
2023
* @module {{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient
2124
* @version {{projectVersion}}
@@ -440,6 +443,106 @@
440443
return tester;
441444
}
442445

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+
443546
// Code added by Infosys dev team
444547

445548
/**
@@ -592,43 +695,29 @@
592695
headers: {}
593696
};
594697

698+
// Use module-level connection pooling with keepAlive
595699
if (useProxy && (proxyAddress != null && proxyAddress != '')) {
596-
if ((proxyUser != null && proxyUser != '') && (proxyPassword!= null && proxyPassword != '')) {
597-
var proxy = process.env.http_proxy || 'http://' + proxyUser + ':' + proxyPassword + '@' + proxyAddress + ':' + proxyPort;
598-
}
599-
else {
600-
var proxy = process.env.http_proxy || 'http://' + proxyAddress + ':' + proxyPort;
601-
}
602-
603-
var agent = new HttpsProxyAgent(proxy);
604-
axiosConfig.httpsAgent = agent;
700+
// Get or create a proxy agent from the pool
701+
axiosConfig.httpsAgent = getOrCreateProxyAgent(proxyAddress, proxyPort, proxyUser, proxyPassword, this.merchantConfig.getMaxIdleSockets());
605702
} else {
606-
if (sslCaCert) {
607-
axiosConfig.httpsAgent = new https.Agent({
608-
rejectUnauthorized: !isSslVerificationDisabled,
609-
ca: fslib.readFileSync(sslCaCert)
610-
});
611-
} else {
612-
axiosConfig.httpsAgent = new https.Agent({
613-
rejectUnauthorized: !isSslVerificationDisabled
614-
});
615-
}
616-
}
617-
618-
if(enableClientCert) {
619-
var certFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getSSLClientCert()));
620-
var keyFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getPrivateKey()));
621-
622-
if (axiosConfig.httpsAgent) {
623-
axiosConfig.httpsAgent.cert = fslib.readFileSync(certFile);
624-
axiosConfig.httpsAgent.key = fslib.readFileSync(keyFile);
625-
} else {
626-
axiosConfig.httpsAgent = new https.Agent({
627-
rejectUnauthorized: !isSslVerificationDisabled,
628-
cert: fslib.readFileSync(certFile),
629-
key: fslib.readFileSync(keyFile)
630-
});
703+
// Get or create an HTTPS agent from the pool
704+
var certFile, keyFile;
705+
706+
if (enableClientCert) {
707+
certFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getSSLClientCert()));
708+
keyFile = pathlib.resolve(pathlib.join(this.merchantConfig.getClientCertDir(), this.merchantConfig.getPrivateKey()));
631709
}
710+
711+
axiosConfig.httpsAgent = getOrCreateAgent({
712+
disableSSLVerification: isSslVerificationDisabled,
713+
sslCaCert: sslCaCert,
714+
enableClientCert: enableClientCert,
715+
certFile: certFile,
716+
keyFile: keyFile,
717+
useProxy: false,
718+
maxIdleSockets: this.merchantConfig.getMaxIdleSockets(),
719+
freeSocketTimeout: this.merchantConfig.getFreeSocketTimeout()
720+
});
632721
}
633722

634723
// apply authentications

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"axios-cookiejar-support": "4.0.7",
1717
"tough-cookie": "4.1.3",
1818
"https-proxy-agent": "^7.0.0",
19+
"agentkeepalive": "^4.6.0",
1920
"app-root-path": "^3.1.0",
2021
"chai": "^4.3.1",
2122
"chai-as-promised": "^7.1.1",

0 commit comments

Comments
 (0)