UNPKG

channelape-sdk

Version:
146 lines 7.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const RequestLogger_1 = require("./utils/RequestLogger"); const ChannelApeError_1 = require("./model/ChannelApeError"); const limiter_1 = require("limiter"); const util = require("util"); const GENERIC_ERROR_CODE = -1; const IMMEDIATELY_FIRE_RATE_LIMITED_CALLBACK = false; const DEFAULT_API_CALLS_PER_INTERVAL = 20; const DEFAULT_API_LIMIT_INTERVAL = 'second'; const CHANNEL_APE_API_RETRY_TIMEOUT_MESSAGE = `A problem with the ChannelApe API has been encountered. Your request was tried a total of %s times over the course of %s milliseconds`; class RequestClientWrapper { constructor(client, logLevel, endpoint, maximumRequestRetryTimeout) { this.client = client; this.logLevel = logLevel; this.maximumRequestRetryTimeout = maximumRequestRetryTimeout; this.requestLogger = new RequestLogger_1.default(this.logLevel, endpoint); this.limiter = new limiter_1.RateLimiter(DEFAULT_API_CALLS_PER_INTERVAL, DEFAULT_API_LIMIT_INTERVAL, IMMEDIATELY_FIRE_RATE_LIMITED_CALLBACK); } get(uriOrOptions, callbackOrOptionsOrUndefined, callBackOrUndefined) { const callStart = new Date(); const initialCallCountForThisRequest = 0; this.makeRequest('get', callStart, initialCallCountForThisRequest, uriOrOptions, callbackOrOptionsOrUndefined, callBackOrUndefined); } put(uriOrOptions, callbackOrOptionsOrUndefined, callBackOrUndefined) { const callStart = new Date(); const initialCallCountForThisRequest = 0; this.makeRequest('put', callStart, initialCallCountForThisRequest, uriOrOptions, callbackOrOptionsOrUndefined, callBackOrUndefined); } makeRequest(method, callStart, numberOfCalls, uriOrOptions, callbackOrOptionsOrUndefined, callBackOrUndefined) { this.limiter.removeTokens(1, (err, remainingRequest) => { const callDetails = { callStart, callCountForThisRequest: numberOfCalls }; let callableRequestMethod; try { callableRequestMethod = this.getCallableRequestMethod(method); } catch (e) { if (typeof callbackOrOptionsOrUndefined === 'function') { this.handleResponse(e, {}, {}, callbackOrOptionsOrUndefined, '', undefined, callDetails); } else if (typeof callBackOrUndefined === 'function') { this.handleResponse(e, {}, {}, callBackOrUndefined, '', undefined, callDetails); } return; } this.requestLogger.logCall(method, uriOrOptions, callbackOrOptionsOrUndefined); if (typeof uriOrOptions === 'string') { if (typeof callbackOrOptionsOrUndefined === 'function') { return callableRequestMethod(uriOrOptions, (error, response, body) => { this.handleResponse(error, response, body, callbackOrOptionsOrUndefined, uriOrOptions, undefined, callDetails); }); } return callableRequestMethod(uriOrOptions, callbackOrOptionsOrUndefined, (error, response, body) => { this.handleResponse(error, response, body, callBackOrUndefined, uriOrOptions, callbackOrOptionsOrUndefined, callDetails); }); } if (typeof callbackOrOptionsOrUndefined === 'function') { return callableRequestMethod(uriOrOptions, (error, response, body) => { this.handleResponse(error, response, body, callbackOrOptionsOrUndefined, uriOrOptions.uri.toString(), undefined, callDetails); }); } return callableRequestMethod(uriOrOptions); }); } getCallableRequestMethod(method) { let callableRequestMethod; switch (method.toUpperCase()) { case ('GET'): callableRequestMethod = this.client.get; break; case ('PUT'): callableRequestMethod = this.client.put; break; default: throw new ChannelApeError_1.default('HTTP Request Method could not be determined', {}, '', []); } return callableRequestMethod; } handleResponse(error, response, body, callBackOrUndefined, uri, options, callDetails) { this.requestLogger.logResponse(error, response, body); let finalError = null; if (this.didRequestTimeout(callDetails.callStart)) { const maximumRetryLimitExceededMessage = this.getMaximumRetryLimitExceededMessage(callDetails.callStart, callDetails.callCountForThisRequest); finalError = new ChannelApeError_1.default(maximumRetryLimitExceededMessage, response, uri, []); } else if (response == null) { const badResponseMessage = 'No response was received from the server'; finalError = new ChannelApeError_1.default(badResponseMessage, undefined, uri, [{ code: 504, message: badResponseMessage }]); } else if (this.shouldRequestBeRetried(error, response) && response) { this.retryRequest(response.method, uri, options, callBackOrUndefined, response, body, callDetails); return; } if (error) { finalError = new ChannelApeError_1.default(error.message, response, uri, [{ code: GENERIC_ERROR_CODE, message: error.message }]); } else if (this.isApiError(body) && response && body) { finalError = new ChannelApeError_1.default(`${response.statusCode} ${response.statusMessage}`, response, uri, body.errors); } if (typeof callBackOrUndefined === 'function') { callBackOrUndefined(finalError, response, body); } } getMaximumRetryLimitExceededMessage(callStart, numberOfCalls) { const elapsedTimeMs = new Date().getTime() - callStart.getTime(); return util.format(CHANNEL_APE_API_RETRY_TIMEOUT_MESSAGE, numberOfCalls, elapsedTimeMs); } didRequestTimeout(callStart) { const now = new Date(); const totalElapsedTime = now.getTime() - callStart.getTime(); return totalElapsedTime > this.maximumRequestRetryTimeout; } shouldRequestBeRetried(error, response) { if (response == null) { return false; } return (!error && ((response.statusCode >= 500 && response.statusCode <= 599) || response.statusCode === 429)); } isApiError(body) { if (typeof body === 'undefined' || typeof body.errors === 'undefined') { return false; } return body.errors.length > 0; } retryRequest(method, uri, options, callBackOrUndefined, response, body, callDetails) { if (method == null) { if (typeof callBackOrUndefined === 'function') { const e = new ChannelApeError_1.default('HTTP Request Method could not be determined', response, uri, []); callBackOrUndefined(e, response, body); } return; } const newNumberOfCalls = callDetails.callCountForThisRequest + 1; this.makeRequest(method, callDetails.callStart, newNumberOfCalls, uri, options, callBackOrUndefined); } } exports.default = RequestClientWrapper; //# sourceMappingURL=RequestClientWrapper.js.map