@selfage/service_handler
Version:
Http-based service handlers on top of expressjs.
147 lines • 23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseRemoteCallHandler = void 0;
const getStream = require("get-stream");
const promClient = require("prom-client");
const stream_message_reader_1 = require("./stream_message_reader");
const http_error_1 = require("@selfage/http_error");
const parser_1 = require("@selfage/message/parser");
const serializer_1 = require("@selfage/message/serializer");
const stringifier_1 = require("@selfage/message/stringifier");
const service_descriptor_1 = require("@selfage/service_descriptor");
let TOTAL_COUNTER = new promClient.Counter({
name: "remote_calls_total",
help: "The total number of calls received.",
labelNames: ["path"],
});
let FAILURE_COUNTER = new promClient.Counter({
name: "remote_calls_failure",
help: "The number of failed calls.",
labelNames: ["path", "errorCode"],
});
class BaseRemoteCallHandler {
static create(allowOrigin) {
return new BaseRemoteCallHandler(allowOrigin);
}
constructor(allowOrigin) {
this.allowOrigin = allowOrigin;
}
async handle(remoteCallHandler, req, res) {
TOTAL_COUNTER.inc({
path: remoteCallHandler.descriptor.service.path +
remoteCallHandler.descriptor.path,
});
// Add CORS rules.
res.setHeader("Access-Control-Allow-Origin", this.allowOrigin);
res.setHeader("Access-Control-Allow-Methods", "*");
res.setHeader("Access-Control-Allow-Headers", "*");
let requestId = `${Math.floor(Date.now() / 1000)}-${Math.floor(Math.random() * 10000)}`;
let loggingPrefix = `Request ${requestId}:`;
console.info(`${loggingPrefix} ${req.url}.`);
try {
await this.handleRequest(loggingPrefix, remoteCallHandler, req, res);
}
catch (e) {
console.error(`${loggingPrefix} ${e.stack ?? e.message ?? e}`);
let statusCode = e.statusCode ?? http_error_1.StatusCode.InternalServerError;
FAILURE_COUNTER.inc({
path: remoteCallHandler.descriptor.service.path +
remoteCallHandler.descriptor.path,
errorCode: statusCode,
});
res.sendStatus(statusCode);
await new Promise((resolve) => res.end(resolve));
}
}
async handleRequest(loggingPrefix, remoteCallHandler, req, res) {
let args = [loggingPrefix];
let legacyJsonQuery = false;
if (remoteCallHandler.descriptor.body.messageType) {
let bodyBuffer = await getStream.buffer(req, {
maxBuffer: 1 * 1024 * 1024,
});
if (req.headers["content-type"] === "application/json") {
legacyJsonQuery = true;
let bodyStr = bodyBuffer.toString("utf-8");
args.push(this.parse(loggingPrefix, bodyStr, remoteCallHandler.descriptor.body.messageType, `body`));
}
else {
args.push(this.deserialize(loggingPrefix, bodyBuffer, remoteCallHandler.descriptor.body.messageType, `body`));
}
}
else if (remoteCallHandler.descriptor.body.streamMessageType) {
// NOTE: Doesn't work! Client side requires http2 to enable custom streaming with unspecified content length.
let streamReader = new stream_message_reader_1.StreamMessageReader(req, remoteCallHandler.descriptor.body.streamMessageType);
args.push(streamReader);
}
else if (remoteCallHandler.descriptor.body.primitiveType ===
service_descriptor_1.PrimitveTypeForBody.BYTES) {
args.push(req);
}
else {
throw (0, http_error_1.newInternalServerErrorError)(`Unsupported server request body.`);
}
if (remoteCallHandler.descriptor.metadata) {
args.push(this.destringify(loggingPrefix, req.query[remoteCallHandler.descriptor.metadata.key], remoteCallHandler.descriptor.metadata.type, `metadata`));
}
if (remoteCallHandler.descriptor.authKey) {
let authStr = req.header(remoteCallHandler.descriptor.authKey);
if (!authStr) {
throw (0, http_error_1.newUnauthorizedError)(`No auth string is found in the header ${remoteCallHandler.descriptor.authKey}.`);
}
args.push(authStr);
}
let response = await remoteCallHandler.handle(...args);
await new Promise((resolve) => {
if (legacyJsonQuery) {
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(response), resolve);
}
else {
res.setHeader("Content-Type", "application/octet-stream");
res.end((0, serializer_1.serializeMessage)(response, remoteCallHandler.descriptor.response.messageType), resolve);
}
});
}
destringify(loggingPrefix, value, messageDescriptor, what) {
let ret;
try {
ret = (0, stringifier_1.destringifyMessage)(value, messageDescriptor);
}
catch (e) {
throw (0, http_error_1.newBadRequestError)(`Unable to destringify ${what}. Raw string: ${value}.`, e);
}
if (!ret) {
throw (0, http_error_1.newBadRequestError)(`${what} is empty.`);
}
return ret;
}
deserialize(loggingPrefix, value, messageDescriptor, what) {
let ret;
try {
ret = (0, serializer_1.deserializeMessage)(value, messageDescriptor);
}
catch (e) {
throw (0, http_error_1.newBadRequestError)(`Unable to deserialize ${what}. Raw value as base64: ${Buffer.from(value).toString("base64")}.`, e);
}
if (!ret) {
throw (0, http_error_1.newBadRequestError)(`${what} is empty.`);
}
return ret;
}
parse(loggingPrefix, value, messageDescriptor, what) {
let ret;
try {
ret = (0, parser_1.parseMessage)(JSON.parse(value), messageDescriptor);
}
catch (e) {
throw (0, http_error_1.newBadRequestError)(`Unable to parse ${what}. Raw value: ${value}.`, e);
}
if (!ret) {
throw (0, http_error_1.newBadRequestError)(`${what} is empty.`);
}
return ret;
}
}
exports.BaseRemoteCallHandler = BaseRemoteCallHandler;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZV9yZW1vdGVfY2FsbF9oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmFzZV9yZW1vdGVfY2FsbF9oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHdDQUF5QztBQUN6QywwQ0FBMkM7QUFDM0MsbUVBQThEO0FBQzlELG9EQUs2QjtBQUU3QixvREFBdUQ7QUFDdkQsNERBR3FDO0FBQ3JDLDhEQUFrRTtBQUNsRSxvRUFBa0U7QUFHbEUsSUFBSSxhQUFhLEdBQUcsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDO0lBQ3pDLElBQUksRUFBRSxvQkFBb0I7SUFDMUIsSUFBSSxFQUFFLHFDQUFxQztJQUMzQyxVQUFVLEVBQUUsQ0FBQyxNQUFNLENBQUM7Q0FDckIsQ0FBQyxDQUFDO0FBQ0gsSUFBSSxlQUFlLEdBQUcsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDO0lBQzNDLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsSUFBSSxFQUFFLDZCQUE2QjtJQUNuQyxVQUFVLEVBQUUsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDO0NBQ2xDLENBQUMsQ0FBQztBQUVILE1BQWEscUJBQXFCO0lBQ3pCLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBbUI7UUFDdEMsT0FBTyxJQUFJLHFCQUFxQixDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRCxZQUEyQixXQUFtQjtRQUFuQixnQkFBVyxHQUFYLFdBQVcsQ0FBUTtJQUFHLENBQUM7SUFFM0MsS0FBSyxDQUFDLE1BQU0sQ0FDakIsaUJBQTZDLEVBQzdDLEdBQW9CLEVBQ3BCLEdBQXFCO1FBRXJCLGFBQWEsQ0FBQyxHQUFHLENBQUM7WUFDaEIsSUFBSSxFQUNGLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsSUFBSTtnQkFDekMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLElBQUk7U0FDcEMsQ0FBQyxDQUFDO1FBQ0gsa0JBQWtCO1FBQ2xCLEdBQUcsQ0FBQyxTQUFT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O0FBbE1ELHNEQWtNQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHByZXNzID0gcmVxdWlyZShcImV4cHJlc3NcIik7XG5pbXBvcnQgZ2V0U3RyZWFtID0gcmVxdWlyZShcImdldC1zdHJlYW1cIik7XG5pbXBvcnQgcHJvbUNsaWVudCA9IHJlcXVpcmUoXCJwcm9tLWNsaWVudFwiKTtcbmltcG9ydCB7IFN0cmVhbU1lc3NhZ2VSZWFkZXIgfSBmcm9tIFwiLi9zdHJlYW1fbWVzc2FnZV9yZWFkZXJcIjtcbmltcG9ydCB7XG4gIFN0YXR1c0NvZGUsXG4gIG5ld0JhZFJlcXVlc3RFcnJvcixcbiAgbmV3SW50ZXJuYWxTZXJ2ZXJFcnJvckVycm9yLFxuICBuZXdVbmF1dGhvcml6ZWRFcnJvcixcbn0gZnJvbSBcIkBzZWxmYWdlL2h0dHBfZXJyb3JcIjtcbmltcG9ydCB7IE1lc3NhZ2VEZXNjcmlwdG9yIH0gZnJvbSBcIkBzZWxmYWdlL21lc3NhZ2UvZGVzY3JpcHRvclwiO1xuaW1wb3J0IHsgcGFyc2VNZXNzYWdlIH0gZnJvbSBcIkBzZWxmYWdlL21lc3NhZ2UvcGFyc2VyXCI7XG5pbXBvcnQge1xuICBkZXNlcmlhbGl6ZU1lc3NhZ2UsXG4gIHNlcmlhbGl6ZU1lc3NhZ2UsXG59IGZyb20gXCJAc2VsZmFnZS9tZXNzYWdlL3NlcmlhbGl6ZXJcIjtcbmltcG9ydCB7IGRlc3RyaW5naWZ5TWVzc2FnZSB9IGZyb20gXCJAc2VsZmFnZS9tZXNzYWdlL3N0cmluZ2lmaWVyXCI7XG5pbXBvcnQgeyBQcmltaXR2ZVR5cGVGb3JCb2R5IH0gZnJvbSBcIkBzZWxmYWdlL3NlcnZpY2VfZGVzY3JpcHRvclwiO1xuaW1wb3J0IHsgUmVtb3RlQ2FsbEhhbmRsZXJJbnRlcmZhY2UgfSBmcm9tIFwiQHNlbGZhZ2Uvc2VydmljZV9kZXNjcmlwdG9yL3JlbW90ZV9jYWxsX2hhbmRsZXJfaW50ZXJmYWNlXCI7XG5cbmxldCBUT1RBTF9DT1VOVEVSID0gbmV3IHByb21DbGllbnQuQ291bnRlcih7XG4gIG5hbWU6IFwicmVtb3RlX2NhbGxzX3RvdGFsXCIsXG4gIGhlbHA6IFwiVGhlIHRvdGFsIG51bWJlciBvZiBjYWxscyByZWNlaXZlZC5cIixcbiAgbGFiZWxOYW1lczogW1wicGF0aFwiXSxcbn0pO1xubGV0IEZBSUxVUkVfQ09VTlRFUiA9IG5ldyBwcm9tQ2xpZW50LkNvdW50ZXIoe1xuICBuYW1lOiBcInJlbW90ZV9jYWxsc19mYWlsdXJlXCIsXG4gIGhlbHA6IFwiVGhlIG51bWJlciBvZiBmYWlsZWQgY2FsbHMuXCIsXG4gIGxhYmVsTmFtZXM6IFtcInBhdGhcIiwgXCJlcnJvckNvZGVcIl0sXG59KTtcblxuZXhwb3J0IGNsYXNzIEJhc2VSZW1vdGVDYWxsSGFuZGxlciB7XG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlKGFsbG93T3JpZ2luOiBzdHJpbmcpOiBCYXNlUmVtb3RlQ2FsbEhhbmRsZXIge1xuICAgIHJldHVybiBuZXcgQmFzZVJlbW90ZUNhbGxIYW5kbGVyKGFsbG93T3JpZ2luKTtcbiAgfVxuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIGFsbG93T3JpZ2luOiBzdHJpbmcpIHt9XG5cbiAgcHVibGljIGFzeW5jIGhhbmRsZShcbiAgICByZW1vdGVDYWxsSGFuZGxlcjogUmVtb3RlQ2FsbEhhbmRsZXJJbnRlcmZhY2UsXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBUT1RBTF9DT1VOVEVSLmluYyh7XG4gICAgICBwYXRoOlxuICAgICAgICByZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLnNlcnZpY2UucGF0aCArXG4gICAgICAgIHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IucGF0aCxcbiAgICB9KTtcbiAgICAvLyBBZGQgQ09SUyBydWxlcy5cbiAgICByZXMuc2V0SGVhZGVyKFwiQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luXCIsIHRoaXMuYWxsb3dPcmlnaW4pO1xuICAgIHJlcy5zZXRIZWFkZXIoXCJBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzXCIsIFwiKlwiKTtcbiAgICByZXMuc2V0SGVhZGVyKFwiQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVyc1wiLCBcIipcIik7XG5cbiAgICBsZXQgcmVxdWVzdElkID0gYCR7TWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCl9LSR7TWF0aC5mbG9vcihcbiAgICAgIE1hdGgucmFuZG9tKCkgKiAxMDAwMCxcbiAgICApfWA7XG4gICAgbGV0IGxvZ2dpbmdQcmVmaXggPSBgUmVxdWVzdCAke3JlcXVlc3RJZH06YDtcbiAgICBjb25zb2xlLmluZm8oYCR7bG9nZ2luZ1ByZWZpeH0gJHtyZXEudXJsfS5gKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmhhbmRsZVJlcXVlc3QobG9nZ2luZ1ByZWZpeCwgcmVtb3RlQ2FsbEhhbmRsZXIsIHJlcSwgcmVzKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGAke2xvZ2dpbmdQcmVmaXh9ICR7ZS5zdGFjayA/PyBlLm1lc3NhZ2UgPz8gZX1gKTtcbiAgICAgIGxldCBzdGF0dXNDb2RlID0gZS5zdGF0dXNDb2RlID8/IFN0YXR1c0NvZGUuSW50ZXJuYWxTZXJ2ZXJFcnJvcjtcbiAgICAgIEZBSUxVUkVfQ09VTlRFUi5pbmMoe1xuICAgICAgICBwYXRoOlxuICAgICAgICAgIHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3Iuc2VydmljZS5wYXRoICtcbiAgICAgICAgICByZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLnBhdGgsXG4gICAgICAgIGVycm9yQ29kZTogc3RhdHVzQ29kZSxcbiAgICAgIH0pO1xuICAgICAgcmVzLnNlbmRTdGF0dXMoc3RhdHVzQ29kZSk7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4gcmVzLmVuZChyZXNvbHZlKSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVSZXF1ZXN0KFxuICAgIGxvZ2dpbmdQcmVmaXg6IHN0cmluZyxcbiAgICByZW1vdGVDYWxsSGFuZGxlcjogUmVtb3RlQ2FsbEhhbmRsZXJJbnRlcmZhY2UsXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsZXQgYXJnczogYW55W10gPSBbbG9nZ2luZ1ByZWZpeF07XG4gICAgbGV0IGxlZ2FjeUpzb25RdWVyeSA9IGZhbHNlO1xuICAgIGlmIChyZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLmJvZHkubWVzc2FnZVR5cGUpIHtcbiAgICAgIGxldCBib2R5QnVmZmVyID0gYXdhaXQgZ2V0U3RyZWFtLmJ1ZmZlcihyZXEsIHtcbiAgICAgICAgbWF4QnVmZmVyOiAxICogMTAyNCAqIDEwMjQsXG4gICAgICB9KTtcbiAgICAgIGlmIChyZXEuaGVhZGVyc1tcImNvbnRlbnQtdHlwZVwiXSA9PT0gXCJhcHBsaWNhdGlvbi9qc29uXCIpIHtcbiAgICAgICAgbGVnYWN5SnNvblF1ZXJ5ID0gdHJ1ZTtcbiAgICAgICAgbGV0IGJvZHlTdHIgPSBib2R5QnVmZmVyLnRvU3RyaW5nKFwidXRmLThcIik7XG4gICAgICAgIGFyZ3MucHVzaChcbiAgICAgICAgICB0aGlzLnBhcnNlKFxuICAgICAgICAgICAgbG9nZ2luZ1ByZWZpeCxcbiAgICAgICAgICAgIGJvZHlTdHIsXG4gICAgICAgICAgICByZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLmJvZHkubWVzc2FnZVR5cGUsXG4gICAgICAgICAgICBgYm9keWAsXG4gICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGFyZ3MucHVzaChcbiAgICAgICAgICB0aGlzLmRlc2VyaWFsaXplKFxuICAgICAgICAgICAgbG9nZ2luZ1ByZWZpeCxcbiAgICAgICAgICAgIGJvZHlCdWZmZXIsXG4gICAgICAgICAgICByZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLmJvZHkubWVzc2FnZVR5cGUsXG4gICAgICAgICAgICBgYm9keWAsXG4gICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IuYm9keS5zdHJlYW1NZXNzYWdlVHlwZSkge1xuICAgICAgLy8gTk9URTogRG9lc24ndCB3b3JrISBDbGllbnQgc2lkZSByZXF1aXJlcyBodHRwMiB0byBlbmFibGUgY3VzdG9tIHN0cmVhbWluZyB3aXRoIHVuc3BlY2lmaWVkIGNvbnRlbnQgbGVuZ3RoLlxuICAgICAgbGV0IHN0cmVhbVJlYWRlciA9IG5ldyBTdHJlYW1NZXNzYWdlUmVhZGVyKFxuICAgICAgICByZXEsXG4gICAgICAgIHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IuYm9keS5zdHJlYW1NZXNzYWdlVHlwZSxcbiAgICAgICk7XG4gICAgICBhcmdzLnB1c2goc3RyZWFtUmVhZGVyKTtcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgcmVtb3RlQ2FsbEhhbmRsZXIuZGVzY3JpcHRvci5ib2R5LnByaW1pdGl2ZVR5cGUgPT09XG4gICAgICBQcmltaXR2ZVR5cGVGb3JCb2R5LkJZVEVTXG4gICAgKSB7XG4gICAgICBhcmdzLnB1c2gocmVxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3SW50ZXJuYWxTZXJ2ZXJFcnJvckVycm9yKGBVbnN1cHBvcnRlZCBzZXJ2ZXIgcmVxdWVzdCBib2R5LmApO1xuICAgIH1cblxuICAgIGlmIChyZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLm1ldGFkYXRhKSB7XG4gICAgICBhcmdzLnB1c2goXG4gICAgICAgIHRoaXMuZGVzdHJpbmdpZnkoXG4gICAgICAgICAgbG9nZ2luZ1ByZWZpeCxcbiAgICAgICAgICByZXEucXVlcnlbcmVtb3RlQ2FsbEhhbmRsZXIuZGVzY3JpcHRvci5tZXRhZGF0YS5rZXldIGFzIHN0cmluZyxcbiAgICAgICAgICByZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLm1ldGFkYXRhLnR5cGUsXG4gICAgICAgICAgYG1ldGFkYXRhYCxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IuYXV0aEtleSkge1xuICAgICAgbGV0IGF1dGhTdHIgPSByZXEuaGVhZGVyKHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IuYXV0aEtleSk7XG4gICAgICBpZiAoIWF1dGhTdHIpIHtcbiAgICAgICAgdGhyb3cgbmV3VW5hdXRob3JpemVkRXJyb3IoXG4gICAgICAgICAgYE5vIGF1dGggc3RyaW5nIGlzIGZvdW5kIGluIHRoZSBoZWFkZXIgJHtyZW1vdGVDYWxsSGFuZGxlci5kZXNjcmlwdG9yLmF1dGhLZXl9LmAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBhcmdzLnB1c2goYXV0aFN0cik7XG4gICAgfVxuICAgIGxldCByZXNwb25zZSA9IGF3YWl0IHJlbW90ZUNhbGxIYW5kbGVyLmhhbmRsZSguLi5hcmdzKTtcblxuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBpZiAobGVnYWN5SnNvblF1ZXJ5KSB7XG4gICAgICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJhcHBsaWNhdGlvbi9qc29uXCIpO1xuICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHJlc3BvbnNlKSwgcmVzb2x2ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXMuc2V0SGVhZGVyKFwiQ29udGVudC1UeXBlXCIsIFwiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtXCIpO1xuICAgICAgICByZXMuZW5kKFxuICAgICAgICAgIHNlcmlhbGl6ZU1lc3NhZ2UoXG4gICAgICAgICAgICByZXNwb25zZSxcbiAgICAgICAgICAgIHJlbW90ZUNhbGxIYW5kbGVyLmRlc2NyaXB0b3IucmVzcG9uc2UubWVzc2FnZVR5cGUsXG4gICAgICAgICAgKSxcbiAgICAgICAgICByZXNvbHZlLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBkZXN0cmluZ2lmeShcbiAgICBsb2dnaW5nUHJlZml4OiBzdHJpbmcsXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBtZXNzYWdlRGVzY3JpcHRvcjogTWVzc2FnZURlc2NyaXB0b3I8YW55PixcbiAgICB3aGF0OiBzdHJpbmcsXG4gICk6IGFueSB7XG4gICAgbGV0IHJldDogYW55O1xuICAgIHRyeSB7XG4gICAgICByZXQgPSBkZXN0cmluZ2lmeU1lc3NhZ2UodmFsdWUsIG1lc3NhZ2VEZXNjcmlwdG9yKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXdCYWRSZXF1ZXN0RXJyb3IoXG4gICAgICAgIGBVbmFibGUgdG8gZGVzdHJpbmdpZnkgJHt3aGF0fS4gUmF3IHN0cmluZzogJHt2YWx1ZX0uYCxcbiAgICAgICAgZSxcbiAgICAgICk7XG4gICAgfVxuICAgIGlmICghcmV0KSB7XG4gICAgICB0aHJvdyBuZXdCYWRSZXF1ZXN0RXJyb3IoYCR7d2hhdH0gaXMgZW1wdHkuYCk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICBwcml2YXRlIGRlc2VyaWFsaXplKFxuICAgIGxvZ2dpbmdQcmVmaXg6IHN0cmluZyxcbiAgICB2YWx1ZTogVWludDhBcnJheSxcbiAgICBtZXNzYWdlRGVzY3JpcHRvcjogTWVzc2FnZURlc2NyaXB0b3I8YW55PixcbiAgICB3aGF0OiBzdHJpbmcsXG4gICk6IGFueSB7XG4gICAgbGV0IHJldDogYW55O1xuICAgIHRyeSB7XG4gICAgICByZXQgPSBkZXNlcmlhbGl6ZU1lc3NhZ2UodmFsdWUsIG1lc3NhZ2VEZXNjcmlwdG9yKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXdCYWRSZXF1ZXN0RXJyb3IoXG4gICAgICAgIGBVbmFibGUgdG8gZGVzZXJpYWxpemUgJHt3aGF0fS4gUmF3IHZhbHVlIGFzIGJhc2U2NDogJHtCdWZmZXIuZnJvbSh2YWx1ZSkudG9TdHJpbmcoXCJiYXNlNjRcIil9LmAsXG4gICAgICAgIGUsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIXJldCkge1xuICAgICAgdGhyb3cgbmV3QmFkUmVxdWVzdEVycm9yKGAke3doYXR9IGlzIGVtcHR5LmApO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgcHJpdmF0ZSBwYXJzZShcbiAgICBsb2dnaW5nUHJlZml4OiBzdHJpbmcsXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBtZXNzYWdlRGVzY3JpcHRvcjogTWVzc2FnZURlc2NyaXB0b3I8YW55PixcbiAgICB3aGF0OiBzdHJpbmcsXG4gICk6IGFueSB7XG4gICAgbGV0IHJldDogYW55O1xuICAgIHRyeSB7XG4gICAgICByZXQgPSBwYXJzZU1lc3NhZ2UoSlNPTi5wYXJzZSh2YWx1ZSksIG1lc3NhZ2VEZXNjcmlwdG9yKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBuZXdCYWRSZXF1ZXN0RXJyb3IoXG4gICAgICAgIGBVbmFibGUgdG8gcGFyc2UgJHt3aGF0fS4gUmF3IHZhbHVlOiAke3ZhbHVlfS5gLFxuICAgICAgICBlLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFyZXQpIHtcbiAgICAgIHRocm93IG5ld0JhZFJlcXVlc3RFcnJvcihgJHt3aGF0fSBpcyBlbXB0eS5gKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxufVxuIl19