@datastax/astra-db-ts
Version:
Data API TypeScript client
138 lines (137 loc) • 6.3 kB
JavaScript
;
// Copyright Datastax, Inc
// SPDX-License-Identifier: Apache-2.0
// noinspection ExceptionCaughtLocallyJS
Object.defineProperty(exports, "__esModule", { value: true });
exports.DevOpsAPIHttpClient = void 0;
const index_js_1 = require("../../../lib/api/clients/index.js");
const errors_js_1 = require("../../../administration/errors.js");
const constants_js_1 = require("../../../lib/api/constants.js");
const utils_js_1 = require("../../../lib/utils.js");
const errors_js_2 = require("../../../lib/errors.js");
const index_js_2 = require("../../../lib/index.js");
const index_js_3 = require("../../../documents/index.js");
class DevOpsAPIHttpClient extends index_js_1.HttpClient {
constructor(opts) {
super('devops-api', {
...opts,
additionalHeaders: index_js_2.HeadersProvider.opts.fromObj.concat([
opts.additionalHeaders,
opts.tokenProvider.toHeadersProvider(),
]),
mkTimeoutError: errors_js_1.DevOpsAPITimeoutError.mk,
});
}
async request(req, tm, started = 0) {
return this._executeRequest(req, tm, started, this.logger.internal.generateAdminCommandRequestId());
}
async requestLongRunning(req, info) {
const isLongRunning = info.options?.blocking !== false;
const timeoutManager = info.timeoutManager;
const started = performance.now();
const requestId = this.logger.internal.generateAdminCommandRequestId();
this.logger.internal.adminCommandStarted?.(requestId, this.baseUrl, req, isLongRunning, timeoutManager.initial());
const awaitStatus = await this._mkAwaitStatusFn(info, timeoutManager, started, requestId);
const resp = await this._executeRequest(req, timeoutManager, started, requestId);
const id = (typeof info.id === 'function')
? info.id(resp)
: info.id;
await awaitStatus?.(id, req);
this.logger.internal.adminCommandSucceeded?.(requestId, this.baseUrl, req, isLongRunning, resp, started);
return resp;
}
async _executeRequest(req, tm, started, requestId) {
const isLongRunning = started !== 0;
try {
const url = this.baseUrl + req.path;
if (!isLongRunning) {
this.logger.internal.adminCommandStarted?.(requestId, this.baseUrl, req, isLongRunning, tm.initial());
}
started || (started = performance.now());
const resp = await this._request({
url: url,
method: req.method,
params: req.params,
data: JSON.stringify(req.data),
forceHttp1: true,
timeoutManager: tm,
});
const data = resp.body ? (0, utils_js_1.jsonTryParse)(resp.body, undefined) : undefined;
if (resp.status >= 400) {
throw new errors_js_1.DevOpsAPIResponseError(resp, data);
}
if (!isLongRunning) {
this.logger.internal.adminCommandSucceeded?.(requestId, this.baseUrl, req, false, data, started);
}
return {
data: data,
status: resp.status,
headers: resp.headers,
};
}
catch (thrown) {
const err = errors_js_2.NonErrorError.asError(thrown);
this.logger.internal.adminCommandFailed?.(requestId, this.baseUrl, req, isLongRunning, err, started);
throw err;
}
}
async _mkAwaitStatusFn(info, tm, started, requestId) {
if (info.options?.blocking === false) {
return undefined;
}
if (!await this._canPoll(info, tm, started, requestId)) {
throw new Error('Given token does not have permissions to poll for status updates; please use `blocking: false` to skip polling, or provide a token with the necessary permissions. No changes to the database have been made.');
}
const pollInterval = info.options?.pollInterval || info.defaultPollInterval; // out here so TS doesn't throw a fit
return async (id, req) => {
let waiting = false;
for (let i = 1; i++;) {
if (waiting) {
continue;
}
waiting = true;
this.logger.internal.adminCommandPolling?.(requestId, this.baseUrl, req, started, pollInterval, i);
const resp = await this.request({
method: constants_js_1.HttpMethods.Get,
path: `/databases/${id}`,
methodName: req.methodName,
}, info.timeoutManager, started);
if (resp.data?.status === info.target) {
break;
}
if (!info.legalStates.includes(resp.data?.status)) {
const okStates = [info.target, ...info.legalStates];
const error = new Error(`Created database is not in any legal state [${okStates.join(',')}]; current state: ${resp.data?.status}`);
this.logger.internal.adminCommandFailed?.(requestId, this.baseUrl, req, true, error, started);
throw error;
}
await new Promise((resolve) => {
setTimeout(() => {
waiting = false;
resolve();
}, pollInterval);
});
}
};
}
async _canPoll(info, tm, started, requestId) {
try {
const id = (typeof info.id === 'string') // in case of something like createDatabase
? info.id
: index_js_3.uuid.v4().toString();
await this._executeRequest({
method: constants_js_1.HttpMethods.Get,
path: `/databases/${id}`,
methodName: 'devopsApiHttpClient._canPoll',
}, tm, started, requestId);
}
catch (e) {
if (e instanceof errors_js_1.DevOpsAPIResponseError) {
return e.status === 404;
}
throw e;
}
return true;
}
}
exports.DevOpsAPIHttpClient = DevOpsAPIHttpClient;