agora-rest-client
Version:
Node.js REST client for Agora
153 lines (152 loc) • 6.84 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RequestClient = void 0;
const types_1 = require("../types");
const utils_1 = require("../utils");
const domain_1 = require("../domain/domain");
const https = require("https");
const url_1 = require("url");
const node_fetch_1 = require("node-fetch");
const querystring_1 = require("querystring");
const resolver_1 = require("../domain/resolver");
const log_1 = require("../log");
const logger = (0, log_1.getLogger)('RequestClient');
class RequestClient {
constructor(config) {
this.config = config;
this.domainPool = new domain_1.DomainPool(config.domainArea);
this.timeout = config.httpTimeout || utils_1.DEFAULT_REQ_TIMEOUT;
this.keepAliveAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 3000,
});
}
buildHeaders(host, userAgent) {
const now = new Date();
return {
accept: 'application/json',
date: now.toUTCString(),
host,
'content-type': 'application/json',
'user-agent': userAgent,
};
}
request(method, uriPattern, options) {
return __awaiter(this, void 0, void 0, function* () {
let err, response;
const abortController = new AbortController();
const timeout = options.timeout === undefined ? this.timeout : options.timeout;
let aborted = false;
const timer = setTimeout(() => {
clearTimeout(timer);
aborted = true;
abortController.abort();
}, timeout);
if (this.domainPool.domainNeedUpdate()) {
try {
const domain = yield (0, resolver_1.bestDomain)(this.domainPool.allDomains, this.domainPool.currentRegion);
this.domainPool.selectDomain(domain);
}
catch (e) {
err = utils_1.GenericError.wrapError(utils_1.ERR_NAMESPACE_LIB, types_1.ErrorTypeEnum.RequestDNSError, e);
throw err;
}
}
// start request, but don't process response yet
;
[err, response] = yield (0, utils_1.retry)(this, (retryCount) => __awaiter(this, void 0, void 0, function* () {
var _a;
logger.debug(`http module retry attempt ${retryCount}...`);
const endpoint = this.domainPool.currentUrl;
logger.debug(`current endpoint: ${endpoint}`);
const parsedURL = new url_1.URL(endpoint);
const host = parsedURL.hostname;
const userAgent = (0, utils_1.getUserAgent)();
logger.debug(`current host: ${host},userAgent: ${userAgent}`);
const mixHeaders = Object.assign(this.buildHeaders(host || '', userAgent));
(_a = this.config.credential) === null || _a === void 0 ? void 0 : _a.setAuth(mixHeaders);
const fetchOptions = {
method,
agent: this.keepAliveAgent,
headers: new node_fetch_1.Headers(mixHeaders),
body: options.body,
signal: abortController.signal,
};
let url = `${endpoint}${uriPattern}`;
if (options.query && Object.keys(options.query).length > 0) {
url += `?${querystring_1.default.stringify(options.query)}`;
}
logger.debug(`request body: ${options.body}`);
const response = yield (0, node_fetch_1.default)(url, fetchOptions);
logger.debug(`status:${response.status},method:${fetchOptions.method},url:${url} requestId: ${response.headers.get('x-request-id')}`);
return response;
}), () => aborted, {
onFailAttempt: (err) => {
logger.warn(`http module error: ${err.message}`);
this.domainPool.nextRegion();
},
// delay for 500ms before next request
delay: (retryCount) => (retryCount >= 1 ? 500 : 0),
});
this._checkRequestAborted(aborted, timer);
if (err) {
throw err;
}
if (response) {
let body;
try {
body = yield response.json();
}
catch (e) {
clearTimeout(timer);
throw utils_1.GenericError.wrapError(utils_1.ERR_NAMESPACE_LIB, types_1.ErrorTypeEnum.RequestResponseError, e);
}
clearTimeout(timer);
// @ts-ignore
return { body, response };
}
else {
clearTimeout(timer);
throw utils_1.GenericError.wrapMessage(utils_1.ERR_NAMESPACE_LIB, types_1.ErrorTypeEnum.RequestResponseError, 'FormatError', 'unknown response');
}
});
}
put(path, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.request('PUT', path, options);
});
}
post(path, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.request('POST', path, options);
});
}
get(path, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.request('GET', path, options);
});
}
delete(path, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.request('DELETE', path, options);
});
}
// ------------------- private methods -------------------
_checkRequestAborted(aborted, timer) {
if (aborted) {
logger.error(`request aborted`);
clearTimeout(timer);
throw utils_1.GenericError.wrapMessage(types_1.ERR_NAMESPACE_CLIENT, types_1.ErrorTypeEnum.RequestTimeoutError, 'TimeoutError', 'request timeout');
}
}
}
exports.RequestClient = RequestClient;