@webex/webex-core
Version:
Plugin handling for Cisco Webex
202 lines (187 loc) • 7.76 kB
JavaScript
"use strict";
var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/assertThisInitialized"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
var _weakMap = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/weak-map"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
var _httpCore = require("@webex/http-core");
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } /*!
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
*/
// contains the system time in milliseconds at which the retry after associated with a 429 expires
// mapped by the API name, e.g.: idbroker.webex.com/doStuff would be mapped as 'doStuff'
var rateLimitExpiryTime = new _weakMap.default();
// extracts the common identity API being called
var idBrokerRegex = /.*(idbroker|identity)(bts)?.ciscospark.com\/([^/]+)/;
/**
* @class
*/
var RateLimitInterceptor = exports.default = /*#__PURE__*/function (_Interceptor) {
(0, _inherits2.default)(RateLimitInterceptor, _Interceptor);
var _super = _createSuper(RateLimitInterceptor);
/**
* constructor
* @param {mixed} args
* @returns {Exception}
*/
function RateLimitInterceptor() {
var _this;
(0, _classCallCheck2.default)(this, RateLimitInterceptor);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _super.call.apply(_super, [this].concat(args));
rateLimitExpiryTime.set((0, _assertThisInitialized2.default)(_this), new _map.default());
return _this;
}
/**
* @see {@link Interceptor#onRequest}
* @param {Object} options
* @returns {Object}
*/
(0, _createClass2.default)(RateLimitInterceptor, [{
key: "onRequest",
value: function onRequest(options) {
if (this.isRateLimited(options.uri)) {
return _promise.default.reject(new Error("API rate limited ".concat(options.uri)));
}
return _promise.default.resolve(options);
}
/**
* @see {@link Interceptor#onResponseError}
* @param {Object} options
* @param {Error} reason
* @returns {Object}
*/
}, {
key: "onResponseError",
value: function onResponseError(options, reason) {
if (reason.statusCode === 429 && (options.uri.includes('idbroker') || options.uri.includes('identity'))) {
// set the retry after in the map, setting to milliseconds
this.setRateLimitExpiry(options.uri, this.extractRetryAfterTime(options));
}
return _promise.default.reject(reason);
}
/**
* @param {object} options associated with the request
* @returns {number} retry after time in milliseconds
*/
}, {
key: "extractRetryAfterTime",
value: function extractRetryAfterTime(options) {
// 1S * 1K === 1MS
var milliMultiplier = 1000;
var retryAfter = options.headers['retry-after'] || null;
// set 60 retry if no usable time defined
if (retryAfter === null || retryAfter <= 0) {
return 60 * milliMultiplier;
}
// set max to 3600 S (1 hour) if greater than 1 hour
if (retryAfter > 3600) {
return 3600 * milliMultiplier;
}
return retryAfter * milliMultiplier;
}
/**
* Set the system time at which the rate limiting
* will expire in the rateLimitExpiryTime map.
* Assumes retryAfter is in milliseconds
* @param {string} uri API issuing the rate limiting
* @param {number} retryAfter milliseconds until rate limiting expires
* @returns {bool} true is value was successfully set
*/
}, {
key: "setRateLimitExpiry",
value: function setRateLimitExpiry(uri, retryAfter) {
var apiName = this.getApiName(uri);
if (!apiName) {
return false;
}
var currTimeMilli = new Date().getTime();
var expiry = currTimeMilli + retryAfter;
var dict = rateLimitExpiryTime.get(this);
return dict.set(apiName, expiry);
}
/**
* returns true if the API is currently rate limited
* @param {string} uri
* @returns {Boolean} indicates whether or not the API is rate currently rate limited
*/
}, {
key: "getRateLimitStatus",
value: function getRateLimitStatus(uri) {
var apiName = this.getApiName(uri);
if (!apiName) {
return false;
}
var currTimeMilli = new Date().getTime();
var dict = rateLimitExpiryTime.get(this);
var expiryTime = dict.get(apiName);
// if no rate limit expiry has been registered in the map, return false.
if (expiryTime === undefined) {
return false;
}
// return true, indicating rate limiting, if the system time is less than the expiry time
return currTimeMilli < dict.get(apiName);
}
/**
* split the URI and returns the API name of idBroker
* @param {string} uri
* @returns {string}
*/
}, {
key: "getApiName",
value: function getApiName(uri) {
if (!uri) {
return null;
}
var results = uri.match(idBrokerRegex);
if (!results) {
return null;
}
// group 0 = full match of URL, group 1 = identity or idbroker base
// group 2 = api name
return results[2];
}
/**
* check URI against list of currently rate limited
* URIs, and determines if retry-after
* @param {String} uri pattern to check
* @returns {bool}
*/
}, {
key: "isRateLimited",
value: function isRateLimited(uri) {
// determine if the URI is associated with a common identity API
if (uri && (uri.includes('idbroker') || uri.includes('identity'))) {
return this.getRateLimitStatus(uri);
}
return false;
}
}], [{
key: "create",
value:
/**
* @returns {RateLimitInterceptor}
*/
function create() {
return new RateLimitInterceptor({
webex: this
});
}
}]);
return RateLimitInterceptor;
}(_httpCore.Interceptor);
//# sourceMappingURL=rate-limit.js.map