@azure/ms-rest-azure-js
Version:
Isomorphic Azure client runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest
585 lines • 27.4 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { __assign, __awaiter, __extends, __generator } from "tslib";
import { delay, RestError, stripRequest, WebResource } from "@azure/ms-rest-js";
/**
* A long-running operation polling strategy base class that other polling strategies should extend.
*/
var LROPollStrategy = /** @class */ (function () {
function LROPollStrategy(_azureServiceClient, _pollState) {
this._azureServiceClient = _azureServiceClient;
this._pollState = _pollState;
}
LROPollStrategy.prototype.getOperationStatus = function () {
return this._pollState.state;
};
/**
* Get whether or not this poll strategy's LRO is finished.
* @returns Whether or not this poll strategy's LRO is finished.
*/
LROPollStrategy.prototype.isFinished = function () {
return isFinished(this._pollState.state);
};
/**
* Send poll requests that check the LRO's status until it is determined that the LRO is finished.
* @returns Whether or not the LRO succeeded.
*/
LROPollStrategy.prototype.pollUntilFinished = function () {
return __awaiter(this, void 0, void 0, function () {
var delayInSeconds;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!!this.isFinished()) return [3 /*break*/, 3];
delayInSeconds = getDelayInSeconds(this._azureServiceClient, this._pollState.mostRecentResponse);
return [4 /*yield*/, delay(delayInSeconds * 1000)];
case 1:
_a.sent();
return [4 /*yield*/, this.sendPollRequest()];
case 2:
_a.sent();
return [3 /*break*/, 0];
case 3: return [2 /*return*/, this.isFinalStatusAcceptable()];
}
});
});
};
LROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () {
var initialRequestMethod = this._pollState.initialResponse.request.method;
return !this._pollState.resource && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH" || initialRequestMethod === "POST");
};
LROPollStrategy.prototype.getMostRecentResponse = function () {
return this._pollState.mostRecentResponse;
};
LROPollStrategy.prototype.getOperationResponse = function () {
return __awaiter(this, void 0, void 0, function () {
var response, result, resource;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.shouldDoFinalGetResourceRequest()) return [3 /*break*/, 2];
return [4 /*yield*/, this.doFinalGetResourceRequest()];
case 1:
_a.sent();
_a.label = 2;
case 2:
response = this._pollState.mostRecentResponse;
result = __assign(__assign({}, response), { headers: response.headers.clone() });
resource = this._pollState.resource;
if (!resource) {
result.bodyAsText = response.bodyAsText;
result.parsedBody = response.parsedBody;
}
else if (typeof resource.valueOf() === "string") {
result.bodyAsText = resource;
try {
result.parsedBody = JSON.parse(resource);
}
catch (err) {
// There was an error parsing the JSON. Hence we set the resource as-is. Most likely, the
// resource is a string that was already parsed.
result.parsedBody = resource;
}
}
else {
result.bodyAsText = JSON.stringify(resource);
result.parsedBody = resource;
}
return [2 /*return*/, result];
}
});
});
};
LROPollStrategy.prototype.getRestError = function () {
var error = new RestError("");
error.request = stripRequest(this._pollState.mostRecentRequest);
error.response = this._pollState.mostRecentResponse;
error.message = "Long running operation failed with status: \"" + this._pollState.state + "\".";
error.body = this._pollState.resource;
if (error.body) {
var innerError = error.body.error;
if (innerError) {
if (innerError.message) {
error.message = "Long running operation failed with error: \"" + innerError.message + "\".";
}
if (innerError.code) {
error.code = innerError.code;
}
}
}
return error;
};
LROPollStrategy.prototype.updateState = function (url, shouldDeserialize) {
var _this = this;
return this.updateOperationStatus(url, shouldDeserialize).then(function (result) {
_this._pollState.state = getProvisioningState(result.parsedBody) || "Succeeded";
_this._pollState.mostRecentResponse = result;
_this._pollState.mostRecentRequest = result.request;
_this._pollState.resource = getResponseBody(result);
}).catch(function (error) {
var resultStatus;
if (error.response && error.response.status) {
resultStatus = error.response.status;
if (_this._pollState.initialResponse.request.method !== "DELETE" || resultStatus < 400 || 499 < resultStatus) {
throw error;
}
}
else {
throw error;
}
});
};
/**
* Retrieves operation status by querying the operation URL.
* @param {string} statusUrl URL used to poll operation result.
*/
LROPollStrategy.prototype.updateOperationStatus = function (statusUrl, shouldDeserialize) {
var requestUrl = statusUrl.replace(" ", "%20");
var httpRequest = new WebResource(requestUrl, "GET");
var pollState = this._pollState;
httpRequest.operationSpec = pollState.mostRecentRequest.operationSpec;
httpRequest.shouldDeserialize = shouldDeserialize;
httpRequest.operationResponseGetter = getOperationResponse;
var options = pollState.options;
if (options && options.customHeaders) {
var customHeaders = options.customHeaders;
for (var _i = 0, _a = Object.keys(customHeaders); _i < _a.length; _i++) {
var headerName = _a[_i];
httpRequest.headers.set(headerName, customHeaders[headerName]);
}
}
return this._azureServiceClient.sendRequest(httpRequest);
};
LROPollStrategy.prototype.getPollState = function () {
return this._pollState;
};
return LROPollStrategy;
}());
export { LROPollStrategy };
function getOperationResponse(operationSpec, response) {
var statusCode = response.status;
var operationResponses = operationSpec.responses;
var result = operationResponses[statusCode];
if (!result) {
if (statusCode === 200) {
result = operationResponses[201] || operationResponses[202];
}
else if (201 <= statusCode && statusCode <= 299) {
result = {};
}
}
return result;
}
export function getDelayInSeconds(azureServiceClient, previousResponse) {
var delayInSeconds = 30;
if (azureServiceClient.longRunningOperationRetryTimeout != undefined) {
delayInSeconds = azureServiceClient.longRunningOperationRetryTimeout;
}
else {
var retryAfterHeaderValue = previousResponse.headers.get("retry-after");
if (retryAfterHeaderValue) {
var retryAfterDelayInSeconds = parseInt(retryAfterHeaderValue);
if (!Number.isNaN(retryAfterDelayInSeconds)) {
delayInSeconds = retryAfterDelayInSeconds;
}
}
}
return delayInSeconds;
}
function getProvisioningState(responseBody) {
var result;
if (responseBody) {
if (responseBody.provisioningState) {
result = responseBody.provisioningState;
}
else if (responseBody.properties) {
result = responseBody.properties.provisioningState;
}
}
return result;
}
function getResponseBody(response) {
var result;
try {
if (response.parsedBody) {
result = response.parsedBody;
}
else if (response.bodyAsText && response.bodyAsText.length > 0) {
result = JSON.parse(response.bodyAsText);
}
}
catch (error) {
var deserializationError = new RestError("Error \"" + error + "\" occurred in parsing the responseBody \" +\n \"while creating the PollingState for Long Running Operation- \"" + response.bodyAsText + "\"");
deserializationError.request = response.request;
deserializationError.response = response;
throw deserializationError;
}
return result;
}
function getStatusFromResponse(response, responseBody) {
if (responseBody == undefined) {
responseBody = getResponseBody(response);
}
var result;
switch (response.status) {
case 202:
result = "InProgress";
break;
case 204:
result = "Succeeded";
break;
case 201:
result = getProvisioningState(responseBody) || "InProgress";
break;
case 200:
var provisioningState = getProvisioningState(responseBody);
if (provisioningState) {
result = provisioningState;
}
else if (getAzureAsyncOperationHeaderValue(response) || getLocationHeaderValue(response)) {
result = "InProgress";
}
else {
result = "Succeeded";
}
break;
default:
result = "Failed";
break;
}
return result;
}
var terminalStates = ["Succeeded", "Failed", "Canceled", "Cancelled"];
/**
* Get whether or not a long-running operation with the provided status is finished.
* @param status The current status of a long-running operation.
* @returns Whether or not a long-running operation with the provided status is finished.
*/
export function isFinished(status) {
var result = false;
for (var _i = 0, terminalStates_1 = terminalStates; _i < terminalStates_1.length; _i++) {
var terminalState = terminalStates_1[_i];
if (longRunningOperationStatesEqual(status, terminalState)) {
result = true;
break;
}
}
return result;
}
export function longRunningOperationStatesEqual(lhs, rhs) {
var lhsLowerCased = lhs && lhs.toLowerCase();
var rhsLowerCased = rhs && rhs.toLowerCase();
return lhsLowerCased === rhsLowerCased;
}
/**
* Create a new long-running operation polling strategy based on the provided initial response.
* @param initialResponse The initial response to the long-running operation's initial request.
* @param azureServiceClient The AzureServiceClient that was used to send the initial request.
* @param options Any options that were provided to the initial request.
*/
export function createLROPollStrategyFromInitialResponse(initialResponse, azureServiceClient, options) {
var initialRequestMethod = initialResponse.request.method;
var initialResponseStatus = initialResponse.status;
var lroPollStrategyType;
if (getAzureAsyncOperationHeaderValue(initialResponse)) {
lroPollStrategyType = "AzureAsyncOperation";
}
else if (getLocationHeaderValue(initialResponse)) {
lroPollStrategyType = "Location";
}
else if (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH") {
lroPollStrategyType = "GetResource";
}
else if (initialResponseStatus !== 201 && initialResponseStatus !== 202 && !isFinished(getStatusFromResponse(initialResponse))) {
throw new Error("Can't determine long running operation polling strategy.");
}
var result;
if (lroPollStrategyType) {
var resource = getResponseBody(initialResponse);
var lroPollState = {
pollStrategyType: lroPollStrategyType,
options: options,
initialResponse: initialResponse,
mostRecentResponse: initialResponse,
mostRecentRequest: initialResponse.request,
azureAsyncOperationHeaderValue: getAzureAsyncOperationHeaderValue(initialResponse),
locationHeaderValue: getLocationHeaderValue(initialResponse),
resource: resource,
state: getStatusFromResponse(initialResponse, resource)
};
result = createLROPollStrategyFromPollState(azureServiceClient, lroPollState);
}
else {
result = undefined;
}
return result;
}
export function createLROPollStrategyFromPollState(azureServiceClient, lroPollState) {
var result;
switch (lroPollState.pollStrategyType) {
case "AzureAsyncOperation":
result = new AzureAsyncOperationLROPollStrategy(azureServiceClient, lroPollState);
break;
case "Location":
result = new LocationLROPollStrategy(azureServiceClient, lroPollState);
break;
case "GetResource":
result = new GetResourceLROPollStrategy(azureServiceClient, lroPollState);
break;
default:
throw new Error("Unrecognized LRO poll strategy type: \"" + lroPollState.pollStrategyType + "\"");
break;
}
return result;
}
function getLocationHeaderValue(response) {
return response.headers.get("location");
}
/**
* A long-running operation polling strategy that is based on the location header.
*/
var LocationLROPollStrategy = /** @class */ (function (_super) {
__extends(LocationLROPollStrategy, _super);
function LocationLROPollStrategy() {
return _super !== null && _super.apply(this, arguments) || this;
}
LocationLROPollStrategy.prototype.locationStrategyShouldDeserialize = function (parsedResponse) {
var shouldDeserialize = false;
var initialResponse = this._pollState.initialResponse;
var initialRequestMethod = initialResponse.request.method;
var statusCode = parsedResponse.status;
if (statusCode === 200 ||
(statusCode === 201 && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH")) ||
(statusCode === 204 && (initialRequestMethod === "DELETE" || initialRequestMethod === "POST"))) {
shouldDeserialize = true;
}
return shouldDeserialize;
};
/**
* Retrieve PUT operation status by polling from "location" header.
* @param {string} method - The HTTP method.
* @param {PollingState} pollingState - The object to persist current operation state.
*/
LocationLROPollStrategy.prototype.sendPollRequest = function () {
var lroPollState = this._pollState;
return this.updateOperationStatus(lroPollState.locationHeaderValue, this.locationStrategyShouldDeserialize.bind(this)).then(function (result) {
var locationHeaderValue = getLocationHeaderValue(result);
if (locationHeaderValue) {
lroPollState.locationHeaderValue = locationHeaderValue;
}
lroPollState.mostRecentResponse = result;
lroPollState.mostRecentRequest = result.request;
var initialResponse = lroPollState.initialResponse;
var initialRequestMethod = initialResponse.request.method;
var initialResponseStatusCode = initialResponse.status;
var statusCode = result.status;
if (statusCode === 202) {
lroPollState.state = "InProgress";
}
else if (statusCode === 200 ||
(statusCode === 201 && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH")) ||
(statusCode === 204 && (initialRequestMethod === "DELETE" || initialRequestMethod === "POST"))) {
lroPollState.state = "Succeeded";
lroPollState.resource = getResponseBody(result);
}
else if (statusCode === 404 && initialRequestMethod === "POST" &&
(initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) {
lroPollState.state = "Failed";
lroPollState.resource = getResponseBody(result);
}
else if (400 <= statusCode && statusCode <= 499) {
var resultBody = result.bodyAsText;
var errorMessage = resultBody;
try {
var resultObject = JSON.parse(resultBody);
errorMessage = resultObject.message;
}
catch (parseError) {
// Ignore the exception, use resultBody as the error message
}
throw new RestError(errorMessage, undefined, statusCode, stripRequest(result.request), result, resultBody);
}
else {
throw new Error("The response with status code " + statusCode + " from polling for long running operation url \"" + lroPollState.locationHeaderValue + "\" is not valid.");
}
});
};
LocationLROPollStrategy.prototype.isFinalStatusAcceptable = function () {
var lroPollState = this._pollState;
var initialResponse = lroPollState.initialResponse;
var initialResponseStatusCode = initialResponse.status;
return longRunningOperationStatesEqual(lroPollState.state, "Succeeded") ||
(initialResponse.request.method === "POST" && lroPollState.mostRecentResponse.status === 404 &&
(initialResponseStatusCode === 200 ||
initialResponseStatusCode === 201 ||
initialResponseStatusCode === 202));
};
LocationLROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () {
var lroPollState = this._pollState;
var initialResponse = lroPollState.initialResponse;
var result;
var initialRequestMethod = initialResponse.request.method;
var initialResponseStatusCode = initialResponse.status;
if (initialRequestMethod === "POST" && lroPollState.mostRecentResponse.status === 404 &&
(initialResponseStatusCode === 200 ||
initialResponseStatusCode === 201 ||
initialResponseStatusCode === 202)) {
result = false;
}
else {
result = _super.prototype.shouldDoFinalGetResourceRequest.call(this) ||
(initialRequestMethod === "POST" && initialResponseStatusCode === 201);
}
return result;
};
LocationLROPollStrategy.prototype.doFinalGetResourceRequest = function () {
var lroPollState = this._pollState;
var initialResponse = lroPollState.initialResponse;
var getResourceRequestUrl;
var initialResponseStatusCode = initialResponse.status;
var initialRequest = initialResponse.request;
if (initialRequest.method === "POST" &&
(initialResponseStatusCode === 200 ||
initialResponseStatusCode === 201 ||
initialResponseStatusCode === 202)) {
getResourceRequestUrl = lroPollState.locationHeaderValue;
}
else {
getResourceRequestUrl = initialRequest.url;
}
return this.updateState(getResourceRequestUrl, true);
};
return LocationLROPollStrategy;
}(LROPollStrategy));
function getAzureAsyncOperationHeaderValue(response) {
return response.headers.get("azure-asyncoperation");
}
/**
* A long-running operation polling strategy that is based on the azure-asyncoperation header.
*/
var AzureAsyncOperationLROPollStrategy = /** @class */ (function (_super) {
__extends(AzureAsyncOperationLROPollStrategy, _super);
function AzureAsyncOperationLROPollStrategy() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Retrieve operation status by polling from "azure-asyncoperation" header.
* @param {PollingState} pollingState - The object to persist current operation state.
* @param {boolean} inPostOrDelete - Invoked by Post Or Delete operation.
*/
AzureAsyncOperationLROPollStrategy.prototype.sendPollRequest = function () {
var lroPollState = this._pollState;
return this.updateOperationStatus(lroPollState.azureAsyncOperationHeaderValue, false).then(function (response) {
var statusCode = response.status;
var parsedResponse = response.parsedBody;
if (statusCode !== 200 && statusCode !== 201 && statusCode !== 202 && statusCode !== 204) {
var error = new RestError("Invalid status code (" + statusCode + ") with response body \"" + response.bodyAsText + "\" occurred when polling for operation status.");
error.statusCode = statusCode;
error.request = stripRequest(response.request);
error.response = response;
error.body = parsedResponse;
throw error;
}
if (!parsedResponse) {
throw new Error("The response from long running operation does not contain a body.");
}
else if (!parsedResponse.status) {
throw new Error("The response \"" + response.bodyAsText + "\" from long running operation does not contain the status property.");
}
var azureAsyncOperationHeaderValue = getAzureAsyncOperationHeaderValue(response);
if (azureAsyncOperationHeaderValue) {
lroPollState.azureAsyncOperationHeaderValue = azureAsyncOperationHeaderValue;
}
lroPollState.state = parsedResponse.status;
lroPollState.mostRecentResponse = response;
lroPollState.mostRecentRequest = response.request;
lroPollState.resource = getResponseBody(response);
});
};
AzureAsyncOperationLROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () {
var lroPollState = this._pollState;
var initialResponse = lroPollState.initialResponse;
var initialRequestMethod = initialResponse.request.method;
var result = false;
if (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH") {
result = true;
}
else {
if (lroPollState.locationHeaderValue) {
var initialResponseStatusCode = initialResponse.status;
if (initialRequestMethod === "POST") {
result = initialResponseStatusCode === 200 || initialResponseStatusCode === 201;
}
else if (initialRequestMethod === "DELETE") {
result = initialResponseStatusCode === 200 || initialResponseStatusCode === 202;
}
}
}
return result;
};
AzureAsyncOperationLROPollStrategy.prototype.doFinalGetResourceRequest = function () {
var lroPollState = this._pollState;
var locationHeaderValue = lroPollState.locationHeaderValue;
var initialResponse = lroPollState.initialResponse;
var initialRequest = initialResponse.request;
var getResourceRequestUrl = initialRequest.url;
if (locationHeaderValue) {
var initialRequestMethod = initialRequest.method;
var initialResponseStatusCode = initialResponse.status;
if (initialRequestMethod === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) {
getResourceRequestUrl = locationHeaderValue;
}
else if (initialRequestMethod === "DELETE" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 202)) {
getResourceRequestUrl = locationHeaderValue;
}
}
return this.updateState(getResourceRequestUrl, true);
};
AzureAsyncOperationLROPollStrategy.prototype.isFinalStatusAcceptable = function () {
var lroPollState = this._pollState;
var initialResponse = lroPollState.initialResponse;
var initialResponseStatusCode = initialResponse.status;
return longRunningOperationStatesEqual(lroPollState.state, "Succeeded") ||
(initialResponse.request.method === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201));
};
return AzureAsyncOperationLROPollStrategy;
}(LROPollStrategy));
/**
* A long-running operation polling strategy that is based on the resource's provisioning state.
*/
var GetResourceLROPollStrategy = /** @class */ (function (_super) {
__extends(GetResourceLROPollStrategy, _super);
function GetResourceLROPollStrategy() {
return _super !== null && _super.apply(this, arguments) || this;
}
GetResourceLROPollStrategy.prototype.sendPollRequest = function () {
var lroPollState = this._pollState;
return this.updateOperationStatus(lroPollState.initialResponse.request.url, false).then(function (result) {
var statusCode = result.status;
var responseBody = result.parsedBody;
if (statusCode !== 200 && statusCode !== 201 && statusCode !== 202 && statusCode !== 204) {
var error = new RestError("Invalid status code with response body \"" + result.bodyAsText + "\" occurred when polling for operation status.");
error.statusCode = statusCode;
error.request = stripRequest(result.request);
error.response = result;
error.body = responseBody;
throw error;
}
if (!result.parsedBody) {
throw new Error("The response from long running operation does not contain a body.");
}
lroPollState.state = getProvisioningState(result.parsedBody) || "Succeeded";
lroPollState.mostRecentResponse = result;
lroPollState.mostRecentRequest = result.request;
lroPollState.resource = getResponseBody(result);
});
};
GetResourceLROPollStrategy.prototype.isFinalStatusAcceptable = function () {
return longRunningOperationStatesEqual(this._pollState.state, "Succeeded");
};
GetResourceLROPollStrategy.prototype.doFinalGetResourceRequest = function () {
return this.sendPollRequest();
};
return GetResourceLROPollStrategy;
}(LROPollStrategy));
//# sourceMappingURL=lroPollStrategy.js.map