UNPKG

@selfage/node_service_client

Version:

Http client to make remote call to services from Nodejs applications.

105 lines 16.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeServiceClient = void 0; const EventEmitter = require("events"); const getStream = require("get-stream"); const http = require("http"); const http_error_1 = require("@selfage/http_error"); const serializer_1 = require("@selfage/message/serializer"); const stringifier_1 = require("@selfage/message/stringifier"); const service_descriptor_1 = require("@selfage/service_descriptor"); class NodeServiceClient extends EventEmitter { static create(origin) { return new NodeServiceClient(origin, (callback, ms) => setTimeout(callback, ms)); } constructor(origin, setTimeout) { super(); this.origin = origin; this.setTimeout = setTimeout; } async send(request, options) { try { return await this.sendOrThrowErrors(request, options); } catch (e) { if (e.statusCode) { await Promise.all(this.listeners("httpError").map((callback) => callback(e))); } await Promise.all(this.listeners("error").map((callback) => callback(e))); throw e; } } async sendOrThrowErrors(request, options = {}) { let headers = {}; let searchParams = new URLSearchParams(); if (request.metadata) { searchParams.set(request.descriptor.metadata.key, (0, stringifier_1.stringifyMessage)(request.metadata, request.descriptor.metadata.type)); } let writeBody; if (request.descriptor.body.messageType) { headers["content-type"] = "application/octet-stream"; writeBody = (req) => { req.end((0, serializer_1.serializeMessage)(request.body, request.descriptor.body.messageType)); }; } else if (request.descriptor.body.primitiveType === service_descriptor_1.PrimitveTypeForBody.BYTES) { headers["content-type"] = "application/octet-stream"; writeBody = (req) => { request.body.pipe(req); }; } else { throw (0, http_error_1.newBadRequestError)("Unsupported client request body."); } let httpResponse = await this.requestWithTimeoutAndRetries(`${this.origin}${request.descriptor.service.path}${request.descriptor.path}`, searchParams, writeBody, headers, options.retries, options.timeout); if (httpResponse.statusCode !== 200) { let errorMessage = await getStream(httpResponse, { encoding: "utf-8", }); throw new http_error_1.HttpError(httpResponse.statusCode, errorMessage); } try { return (0, serializer_1.deserializeMessage)(await getStream.buffer(httpResponse), request.descriptor.response.messageType); } catch (e) { throw new Error(`Unable to parse server response.`); } } async requestWithTimeoutAndRetries(url, searchParams, writeBody, headers, retries = 1, timeout) { let lastError; for (let i = 0; i < retries; i++) { try { let signal; if (timeout) { let abortController = new AbortController(); signal = abortController.signal; this.setTimeout(() => abortController.abort(), timeout); } let res = await new Promise((resolve, reject) => { let req = http.request(`${url}?${searchParams}`, { method: "POST", headers, timeout, signal, }, (res) => resolve(res)); req.on("error", (e) => { reject(e); }); writeBody(req); }); return res; } catch (e) { if (e.code === "ABORT_ERR") { throw new Error("Http request timed out."); } else { lastError = e; } } } throw new Error(`Http request failed after ${retries} attempts. ${lastError}`); } } exports.NodeServiceClient = NodeServiceClient; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHVDQUF3QztBQUN4Qyx3Q0FBeUM7QUFDekMsNkJBQThCO0FBQzlCLG9EQUFvRTtBQUNwRSw0REFHcUM7QUFDckMsOERBQWdFO0FBQ2hFLG9FQUFrRTtBQW9CbEUsTUFBYSxpQkFBa0IsU0FBUSxZQUFZO0lBQzFDLE1BQU0sQ0FBQyxNQUFNLENBQ2xCLE1BQWM7UUFFZCxPQUFPLElBQUksaUJBQWlCLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQ3BELFVBQVUsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQ3pCLENBQUM7SUFDSixDQUFDO0lBRUQsWUFDVSxNQUFjLEVBQ2QsVUFBc0Q7UUFFOUQsS0FBSyxFQUFFLENBQUM7UUFIQSxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2QsZUFBVSxHQUFWLFVBQVUsQ0FBNEM7SUFHaEUsQ0FBQztJQUVNLEtBQUssQ0FBQyxJQUFJLENBQ2YsT0FBeUMsRUFDekMsT0FBMkI7UUFFM0IsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDeEQsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxJQUFJLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDakIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNmLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDM0QsQ0FBQztZQUNKLENBQUM7WUFDRCxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDMUUsTUFBTSxDQUFDLENBQUM7UUFDVixDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FDN0IsT0FBb0MsRUFDcEMsVUFBNkIsRUFBRTtRQUUvQixJQUFJLE9BQU8sR0FBNkIsRUFBRSxDQUFDO1FBQzNDLElBQUksWUFBWSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7UUFDekMsSUFBSSxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDckIsWUFBWSxDQUFDLEdBQUcsQ0FDZCxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQy9CLElBQUEsOEJBQWdCLEVBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FDckUsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLFNBQTRCLENBQUM7UUFDakMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN4QyxPQUFPLENBQUMsY0FBYyxDQUFDLEdBQUcsMEJBQTBCLENBQUM7WUFDckQsU0FBUyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQ2xCLEdBQUcsQ0FBQyxHQUFHLENBQ0wsSUFBQSw2QkFBZ0IsRUFBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUNwRSxDQUFDO1lBQ0osQ0FBQyxDQUFDO1FBQ0osQ0FBQzthQUFNLElBQ0wsT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsYUFBYSxLQUFLLHdDQUFtQixDQUFDLEtBQUssRUFDbkUsQ0FBQztZQUNELE9BQU8sQ0FBQyxjQUFjLENBQUMsR0FBRywwQkFBMEIsQ0FBQztZQUNyRCxTQUFTLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDbEIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDekIsQ0FBQyxDQUFDO1FBQ0osQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLElBQUEsK0JBQWtCLEVBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQsSUFBSSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQ3hELEdBQUcsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsRUFDNUUsWUFBWSxFQUNaLFNBQVMsRUFDVCxPQUFPLEVBQ1AsT0FBTyxDQUFDLE9BQU8sRUFDZixPQUFPLENBQUMsT0FBTyxDQUNoQixDQUFDO1FBQ0YsSUFBSSxZQUFZLENBQUMsVUFBVSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ3BDLElBQUksWUFBWSxHQUFHLE1BQU0sU0FBUyxDQUFDLFlBQVksRUFBRTtnQkFDL0MsUUFBUSxFQUFFLE9BQU87YUFDbEIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxJQUFJLHNCQUFTLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUM3RCxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsT0FBTyxJQUFBLCtCQUFrQixFQUN2QixNQUFNLFNBQVMsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLEVBQ3BDLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FDeEMsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ3RELENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLDRCQUE0QixDQUN4QyxHQUFXLEVBQ1gsWUFBNkIsRUFDN0IsU0FBNEIsRUFDNUIsT0FBaUMsRUFDakMsT0FBTyxHQUFHLENBQUMsRUFDWCxPQUFnQjtRQUVoQixJQUFJLFNBQWMsQ0FBQztRQUNuQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDakMsSUFBSSxDQUFDO2dCQUNILElBQUksTUFBbUIsQ0FBQztnQkFDeEIsSUFBSSxPQUFPLEVBQUUsQ0FBQztvQkFDWixJQUFJLGVBQWUsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO29CQUM1QyxNQUFNLEdBQUcsZUFBZSxDQUFDLE1BQU0sQ0FBQztvQkFDaEMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQzFELENBQUM7Z0JBQ0QsSUFBSSxHQUFHLEdBQUcsTUFBTSxJQUFJLE9BQU8sQ0FBdUIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7b0JBQ3BFLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQ3BCLEdBQUcsR0FBRyxJQUFJLFlBQVksRUFBRSxFQUN4Qjt3QkFDRSxNQUFNLEVBQUUsTUFBTTt3QkFDZCxPQUFPO3dCQUNQLE9BQU87d0JBQ1AsTUFBTTtxQkFDUCxFQUNELENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQ3RCLENBQUM7b0JBQ0YsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRTt3QkFDcEIsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUNaLENBQUMsQ0FBQyxDQUFDO29CQUNILFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDakIsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxHQUFHLENBQUM7WUFDYixDQUFDO1lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDWCxJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssV0FBVyxFQUFFLENBQUM7b0JBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztnQkFDN0MsQ0FBQztxQkFBTSxDQUFDO29CQUNOLFNBQVMsR0FBRyxDQUFDLENBQUM7Z0JBQ2hCLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUNELE1BQU0sSUFBSSxLQUFLLENBQ2IsNkJBQTZCLE9BQU8sY0FBYyxTQUFTLEVBQUUsQ0FDOUQsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQXhJRCw4Q0F3SUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKTtcbmltcG9ydCBnZXRTdHJlYW0gPSByZXF1aXJlKFwiZ2V0LXN0cmVhbVwiKTtcbmltcG9ydCBodHRwID0gcmVxdWlyZShcImh0dHBcIik7XG5pbXBvcnQgeyBIdHRwRXJyb3IsIG5ld0JhZFJlcXVlc3RFcnJvciB9IGZyb20gXCJAc2VsZmFnZS9odHRwX2Vycm9yXCI7XG5pbXBvcnQge1xuICBkZXNlcmlhbGl6ZU1lc3NhZ2UsXG4gIHNlcmlhbGl6ZU1lc3NhZ2UsXG59IGZyb20gXCJAc2VsZmFnZS9tZXNzYWdlL3NlcmlhbGl6ZXJcIjtcbmltcG9ydCB7IHN0cmluZ2lmeU1lc3NhZ2UgfSBmcm9tIFwiQHNlbGZhZ2UvbWVzc2FnZS9zdHJpbmdpZmllclwiO1xuaW1wb3J0IHsgUHJpbWl0dmVUeXBlRm9yQm9keSB9IGZyb20gXCJAc2VsZmFnZS9zZXJ2aWNlX2Rlc2NyaXB0b3JcIjtcbmltcG9ydCB7IENsaWVudFJlcXVlc3RJbnRlcmZhY2UgfSBmcm9tIFwiQHNlbGZhZ2Uvc2VydmljZV9kZXNjcmlwdG9yL2NsaWVudF9yZXF1ZXN0X2ludGVyZmFjZVwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5vZGVDbGllbnRPcHRpb25zIHtcbiAgcmV0cmllcz86IG51bWJlcjtcbiAgdGltZW91dD86IG51bWJlcjtcbn1cblxudHlwZSBXcml0ZUJvZHlGdW5jdGlvbiA9IChyZXE6IGh0dHAuQ2xpZW50UmVxdWVzdCkgPT4gdm9pZDtcblxuZXhwb3J0IGludGVyZmFjZSBOb2RlU2VydmljZUNsaWVudCB7XG4gIC8vIFdoZW4gc2VydmVyIGZpbmlzaGVkIHJlc3BvbnNlIHdpdGggYW4gZXJyb3IgY29kZSwgaS5lLiBlaXRoZXIgNHh4IG9yIDV4eC5cbiAgb24oXG4gICAgZXZlbnQ6IFwiaHR0cEVycm9yXCIsXG4gICAgbGlzdGVuZXI6IChlcnJvcjogSHR0cEVycm9yKSA9PiBQcm9taXNlPHZvaWQ+IHwgdm9pZCxcbiAgKTogdGhpcztcbiAgLy8gR2VuZXJhbCBlcnJvcnMgaW5jbHVkaW5nIGh0dHAgZXJyb3JzIGFuZCBuZXR3b3JrIGVycm9ycy5cbiAgb24oZXZlbnQ6IFwiZXJyb3JcIiwgbGlzdGVuZXI6IChlcnJvcjogYW55KSA9PiBQcm9taXNlPHZvaWQ+IHwgdm9pZCk6IHRoaXM7XG59XG5cbmV4cG9ydCBjbGFzcyBOb2RlU2VydmljZUNsaWVudCBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlKFxuICAgIG9yaWdpbjogc3RyaW5nXG4gICk6IE5vZGVTZXJ2aWNlQ2xpZW50IHtcbiAgICByZXR1cm4gbmV3IE5vZGVTZXJ2aWNlQ2xpZW50KG9yaWdpbiwgKGNhbGxiYWNrLCBtcykgPT5cbiAgICAgIHNldFRpbWVvdXQoY2FsbGJhY2ssIG1zKSxcbiAgICApO1xuICB9XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgb3JpZ2luOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSBzZXRUaW1lb3V0OiAoY2FsbGJhY2s6IEZ1bmN0aW9uLCBtczogbnVtYmVyKSA9PiBudW1iZXIsXG4gICkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgc2VuZDxSZXNwb25zZT4oXG4gICAgcmVxdWVzdDogQ2xpZW50UmVxdWVzdEludGVyZmFjZTxSZXNwb25zZT4sXG4gICAgb3B0aW9ucz86IE5vZGVDbGllbnRPcHRpb25zLFxuICApOiBQcm9taXNlPFJlc3BvbnNlPiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNlbmRPclRocm93RXJyb3JzKHJlcXVlc3QsIG9wdGlvbnMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChlLnN0YXR1c0NvZGUpIHtcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgdGhpcy5saXN0ZW5lcnMoXCJodHRwRXJyb3JcIikubWFwKChjYWxsYmFjaykgPT4gY2FsbGJhY2soZSkpLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5saXN0ZW5lcnMoXCJlcnJvclwiKS5tYXAoKGNhbGxiYWNrKSA9PiBjYWxsYmFjayhlKSkpO1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbmRPclRocm93RXJyb3JzKFxuICAgIHJlcXVlc3Q6IENsaWVudFJlcXVlc3RJbnRlcmZhY2U8YW55PixcbiAgICBvcHRpb25zOiBOb2RlQ2xpZW50T3B0aW9ucyA9IHt9LFxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGxldCBoZWFkZXJzOiBodHRwLk91dGdvaW5nSHR0cEhlYWRlcnMgPSB7fTtcbiAgICBsZXQgc2VhcmNoUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcygpO1xuICAgIGlmIChyZXF1ZXN0Lm1ldGFkYXRhKSB7XG4gICAgICBzZWFyY2hQYXJhbXMuc2V0KFxuICAgICAgICByZXF1ZXN0LmRlc2NyaXB0b3IubWV0YWRhdGEua2V5LFxuICAgICAgICBzdHJpbmdpZnlNZXNzYWdlKHJlcXVlc3QubWV0YWRhdGEsIHJlcXVlc3QuZGVzY3JpcHRvci5tZXRhZGF0YS50eXBlKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHdyaXRlQm9keTogV3JpdGVCb2R5RnVuY3Rpb247XG4gICAgaWYgKHJlcXVlc3QuZGVzY3JpcHRvci5ib2R5Lm1lc3NhZ2VUeXBlKSB7XG4gICAgICBoZWFkZXJzW1wiY29udGVudC10eXBlXCJdID0gXCJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1cIjtcbiAgICAgIHdyaXRlQm9keSA9IChyZXEpID0+IHtcbiAgICAgICAgcmVxLmVuZChcbiAgICAgICAgICBzZXJpYWxpemVNZXNzYWdlKHJlcXVlc3QuYm9keSwgcmVxdWVzdC5kZXNjcmlwdG9yLmJvZHkubWVzc2FnZVR5cGUpLFxuICAgICAgICApO1xuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgcmVxdWVzdC5kZXNjcmlwdG9yLmJvZHkucHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0dmVUeXBlRm9yQm9keS5CWVRFU1xuICAgICkge1xuICAgICAgaGVhZGVyc1tcImNvbnRlbnQtdHlwZVwiXSA9IFwiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtXCI7XG4gICAgICB3cml0ZUJvZHkgPSAocmVxKSA9PiB7XG4gICAgICAgIHJlcXVlc3QuYm9keS5waXBlKHJlcSk7XG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXdCYWRSZXF1ZXN0RXJyb3IoXCJVbnN1cHBvcnRlZCBjbGllbnQgcmVxdWVzdCBib2R5LlwiKTtcbiAgICB9XG5cbiAgICBsZXQgaHR0cFJlc3BvbnNlID0gYXdhaXQgdGhpcy5yZXF1ZXN0V2l0aFRpbWVvdXRBbmRSZXRyaWVzKFxuICAgICAgYCR7dGhpcy5vcmlnaW59JHtyZXF1ZXN0LmRlc2NyaXB0b3Iuc2VydmljZS5wYXRofSR7cmVxdWVzdC5kZXNjcmlwdG9yLnBhdGh9YCxcbiAgICAgIHNlYXJjaFBhcmFtcyxcbiAgICAgIHdyaXRlQm9keSxcbiAgICAgIGhlYWRlcnMsXG4gICAgICBvcHRpb25zLnJldHJpZXMsXG4gICAgICBvcHRpb25zLnRpbWVvdXQsXG4gICAgKTtcbiAgICBpZiAoaHR0cFJlc3BvbnNlLnN0YXR1c0NvZGUgIT09IDIwMCkge1xuICAgICAgbGV0IGVycm9yTWVzc2FnZSA9IGF3YWl0IGdldFN0cmVhbShodHRwUmVzcG9uc2UsIHtcbiAgICAgICAgZW5jb2Rpbmc6IFwidXRmLThcIixcbiAgICAgIH0pO1xuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihodHRwUmVzcG9uc2Uuc3RhdHVzQ29kZSwgZXJyb3JNZXNzYWdlKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGRlc2VyaWFsaXplTWVzc2FnZShcbiAgICAgICAgYXdhaXQgZ2V0U3RyZWFtLmJ1ZmZlcihodHRwUmVzcG9uc2UpLFxuICAgICAgICByZXF1ZXN0LmRlc2NyaXB0b3IucmVzcG9uc2UubWVzc2FnZVR5cGUsXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIHBhcnNlIHNlcnZlciByZXNwb25zZS5gKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlcXVlc3RXaXRoVGltZW91dEFuZFJldHJpZXMoXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgc2VhcmNoUGFyYW1zOiBVUkxTZWFyY2hQYXJhbXMsXG4gICAgd3JpdGVCb2R5OiBXcml0ZUJvZHlGdW5jdGlvbixcbiAgICBoZWFkZXJzOiBodHRwLk91dGdvaW5nSHR0cEhlYWRlcnMsXG4gICAgcmV0cmllcyA9IDEsXG4gICAgdGltZW91dD86IG51bWJlcixcbiAgKTogUHJvbWlzZTxodHRwLkluY29taW5nTWVzc2FnZT4ge1xuICAgIGxldCBsYXN0RXJyb3I6IGFueTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJldHJpZXM7IGkrKykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbGV0IHNpZ25hbDogQWJvcnRTaWduYWw7XG4gICAgICAgIGlmICh0aW1lb3V0KSB7XG4gICAgICAgICAgbGV0IGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICAgICAgICBzaWduYWwgPSBhYm9ydENvbnRyb2xsZXIuc2lnbmFsO1xuICAgICAgICAgIHRoaXMuc2V0VGltZW91dCgoKSA9PiBhYm9ydENvbnRyb2xsZXIuYWJvcnQoKSwgdGltZW91dCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlcyA9IGF3YWl0IG5ldyBQcm9taXNlPGh0dHAuSW5jb21pbmdNZXNzYWdlPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgbGV0IHJlcSA9IGh0dHAucmVxdWVzdChcbiAgICAgICAgICAgIGAke3VybH0/JHtzZWFyY2hQYXJhbXN9YCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgICAgICAgaGVhZGVycyxcbiAgICAgICAgICAgICAgdGltZW91dCxcbiAgICAgICAgICAgICAgc2lnbmFsLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIChyZXMpID0+IHJlc29sdmUocmVzKSxcbiAgICAgICAgICApO1xuICAgICAgICAgIHJlcS5vbihcImVycm9yXCIsIChlKSA9PiB7XG4gICAgICAgICAgICByZWplY3QoZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgd3JpdGVCb2R5KHJlcSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoZS5jb2RlID09PSBcIkFCT1JUX0VSUlwiKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSHR0cCByZXF1ZXN0IHRpbWVkIG91dC5cIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbGFzdEVycm9yID0gZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgSHR0cCByZXF1ZXN0IGZhaWxlZCBhZnRlciAke3JldHJpZXN9IGF0dGVtcHRzLiAke2xhc3RFcnJvcn1gLFxuICAgICk7XG4gIH1cbn1cbiJdfQ==