UNPKG

@selfage/service_handler

Version:

Http-based service handlers on top of expressjs.

147 lines 23 kB
"use strict"; 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