package.dist.src.internal.grpc.retry-interceptor.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sdk Show documentation
Show all versions of sdk Show documentation
Client SDK for Momento services
The newest version!
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetryInterceptor = void 0;
// This is temporary work around defining our own interceptor to power re-try's
// Longer term with this proposal re-try's should be added to grpc core, and we
// can leverage by defining a retry policy.
// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#grpc-retry-design
// For now we use re-try interceptor inspired by example here in interceptor proposal for nodejs grpc core
// https://github.com/grpc/proposal/blob/master/L5-node-client-interceptors.md#advanced-examples
// Main difference is that we maintain a allow list of retryable status codes vs trying all.
const grpc_js_1 = require("@grpc/grpc-js");
const constants_1 = require("@grpc/grpc-js/build/src/constants");
const no_retry_strategy_1 = require("../../config/retry/no-retry-strategy");
class RetryInterceptor {
// TODO: We need to send retry count information to the server so that we
// will have some visibility into how often this is happening to customers:
// https://github.com/momentohq/client-sdk-nodejs/issues/80
static createRetryInterceptor(props) {
var _a, _b;
const logger = props.loggerFactory.getLogger(RetryInterceptor.name);
const retryStrategy = (_a = props.retryStrategy) !== null && _a !== void 0 ? _a : new no_retry_strategy_1.NoRetryStrategy({ loggerFactory: props.loggerFactory });
const overallRequestTimeoutMs = props.overallRequestTimeoutMs;
const deadlineOffset = (_b = retryStrategy.responseDataReceivedTimeoutMillis) !== null && _b !== void 0 ? _b : props.overallRequestTimeoutMs;
logger.trace(`Creating RetryInterceptor (for ${props.clientName}); overall request timeout offset: ${overallRequestTimeoutMs} ms; retry strategy responseDataRecievedTimeoutMillis: ${String(retryStrategy === null || retryStrategy === void 0 ? void 0 : retryStrategy.responseDataReceivedTimeoutMillis)}; deadline offset: ${deadlineOffset} ms`);
return (options, nextCall) => {
logger.trace(`Entering RetryInterceptor (for ${props.clientName}); overall request timeout offset: ${overallRequestTimeoutMs} ms; deadline offset: ${String(deadlineOffset)}`);
const overallDeadline = calculateDeadline(overallRequestTimeoutMs);
logger.trace(`Setting initial deadline (for ${props.clientName}) based on offset: ${deadlineOffset} ms`);
let nextDeadline = calculateDeadline(deadlineOffset);
options.deadline = nextDeadline;
let savedMetadata;
let savedSendMessage;
let savedReceiveMessage;
let savedMessageNext;
return new grpc_js_1.InterceptingCall(nextCall(options), {
start: function (metadata, listener, next) {
savedMetadata = metadata;
const newListener = {
onReceiveMessage: function (message, next) {
savedReceiveMessage = message;
savedMessageNext = next;
},
onReceiveStatus: function (status,
// NOTE: we have to use `any` here because that is what is used in the grpc-js type definitions
// eslint-disable-next-line @typescript-eslint/no-explicit-any
next) {
let attempts = 0;
const retry = function (message, metadata) {
var _a;
logger.debug(`Retrying request: path: ${options.method_definition.path}; deadline was: ${String((_a = options.deadline) === null || _a === void 0 ? void 0 : _a.toISOString())}, overall deadline is: ${overallDeadline.toISOString()}`);
if (new Date(Date.now()) >= overallDeadline) {
logger.debug(`Request not eligible for retry: path: ${options.method_definition.path}; overall deadline exceeded: ${overallDeadline.toISOString()}`);
savedMessageNext(savedReceiveMessage);
next(status);
return;
}
nextDeadline = calculateDeadline(deadlineOffset);
logger.debug(`Setting next deadline (via offset of ${deadlineOffset} ms) to: ${nextDeadline.toISOString()}`);
options.deadline = nextDeadline;
const newCall = nextCall(options);
newCall.start(metadata, {
onReceiveMessage: function (message) {
savedReceiveMessage = message;
},
onReceiveStatus: function (status) {
const whenToRetry = retryStrategy.determineWhenToRetryRequest({
grpcStatus: status,
grpcRequest: options.method_definition,
attemptNumber: attempts,
requestMetadata: metadata,
});
if (whenToRetry === null) {
logger.debug(`Request not eligible for retry: path: ${options.method_definition.path}; retryable status code: ${status.code}; number of attempts (${attempts}).`);
savedMessageNext(savedReceiveMessage);
next(status);
}
else {
attempts++;
logger.debug(`Request eligible for retry: path: ${options.method_definition.path}; response status code: ${status.code}; number of attempts (${attempts}); will retry in ${whenToRetry}ms`);
setTimeout(() => retry(message, metadata), whenToRetry);
}
},
});
newCall.sendMessage(savedSendMessage);
newCall.halfClose();
};
if (status.code === constants_1.Status.OK) {
savedMessageNext(savedReceiveMessage);
next(status);
}
else {
const whenToRetry = retryStrategy.determineWhenToRetryRequest({
grpcStatus: status,
grpcRequest: options.method_definition,
attemptNumber: attempts,
requestMetadata: metadata,
});
if (whenToRetry === null) {
logger.debug(`Request not eligible for retry: path: ${options.method_definition.path}; response status code: ${status.code}.`);
savedMessageNext(savedReceiveMessage);
next(status);
}
else {
attempts++;
logger.debug(`Request eligible for retry: path: ${options.method_definition.path}; response status code: ${status.code}; number of attempts (${attempts}); will retry in ${whenToRetry}ms`);
setTimeout(() => retry(savedSendMessage, savedMetadata), whenToRetry);
}
}
},
};
next(metadata, newListener);
},
sendMessage: function (message, next) {
savedSendMessage = message;
next(message);
},
});
};
}
}
exports.RetryInterceptor = RetryInterceptor;
function calculateDeadline(offsetMillis) {
const deadline = new Date(Date.now());
deadline.setMilliseconds(deadline.getMilliseconds() + offsetMillis);
return deadline;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0cnktaW50ZXJjZXB0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaW50ZXJuYWwvZ3JwYy9yZXRyeS1pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrRUFBK0U7QUFDL0UsK0VBQStFO0FBQy9FLDJDQUEyQztBQUMzQyxzRkFBc0Y7QUFDdEYsMEdBQTBHO0FBQzFHLGdHQUFnRztBQUNoRyw0RkFBNEY7QUFDNUYsMkNBTXVCO0FBRXZCLGlFQUF5RDtBQUV6RCw0RUFBcUU7QUFTckUsTUFBYSxnQkFBZ0I7SUFDM0IseUVBQXlFO0lBQ3pFLDJFQUEyRTtJQUMzRSwyREFBMkQ7SUFDcEQsTUFBTSxDQUFDLHNCQUFzQixDQUNsQyxLQUE0Qjs7UUFFNUIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFcEUsTUFBTSxhQUFhLEdBQ2pCLE1BQUEsS0FBSyxDQUFDLGFBQWEsbUNBQ25CLElBQUksbUNBQWUsQ0FBQyxFQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYSxFQUFDLENBQUMsQ0FBQztRQUU1RCxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQztRQUM5RCxNQUFNLGNBQWMsR0FDbEIsTUFBQSxhQUFhLENBQUMsaUNBQWlDLG1DQUMvQyxLQUFLLENBQUMsdUJBQXVCLENBQUM7UUFFaEMsTUFBTSxDQUFDLEtBQUssQ0FDVixrQ0FDRSxLQUFLLENBQUMsVUFDUixzQ0FBc0MsdUJBQXVCLDBEQUEwRCxNQUFNLENBQzNILGFBQWEsYUFBYixhQUFhLHVCQUFiLGFBQWEsQ0FBRSxpQ0FBaUMsQ0FDakQsc0JBQXNCLGNBQWMsS0FBSyxDQUMzQyxDQUFDO1FBRUYsT0FBTyxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRTtZQUMzQixNQUFNLENBQUMsS0FBSyxDQUNWLGtDQUNF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QWdCLENBQUMsbUJBQW1CLENBQUMsQ0FBQztvQ0FDdEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2lDQUNkO3FDQUFNO29DQUNMLFFBQVEsRUFBRSxDQUFDO29DQUNYLE1BQU0sQ0FBQyxLQUFLLENBQ1YscUNBQXFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLDJCQUEyQixNQUFNLENBQUMsSUFBSSx5QkFBeUIsUUFBUSxvQkFBb0IsV0FBVyxJQUFJLENBQzlLLENBQUM7b0NBQ0YsVUFBVSxDQUNSLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxhQUFhLENBQUMsRUFDNUMsV0FBVyxDQUNaLENBQUM7aUNBQ0g7NkJBQ0Y7d0JBQ0gsQ0FBQztxQkFDRixDQUFDO29CQUNGLElBQUksQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQzlCLENBQUM7Z0JBQ0QsV0FBVyxFQUFFLFVBQVUsT0FBTyxFQUFFLElBQUk7b0JBQ2xDLGdCQUFnQixHQUFHLE9BQU8sQ0FBQztvQkFDM0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNoQixDQUFDO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBaEtELDRDQWdLQztBQUVELFNBQVMsaUJBQWlCLENBQUMsWUFBb0I7SUFDN0MsTUFBTSxRQUFRLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDdEMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLEdBQUcsWUFBWSxDQUFDLENBQUM7SUFDcEUsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIFRoaXMgaXMgdGVtcG9yYXJ5IHdvcmsgYXJvdW5kIGRlZmluaW5nIG91ciBvd24gaW50ZXJjZXB0b3IgdG8gcG93ZXIgcmUtdHJ5J3Ncbi8vIExvbmdlciB0ZXJtIHdpdGggdGhpcyBwcm9wb3NhbCByZS10cnkncyBzaG91bGQgYmUgYWRkZWQgdG8gZ3JwYyBjb3JlLCBhbmQgd2Vcbi8vIGNhbiBsZXZlcmFnZSBieSBkZWZpbmluZyBhIHJldHJ5IHBvbGljeS5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9ncnBjL3Byb3Bvc2FsL2Jsb2IvbWFzdGVyL0E2LWNsaWVudC1yZXRyaWVzLm1kI2dycGMtcmV0cnktZGVzaWduXG4vLyBGb3Igbm93IHdlIHVzZSByZS10cnkgaW50ZXJjZXB0b3IgaW5zcGlyZWQgYnkgZXhhbXBsZSBoZXJlIGluIGludGVyY2VwdG9yIHByb3Bvc2FsIGZvciBub2RlanMgZ3JwYyBjb3JlXG4vLyBodHRwczovL2dpdGh1Yi5jb20vZ3JwYy9wcm9wb3NhbC9ibG9iL21hc3Rlci9MNS1ub2RlLWNsaWVudC1pbnRlcmNlcHRvcnMubWQjYWR2YW5jZWQtZXhhbXBsZXNcbi8vIE1haW4gZGlmZmVyZW5jZSBpcyB0aGF0IHdlIG1haW50YWluIGEgYWxsb3cgbGlzdCBvZiByZXRyeWFibGUgc3RhdHVzIGNvZGVzIHZzIHRyeWluZyBhbGwuXG5pbXBvcnQge1xuICBJbnRlcmNlcHRpbmdDYWxsLFxuICBJbnRlcmNlcHRvcixcbiAgTGlzdGVuZXIsXG4gIE1ldGFkYXRhLFxuICBTdGF0dXNPYmplY3QsXG59IGZyb20gJ0BncnBjL2dycGMtanMnO1xuaW1wb3J0IHtSZXRyeVN0cmF0ZWd5fSBmcm9tICcuLi8uLi9jb25maWcvcmV0cnkvcmV0cnktc3RyYXRlZ3knO1xuaW1wb3J0IHtTdGF0dXN9IGZyb20gJ0BncnBjL2dycGMtanMvYnVpbGQvc3JjL2NvbnN0YW50cyc7XG5pbXBvcnQge01vbWVudG9Mb2dnZXJGYWN0b3J5fSBmcm9tICcuLi8uLi8nO1xuaW1wb3J0IHtOb1JldHJ5U3RyYXRlZ3l9IGZyb20gJy4uLy4uL2NvbmZpZy9yZXRyeS9uby1yZXRyeS1zdHJhdGVneSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmV0cnlJbnRlcmNlcHRvclByb3BzIHtcbiAgY2xpZW50TmFtZTogc3RyaW5nO1xuICBsb2dnZXJGYWN0b3J5OiBNb21lbnRvTG9nZ2VyRmFjdG9yeTtcbiAgb3ZlcmFsbFJlcXVlc3RUaW1lb3V0TXM6IG51bWJlcjtcbiAgcmV0cnlTdHJhdGVneT86IFJldHJ5U3RyYXRlZ3k7XG59XG5cbmV4cG9ydCBjbGFzcyBSZXRyeUludGVyY2VwdG9yIHtcbiAgLy8gVE9ETzogV2UgbmVlZCB0byBzZW5kIHJldHJ5IGNvdW50IGluZm9ybWF0aW9uIHRvIHRoZSBzZXJ2ZXIgc28gdGhhdCB3ZVxuICAvLyB3aWxsIGhhdmUgc29tZSB2aXNpYmlsaXR5IGludG8gaG93IG9mdGVuIHRoaXMgaXMgaGFwcGVuaW5nIHRvIGN1c3RvbWVyczpcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL21vbWVudG9ocS9jbGllbnQtc2RrLW5vZGVqcy9pc3N1ZXMvODBcbiAgcHVibGljIHN0YXRpYyBjcmVhdGVSZXRyeUludGVyY2VwdG9yKFxuICAgIHByb3BzOiBSZXRyeUludGVyY2VwdG9yUHJvcHNcbiAgKTogSW50ZXJjZXB0b3Ige1xuICAgIGNvbnN0IGxvZ2dlciA9IHByb3BzLmxvZ2dlckZhY3RvcnkuZ2V0TG9nZ2VyKFJldHJ5SW50ZXJjZXB0b3IubmFtZSk7XG5cbiAgICBjb25zdCByZXRyeVN0cmF0ZWd5OiBSZXRyeVN0cmF0ZWd5ID1cbiAgICAgIHByb3BzLnJldHJ5U3RyYXRlZ3kgPz9cbiAgICAgIG5ldyBOb1JldHJ5U3RyYXRlZ3koe2xvZ2dlckZhY3Rvcnk6IHByb3BzLmxvZ2dlckZhY3Rvcnl9KTtcblxuICAgIGNvbnN0IG92ZXJhbGxSZXF1ZXN0VGltZW91dE1zID0gcHJvcHMub3ZlcmFsbFJlcXVlc3RUaW1lb3V0TXM7XG4gICAgY29uc3QgZGVhZGxpbmVPZmZzZXQgPVxuICAgICAgcmV0cnlTdHJhdGVneS5yZXNwb25zZURhdGFSZWNlaXZlZFRpbWVvdXRNaWxsaXMgPz9cbiAgICAgIHByb3BzLm92ZXJhbGxSZXF1ZXN0VGltZW91dE1zO1xuXG4gICAgbG9nZ2VyLnRyYWNlKFxuICAgICAgYENyZWF0aW5nIFJldHJ5SW50ZXJjZXB0b3IgKGZvciAke1xuICAgICAgICBwcm9wcy5jbGllbnROYW1lXG4gICAgICB9KTsgb3ZlcmFsbCByZXF1ZXN0IHRpbWVvdXQgb2Zmc2V0OiAke292ZXJhbGxSZXF1ZXN0VGltZW91dE1zfSBtczsgcmV0cnkgc3RyYXRlZ3kgcmVzcG9uc2VEYXRhUmVjaWV2ZWRUaW1lb3V0TWlsbGlzOiAke1N0cmluZyhcbiAgICAgICAgcmV0cnlTdHJhdGVneT8ucmVzcG9uc2VEYXRhUmVjZWl2ZWRUaW1lb3V0TWlsbGlzXG4gICAgICApfTsgZGVhZGxpbmUgb2Zmc2V0OiAke2RlYWRsaW5lT2Zmc2V0fSBtc2BcbiAgICApO1xuXG4gICAgcmV0dXJuIChvcHRpb25zLCBuZXh0Q2FsbCkgPT4ge1xuICAgICAgbG9nZ2VyLnRyYWNlKFxuICAgICAgICBgRW50ZXJpbmcgUmV0cnlJbnRlcmNlcHRvciAoZm9yICR7XG4gICAgICAgICAgcHJvcHMuY2xpZW50TmFtZVxuICAgICAgICB9KTsgb3ZlcmFsbCByZXF1ZXN0IHRpbWVvdXQgb2Zmc2V0OiAke292ZXJhbGxSZXF1ZXN0VGltZW91dE1zfSBtczsgZGVhZGxpbmUgb2Zmc2V0OiAke1N0cmluZyhcbiAgICAgICAgICBkZWFkbGluZU9mZnNldFxuICAgICAgICApfWBcbiAgICAgICk7XG4gICAgICBjb25zdCBvdmVyYWxsRGVhZGxpbmUgPSBjYWxjdWxhdGVEZWFkbGluZShvdmVyYWxsUmVxdWVzdFRpbWVvdXRNcyk7XG5cbiAgICAgIGxvZ2dlci50cmFjZShcbiAgICAgICAgYFNldHRpbmcgaW5pdGlhbCBkZWFkbGluZSAoZm9yICR7cHJvcHMuY2xpZW50TmFtZX0pIGJhc2VkIG9uIG9mZnNldDogJHtkZWFkbGluZU9mZnNldH0gbXNgXG4gICAgICApO1xuICAgICAgbGV0IG5leHREZWFkbGluZSA9IGNhbGN1bGF0ZURlYWRsaW5lKGRlYWRsaW5lT2Zmc2V0KTtcblxuICAgICAgb3B0aW9ucy5kZWFkbGluZSA9IG5leHREZWFkbGluZTtcblxuICAgICAgbGV0IHNhdmVkTWV0YWRhdGE6IE1ldGFkYXRhO1xuICAgICAgbGV0IHNhdmVkU2VuZE1lc3NhZ2U6IHVua25vd247XG4gICAgICBsZXQgc2F2ZWRSZWNlaXZlTWVzc2FnZTogdW5rbm93bjtcbiAgICAgIGxldCBzYXZlZE1lc3NhZ2VOZXh0OiAoYXJnMDogdW5rbm93bikgPT4gdm9pZDtcbiAgICAgIHJldHVybiBuZXcgSW50ZXJjZXB0aW5nQ2FsbChuZXh0Q2FsbChvcHRpb25zKSwge1xuICAgICAgICBzdGFydDogZnVuY3Rpb24gKG1ldGFkYXRhLCBsaXN0ZW5lciwgbmV4dCkge1xuICAgICAgICAgIHNhdmVkTWV0YWRhdGEgPSBtZXRhZGF0YTtcbiAgICAgICAgICBjb25zdCBuZXdMaXN0ZW5lcjogTGlzdGVuZXIgPSB7XG4gICAgICAgICAgICBvblJlY2VpdmVNZXNzYWdlOiBmdW5jdGlvbiAoXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IHVua25vd24sXG4gICAgICAgICAgICAgIG5leHQ6IChhcmcwOiB1bmtub3duKSA9PiB2b2lkXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgc2F2ZWRSZWNlaXZlTWVzc2FnZSA9IG1lc3NhZ2U7XG4gICAgICAgICAgICAgIHNhdmVkTWVzc2FnZU5leHQgPSBuZXh0O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uUmVjZWl2ZVN0YXR1czogZnVuY3Rpb24gKFxuICAgICAgICAgICAgICBzdGF0dXM6IFN0YXR1c09iamVjdCxcbiAgICAgICAgICAgICAgLy8gTk9URTogd2UgaGF2ZSB0byB1c2UgYGFueWAgaGVyZSBiZWNhdXNlIHRoYXQgaXMgd2hhdCBpcyB1c2VkIGluIHRoZSBncnBjLWpzIHR5cGUgZGVmaW5pdGlvbnNcbiAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICAgICAgICAgICAgbmV4dDogKGFyZzA6IGFueSkgPT4gdm9pZFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIGxldCBhdHRlbXB0cyA9IDA7XG4gICAgICAgICAgICAgIGNvbnN0IHJldHJ5ID0gZnVuY3Rpb24gKG1lc3NhZ2U6IHVua25vd24sIG1ldGFkYXRhOiBNZXRhZGF0YSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgIGBSZXRyeWluZyByZXF1ZXN0OiBwYXRoOiAke1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLm1ldGhvZF9kZWZpbml0aW9uLnBhdGhcbiAgICAgICAgICAgICAgICAgIH07IGRlYWRsaW5lIHdhczogJHtTdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgIChvcHRpb25zLmRlYWRsaW5lIGFzIERhdGUgfCB1bmRlZmluZWQpPy50b0lTT1N0cmluZygpXG4gICAgICAgICAgICAgICAgICApfSwgb3ZlcmFsbCBkZWFkbGluZSBpczogJHtvdmVyYWxsRGVhZGxpbmUudG9JU09TdHJpbmcoKX1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZiAobmV3IERhdGUoRGF0ZS5ub3coKSkgPj0gb3ZlcmFsbERlYWRsaW5lKSB7XG4gICAgICAgICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAgIGBSZXF1ZXN0IG5vdCBlbGlnaWJsZSBmb3IgcmV0cnk6IHBhdGg6ICR7XG4gICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5tZXRob2RfZGVmaW5pdGlvbi5wYXRoXG4gICAgICAgICAgICAgICAgICAgIH07IG92ZXJhbGwgZGVhZGxpbmUgZXhjZWVkZWQ6ICR7b3ZlcmFsbERlYWRsaW5lLnRvSVNPU3RyaW5nKCl9YFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHNhdmVkTWVzc2FnZU5leHQoc2F2ZWRSZWNlaXZlTWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICBuZXh0KHN0YXR1cyk7XG4gICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG5leHREZWFkbGluZSA9IGNhbGN1bGF0ZURlYWRsaW5lKGRlYWRsaW5lT2Zmc2V0KTtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICBgU2V0dGluZyBuZXh0IGRlYWRsaW5lICh2aWEgb2Zmc2V0IG9mICR7ZGVhZGxpbmVPZmZzZXR9IG1zKSB0bzogJHtuZXh0RGVhZGxpbmUudG9JU09TdHJpbmcoKX1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmRlYWRsaW5lID0gbmV4dERlYWRsaW5lO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgbmV3Q2FsbCA9IG5leHRDYWxsKG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIG5ld0NhbGwuc3RhcnQobWV0YWRhdGEsIHtcbiAgICAgICAgICAgICAgICAgIG9uUmVjZWl2ZU1lc3NhZ2U6IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNhdmVkUmVjZWl2ZU1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIG9uUmVjZWl2ZVN0YXR1czogZnVuY3Rpb24gKHN0YXR1cykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB3aGVuVG9SZXRyeSA9XG4gICAgICAgICAgICAgICAgICAgICAgcmV0cnlTdHJhdGVneS5kZXRlcm1pbmVXaGVuVG9SZXRyeVJlcXVlc3Qoe1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JwY1N0YXR1czogc3RhdHVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgZ3JwY1JlcXVlc3Q6IG9wdGlvbnMubWV0aG9kX2RlZmluaXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBhdHRlbXB0TnVtYmVyOiBhdHRlbXB0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RNZXRhZGF0YTogbWV0YWRhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHdoZW5Ub1JldHJ5ID09PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICAgICAgYFJlcXVlc3Qgbm90IGVsaWdpYmxlIGZvciByZXRyeTogcGF0aDogJHtvcHRpb25zLm1ldGhvZF9kZWZpbml0aW9uLnBhdGh9OyByZXRyeWFibGUgc3RhdHVzIGNvZGU6ICR7c3RhdHVzLmNvZGV9OyBudW1iZXIgb2YgYXR0ZW1wdHMgKCR7YXR0ZW1wdHN9KS5gXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICBzYXZlZE1lc3NhZ2VOZXh0KHNhdmVkUmVjZWl2ZU1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICAgIG5leHQoc3RhdHVzKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICBhdHRlbXB0cysrO1xuICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIGBSZXF1ZXN0IGVsaWdpYmxlIGZvciByZXRyeTogcGF0aDogJHtvcHRpb25zLm1ldGhvZF9kZWZpbml0aW9uLnBhdGh9OyByZXNwb25zZSBzdGF0dXMgY29kZTogJHtzdGF0dXMuY29kZX07IG51bWJlciBvZiBhdHRlbXB0cyAoJHthdHRlbXB0c30pOyB3aWxsIHJldHJ5IGluICR7d2hlblRvUmV0cnl9bXNgXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHJldHJ5KG1lc3NhZ2UsIG1ldGFkYXRhKSwgd2hlblRvUmV0cnkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIG5ld0NhbGwuc2VuZE1lc3NhZ2Uoc2F2ZWRTZW5kTWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgbmV3Q2FsbC5oYWxmQ2xvc2UoKTtcbiAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICBpZiAoc3RhdHVzLmNvZGUgPT09IFN0YXR1cy5PSykge1xuICAgICAgICAgICAgICAgIHNhdmVkTWVzc2FnZU5leHQoc2F2ZWRSZWNlaXZlTWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgbmV4dChzdGF0dXMpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnN0IHdoZW5Ub1JldHJ5ID0gcmV0cnlTdHJhdGVneS5kZXRlcm1pbmVXaGVuVG9SZXRyeVJlcXVlc3Qoe1xuICAgICAgICAgICAgICAgICAgZ3JwY1N0YXR1czogc3RhdHVzLFxuICAgICAgICAgICAgICAgICAgZ3JwY1JlcXVlc3Q6IG9wdGlvbnMubWV0aG9kX2RlZmluaXRpb24sXG4gICAgICAgICAgICAgICAgICBhdHRlbXB0TnVtYmVyOiBhdHRlbXB0cyxcbiAgICAgICAgICAgICAgICAgIHJlcXVlc3RNZXRhZGF0YTogbWV0YWRhdGEsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKHdoZW5Ub1JldHJ5ID09PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgICAgICAgIGBSZXF1ZXN0IG5vdCBlbGlnaWJsZSBmb3IgcmV0cnk6IHBhdGg6ICR7b3B0aW9ucy5tZXRob2RfZGVmaW5pdGlvbi5wYXRofTsgcmVzcG9uc2Ugc3RhdHVzIGNvZGU6ICR7c3RhdHVzLmNvZGV9LmBcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICBzYXZlZE1lc3NhZ2VOZXh0KHNhdmVkUmVjZWl2ZU1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgbmV4dChzdGF0dXMpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBhdHRlbXB0cysrO1xuICAgICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICBgUmVxdWVzdCBlbGlnaWJsZSBmb3IgcmV0cnk6IHBhdGg6ICR7b3B0aW9ucy5tZXRob2RfZGVmaW5pdGlvbi5wYXRofTsgcmVzcG9uc2Ugc3RhdHVzIGNvZGU6ICR7c3RhdHVzLmNvZGV9OyBudW1iZXIgb2YgYXR0ZW1wdHMgKCR7YXR0ZW1wdHN9KTsgd2lsbCByZXRyeSBpbiAke3doZW5Ub1JldHJ5fW1zYFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgICAgICgpID0+IHJldHJ5KHNhdmVkU2VuZE1lc3NhZ2UsIHNhdmVkTWV0YWRhdGEpLFxuICAgICAgICAgICAgICAgICAgICB3aGVuVG9SZXRyeVxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgICBuZXh0KG1ldGFkYXRhLCBuZXdMaXN0ZW5lcik7XG4gICAgICAgIH0sXG4gICAgICAgIHNlbmRNZXNzYWdlOiBmdW5jdGlvbiAobWVzc2FnZSwgbmV4dCkge1xuICAgICAgICAgIHNhdmVkU2VuZE1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgICAgICAgIG5leHQobWVzc2FnZSk7XG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9O1xuICB9XG59XG5cbmZ1bmN0aW9uIGNhbGN1bGF0ZURlYWRsaW5lKG9mZnNldE1pbGxpczogbnVtYmVyKTogRGF0ZSB7XG4gIGNvbnN0IGRlYWRsaW5lID0gbmV3IERhdGUoRGF0ZS5ub3coKSk7XG4gIGRlYWRsaW5lLnNldE1pbGxpc2Vjb25kcyhkZWFkbGluZS5nZXRNaWxsaXNlY29uZHMoKSArIG9mZnNldE1pbGxpcyk7XG4gIHJldHVybiBkZWFkbGluZTtcbn1cbiJdfQ==