serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
228 lines • 35.2 kB
JavaScript
import { getConnection } from './iot-connection';
import { getTopic } from './topic';
export class WsListener {
constructor() {
this.messages = [];
this.trackers = [];
this.closed = true;
this.functionPrefix = 'waitFor';
this.debugMode = false;
this.fragments = new Map();
}
async start(params) {
this.debugMode = !!params.debugMode;
try {
this.connection = await getConnection(this.debugMode, params.serverlessSpyWsUrl);
this.closed = false;
const topic = getTopic(params.scope || '#');
this.log(`Subscribing to topic ${topic}`);
const connectionOpenResolve = this.connectionOpenResolve || params.connectionOpenResolve;
const localConnection = this.connection;
this.connection.on('connect', () => {
this.closed = false;
this.log('Connection opened');
localConnection.subscribe(topic);
if (connectionOpenResolve) {
connectionOpenResolve();
}
});
this.connection.on('message', (_topic, data) => {
if (this.closed)
return;
this.log('Message received', data.toString());
const fragment = JSON.parse(data.toString());
let message = undefined;
if (!fragment.id) {
message = JSON.parse(fragment.data);
}
let pending = this.fragments.get(fragment.id);
if (!pending) {
pending = new Map();
this.fragments.set(fragment.id, pending);
}
pending.set(fragment.index, fragment);
if (pending.size === fragment.count) {
const data = [...pending.values()]
.sort((a, b) => a.index - b.index)
.map((item) => item.data)
.join('');
this.fragments.delete(fragment.id);
message = JSON.parse(data);
}
if (message) {
message.serviceKeyForFunction = message.serviceKey.replace(/#/g, '');
if (message.serviceKey.startsWith('Function')) {
message.functionContextAwsRequestId = message.data.context.awsRequestId;
}
this.messages.push(message);
this.resolveOldTrackerWithNewMessage(message);
}
});
this.connection.on('close', () => {
this.log('Connection closed');
this.closed = true;
});
const connectionOpenReject = this.connectionOpenReject || params.connectionOpenReject;
this.connection.on('error', (error) => {
this.log('Connection error:', error);
connectionOpenReject?.(error);
});
}
catch (e) {
console.error('Failed to get connection', e);
throw e;
}
}
async stop() {
this.closed = true;
this.connection.end(true);
}
trackerMatchMessage(tracker, message) {
if (tracker.finished)
return;
if ((tracker.serviceKey && tracker.serviceKey === message.serviceKey) ||
(tracker.serviceKeyForFunction &&
tracker.serviceKeyForFunction === message.serviceKeyForFunction)) {
if (this.trackerMatchCondition(tracker, message)) {
tracker.finished = true;
const spyAndJestMatchers = {
getData: () => message.data,
};
const serviceKeyForFunction = tracker.serviceKeyForFunction;
if (serviceKeyForFunction &&
serviceKeyForFunction.startsWith('Function') &&
(serviceKeyForFunction.endsWith('Request') ||
serviceKeyForFunction.endsWith('Console'))) {
let serviceKeyForFunctionChain = serviceKeyForFunction;
if (serviceKeyForFunctionChain.endsWith('Request')) {
serviceKeyForFunctionChain = serviceKeyForFunctionChain.substring(0, serviceKeyForFunctionChain.length - 'Request'.length);
}
else if (serviceKeyForFunctionChain.endsWith('Console')) {
serviceKeyForFunctionChain = serviceKeyForFunctionChain.substring(0, serviceKeyForFunctionChain.length - 'Console'.length);
}
spyAndJestMatchers.followedByConsole = (paramsW) => {
return this.createWaitForXXXFunc(`${serviceKeyForFunctionChain}Console`, message.data.context.awsRequestId)(paramsW);
};
spyAndJestMatchers.followedByResponse = (paramsW) => {
return this.createWaitForXXXFunc(`${serviceKeyForFunctionChain}Response`, message.data.context.awsRequestId)(paramsW);
};
}
const proxy = new Proxy(spyAndJestMatchers, {
get: function (target, objectKey) {
if (target.hasOwnProperty(objectKey)) {
return target[objectKey];
}
else if (objectKey !== 'then') {
return function () {
const jestFunctionToExecute = expect(message.data)[objectKey];
jestFunctionToExecute.apply(undefined, arguments);
return proxy;
};
}
},
});
tracker.promiseResolve(proxy);
return true;
}
}
return false;
}
resolveTrackerInOldMessages(tracker) {
for (const message of this.messages) {
if (this.trackerMatchMessage(tracker, message)) {
return true;
}
}
return false;
}
resolveOldTrackerWithNewMessage(message) {
for (let index = 0; index < this.trackers.length; index++) {
const tracker = this.trackers[index];
if (this.trackerMatchMessage(tracker, message)) {
this.trackers = this.trackers.splice(index, 1);
return true;
}
}
return false;
}
trackerMatchCondition(tracker, message) {
const matchCondition = (tracker.condition && tracker.condition(message.data)) ||
!tracker.condition;
const matchRequestId = (tracker.functionContextAwsRequestId &&
tracker.functionContextAwsRequestId ===
message.functionContextAwsRequestId) ||
!tracker.functionContextAwsRequestId;
if (matchCondition && matchRequestId) {
return true;
}
else {
if (!matchCondition &&
matchRequestId &&
!tracker.possibleSpyMessageDataForDebugging) {
tracker.possibleSpyMessageDataForDebugging = message.data;
}
return false;
}
}
createWaitForXXXFunc(serviceKeyForFunction, functionContextAwsRequestId) {
return (paramsW) => {
let resolve;
const promise = new Promise((res) => {
resolve = res;
});
const tracker = {
finished: false,
// @ts-ignore
promiseResolve: resolve,
serviceKeyForFunction,
functionContextAwsRequestId,
};
tracker.condition = paramsW?.condition;
let timeoutPid;
const timer = new Promise((_, reject) => {
timeoutPid = setTimeout(() => {
if (tracker.finished)
return;
tracker.finished = true;
let message = `Timeout waiting for Serverless Spy message ${serviceKeyForFunction}.`;
if (tracker.possibleSpyMessageDataForDebugging) {
message += ` Similar matching spy event data: ${JSON.stringify(tracker.possibleSpyMessageDataForDebugging, null, 2)}`;
}
reject(new Error(message));
}, paramsW?.timoutMs || 10000);
});
if (!this.resolveTrackerInOldMessages(tracker)) {
this.trackers.push(tracker);
}
return Promise.race([promise, timer]).finally(() => {
if (!!timeoutPid) {
clearTimeout(timeoutPid);
}
});
};
}
createProxy() {
const spyListener = {};
spyListener.stop = async () => {
await this.stop();
};
return new Proxy(spyListener, {
get: (target, objectKey) => {
if (target.hasOwnProperty(objectKey)) {
return target[objectKey].bind(target);
}
else if (typeof objectKey === 'string' &&
objectKey.startsWith(this.functionPrefix)) {
const serviceKeyForFunction = objectKey.substring(this.functionPrefix.length);
return this.createWaitForXXXFunc(serviceKeyForFunction);
}
},
});
}
log(message, ...optionalParams) {
if (this.debugMode && !this.closed) {
console.debug('SSPY', message, new Date().toISOString(), ...optionalParams);
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV3NMaXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2xpc3RlbmVyL1dzTGlzdGVuZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFZLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRzNELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFLbkMsTUFBTSxPQUFPLFVBQVU7SUFBdkI7UUFDVSxhQUFRLEdBQXdCLEVBQUUsQ0FBQztRQUNuQyxhQUFRLEdBQWMsRUFBRSxDQUFDO1FBSXpCLFdBQU0sR0FBRyxJQUFJLENBQUM7UUFDZCxtQkFBYyxHQUFHLFNBQVMsQ0FBQztRQUMzQixjQUFTLEdBQUcsS0FBSyxDQUFDO1FBR2xCLGNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBaUMsQ0FBQztJQW1TL0QsQ0FBQztJQWpTUSxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQW1DO1FBQ3BELElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFDcEMsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FDbkMsSUFBSSxDQUFDLFNBQVMsRUFDZCxNQUFNLENBQUMsa0JBQWtCLENBQzFCLENBQUM7WUFDRixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztZQUNwQixNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUMsQ0FBQztZQUM1QyxJQUFJLENBQUMsR0FBRyxDQUFDLHdCQUF3QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzFDLE1BQU0scUJBQXFCLEdBQ3pCLElBQUksQ0FBQyxxQkFBcUIsSUFBSSxNQUFNLENBQUMscUJBQXFCLENBQUM7WUFDN0QsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztZQUN4QyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxT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LENBQUM7WUFDSCxDQUFDO1NBQ0YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLEdBQUcsQ0FBQyxPQUFlLEVBQUUsR0FBRyxjQUFxQjtRQUNuRCxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkMsT0FBTyxDQUFDLEtBQUssQ0FDWCxNQUFNLEVBQ04sT0FBTyxFQUNQLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQ3hCLEdBQUcsY0FBYyxDQUNsQixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRldmljZSB9IGZyb20gJ2F3cy1pb3QtZGV2aWNlLXNkayc7XG5pbXBvcnQgeyBmcmFnbWVudCwgZ2V0Q29ubmVjdGlvbiB9IGZyb20gJy4vaW90LWNvbm5lY3Rpb24nO1xuaW1wb3J0IHsgU2VydmVybGVzc1NweUxpc3RlbmVyIH0gZnJvbSAnLi9TZXJ2ZXJsZXNzU3B5TGlzdGVuZXInO1xuaW1wb3J0IHsgU2VydmVybGVzc1NweUxpc3RlbmVyUGFyYW1zIH0gZnJvbSAnLi9TZXJ2ZXJsZXNzU3B5TGlzdGVuZXJQYXJhbXMnO1xuaW1wb3J0IHsgZ2V0VG9waWMgfSBmcm9tICcuL3RvcGljJztcbmltcG9ydCB7IFdhaXRGb3JQYXJhbXMgfSBmcm9tICcuL1dhaXRGb3JQYXJhbXMnO1xuaW1wb3J0IHsgRnVuY3Rpb25SZXF1ZXN0U3B5RXZlbnQgfSBmcm9tICcuLi9jb21tb24vc3B5RXZlbnRzL0Z1bmN0aW9uUmVxdWVzdFNweUV2ZW50JztcbmltcG9ydCB7IFNweU1lc3NhZ2UgfSBmcm9tICcuLi9jb21tb24vc3B5RXZlbnRzL1NweU1lc3NhZ2UnO1xuXG5leHBvcnQgY2xhc3MgV3NMaXN0ZW5lcjxUU3B5RXZlbnRzPiB7XG4gIHByaXZhdGUgbWVzc2FnZXM6IFNweU1lc3NhZ2VTdG9yYWdlW10gPSBbXTtcbiAgcHJpdmF0ZSB0cmFja2VyczogVHJhY2tlcltdID0gW107XG5cbiAgcHJpdmF0ZSBjb25uZWN0aW9uT3BlblJlc29sdmU/OiAoKSA9PiB2b2lkO1xuICBwcml2YXRlIGNvbm5lY3Rpb25PcGVuUmVqZWN0PzogKHJlYXNvbj86IGFueSkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBjbG9zZWQgPSB0cnVlO1xuICBwcml2YXRlIGZ1bmN0aW9uUHJlZml4ID0gJ3dhaXRGb3InO1xuICBwcml2YXRlIGRlYnVnTW9kZSA9IGZhbHNlO1xuICBwcml2YXRlIGNvbm5lY3Rpb246IGRldmljZSB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIGZyYWdtZW50cyA9IG5ldyBNYXA8c3RyaW5nLCBNYXA8bnVtYmVyLCBmcmFnbWVudD4+KCk7XG5cbiAgcHVibGljIGFzeW5jIHN0YXJ0KHBhcmFtczogU2VydmVybGVzc1NweUxpc3RlbmVyUGFyYW1zKSB7XG4gICAgdGhpcy5kZWJ1Z01vZGUgPSAhIXBhcmFtcy5kZWJ1Z01vZGU7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuY29ubmVjdGlvbiA9IGF3YWl0IGdldENvbm5lY3Rpb24oXG4gICAgICAgIHRoaXMuZGVidWdNb2RlLFxuICAgICAgICBwYXJhbXMuc2VydmVybGVzc1NweVdzVXJsXG4gICAgICApO1xuICAgICAgdGhpcy5jbG9zZWQgPSBmYWxzZTtcbiAgICAgIGNvbnN0IHRvcGljID0gZ2V0VG9waWMocGFyYW1zLnNjb3BlIHx8ICcjJyk7XG4gICAgICB0aGlzLmxvZyhgU3Vic2NyaWJpbmcgdG8gdG9waWMgJHt0b3BpY31gKTtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb25PcGVuUmVzb2x2ZSA9XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbk9wZW5SZXNvbHZlIHx8IHBhcmFtcy5jb25uZWN0aW9uT3BlblJlc29sdmU7XG4gICAgICBjb25zdCBsb2NhbENvbm5lY3Rpb24gPSB0aGlzLmNvbm5lY3Rpb247XG4gICAgICB0aGlzLmNvbm5lY3Rpb24ub24oJ2Nvbm5lY3QnLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuY2xvc2VkID0gZmFsc2U7XG4gICAgICAgIHRoaXMubG9nKCdDb25uZWN0aW9uIG9wZW5lZCcpO1xuICAgICAgICBsb2NhbENvbm5lY3Rpb24uc3Vic2NyaWJlKHRvcGljKTtcbiAgICAgICAgaWYgKGNvbm5lY3Rpb25PcGVuUmVzb2x2ZSkge1xuICAgICAgICAgIGNvbm5lY3Rpb25PcGVuUmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuY29ubmVjdGlvbi5vbignbWVzc2FnZScsIChfdG9waWM6IHN0cmluZywgZGF0YTogQnVmZmVyKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmNsb3NlZCkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMubG9nKCdNZXNzYWdlIHJlY2VpdmVkJywgZGF0YS50b1N0cmluZygpKTtcbiAgICAgICAgY29uc3QgZnJhZ21lbnQgPSBKU09OLnBhcnNlKGRhdGEudG9TdHJpbmcoKSk7XG4gICAgICAgIGxldCBtZXNzYWdlOiBTcHlNZXNzYWdlU3RvcmFnZSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKCFmcmFnbWVudC5pZCkge1xuICAgICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKGZyYWdtZW50LmRhdGEpIGFzIFNweU1lc3NhZ2VTdG9yYWdlO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHBlbmRpbmcgPSB0aGlzLmZyYWdtZW50cy5nZXQoZnJhZ21lbnQuaWQpO1xuICAgICAgICBpZiAoIXBlbmRpbmcpIHtcbiAgICAgICAgICBwZW5kaW5nID0gbmV3IE1hcCgpO1xuICAgICAgICAgIHRoaXMuZnJhZ21lbnRzLnNldChmcmFnbWVudC5pZCwgcGVuZGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgcGVuZGluZy5zZXQoZnJhZ21lbnQuaW5kZXgsIGZyYWdtZW50KTtcblxuICAgICAgICBpZiAocGVuZGluZy5zaXplID09PSBmcmFnbWVudC5jb3VudCkge1xuICAgICAgICAgIGNvbnN0IGRhdGEgPSBbLi4ucGVuZGluZy52YWx1ZXMoKV1cbiAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBhLmluZGV4IC0gYi5pbmRleClcbiAgICAgICAgICAgIC5tYXAoKGl0ZW0pID0+IGl0ZW0uZGF0YSlcbiAgICAgICAgICAgIC5qb2luKCcnKTtcbiAgICAgICAgICB0aGlzLmZyYWdtZW50cy5kZWxldGUoZnJhZ21lbnQuaWQpO1xuICAgICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKGRhdGEpIGFzIFNweU1lc3NhZ2VTdG9yYWdlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1lc3NhZ2UpIHtcbiAgICAgICAgICBtZXNzYWdlLnNlcnZpY2VLZXlGb3JGdW5jdGlvbiA9IG1lc3NhZ2Uuc2VydmljZUtleS5yZXBsYWNlKC8jL2csICcnKTtcblxuICAgICAgICAgIGlmIChtZXNzYWdlLnNlcnZpY2VLZXkuc3RhcnRzV2l0aCgnRnVuY3Rpb24nKSkge1xuICAgICAgICAgICAgbWVzc2FnZS5mdW5jdGlvbkNvbnRleHRBd3NSZXF1ZXN0SWQgPSAoXG4gICAgICAgICAgICAgIG1lc3NhZ2UuZGF0YSBhcyBGdW5jdGlvblJlcXVlc3RTcHlFdmVudFxuICAgICAgICAgICAgKS5jb250ZXh0LmF3c1JlcXVlc3RJZDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnB1c2gobWVzc2FnZSk7XG4gICAgICAgICAgdGhpcy5yZXNvbHZlT2xkVHJhY2tlcldpdGhOZXdNZXNzYWdlKG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRoaXMuY29ubmVjdGlvbi5vbignY2xvc2UnLCAoKSA9PiB7XG4gICAgICAgIHRoaXMubG9nKCdDb25uZWN0aW9uIGNsb3NlZCcpO1xuXG4gICAgICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBjb25uZWN0aW9uT3BlblJlamVjdCA9XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbk9wZW5SZWplY3QgfHwgcGFyYW1zLmNvbm5lY3Rpb25PcGVuUmVqZWN0O1xuICAgICAgdGhpcy5jb25uZWN0aW9uLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICB0aGlzLmxvZygnQ29ubmVjdGlvbiBlcnJvcjonLCBlcnJvcik7XG4gICAgICAgIGNvbm5lY3Rpb25PcGVuUmVqZWN0Py4oZXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIGdldCBjb25uZWN0aW9uJywgZSk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBzdG9wKCkge1xuICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcbiAgICB0aGlzLmNvbm5lY3Rpb24hLmVuZCh0cnVlKTtcbiAgfVxuXG4gIHByaXZhdGUgdHJhY2tlck1hdGNoTWVzc2FnZSh0cmFja2VyOiBUcmFja2VyLCBtZXNzYWdlOiBTcHlNZXNzYWdlU3RvcmFnZSkge1xuICAgIGlmICh0cmFja2VyLmZpbmlzaGVkKSByZXR1cm47XG5cbiAgICBpZiAoXG4gICAgICAodHJhY2tlci5zZXJ2aWNlS2V5ICYmIHRyYWNrZXIuc2VydmljZUtleSA9PT0gbWVzc2FnZS5zZXJ2aWNlS2V5KSB8fFxuICAgICAgKHRyYWNrZXIuc2VydmljZUtleUZvckZ1bmN0aW9uICYmXG4gICAgICAgIHRyYWNrZXIuc2VydmljZUtleUZvckZ1bmN0aW9uID09PSBtZXNzYWdlLnNlcnZpY2VLZXlGb3JGdW5jdGlvbilcbiAgICApIHtcbiAgICAgIGlmICh0aGlzLnRyYWNrZXJNYXRjaENvbmRpdGlvbih0cmFja2VyLCBtZXNzYWdlKSkge1xuICAgICAgICB0cmFja2VyLmZpbmlzaGVkID0gdHJ1ZTtcblxuICAgICAgICBjb25zdCBzcHlBbmRKZXN0TWF0Y2hlcnM6IGFueSA9IHtcbiAgICAgICAgICBnZXREYXRhOiAoKSA9PiBtZXNzYWdlLmRhdGEsXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3Qgc2VydmljZUtleUZvckZ1bmN0aW9uID0gdHJhY2tlci5zZXJ2aWNlS2V5Rm9yRnVuY3Rpb247XG4gICAgICAgIGlmIChcbiAgICAgICAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb24gJiZcbiAgICAgICAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb24uc3RhcnRzV2l0aCgnRnVuY3Rpb24nKSAmJlxuICAgICAgICAgIChzZXJ2aWNlS2V5Rm9yRnVuY3Rpb24uZW5kc1dpdGgoJ1JlcXVlc3QnKSB8fFxuICAgICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uLmVuZHNXaXRoKCdDb25zb2xlJykpXG4gICAgICAgICkge1xuICAgICAgICAgIGxldCBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbiA9IHNlcnZpY2VLZXlGb3JGdW5jdGlvbjtcblxuICAgICAgICAgIGlmIChzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbi5lbmRzV2l0aCgnUmVxdWVzdCcpKSB7XG4gICAgICAgICAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbiA9IHNlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWluLnN1YnN0cmluZyhcbiAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4ubGVuZ3RoIC0gJ1JlcXVlc3QnLmxlbmd0aFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHNlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWluLmVuZHNXaXRoKCdDb25zb2xlJykpIHtcbiAgICAgICAgICAgIHNlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWluID0gc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4uc3Vic3RyaW5nKFxuICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbi5sZW5ndGggLSAnQ29uc29sZScubGVuZ3RoXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNweUFuZEplc3RNYXRjaGVycy5mb2xsb3dlZEJ5Q29uc29sZSA9IChwYXJhbXNXOiBXYWl0Rm9yUGFyYW1zKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVXYWl0Rm9yWFhYRnVuYyhcbiAgICAgICAgICAgICAgYCR7c2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW59Q29uc29sZWAsXG4gICAgICAgICAgICAgIChtZXNzYWdlLmRhdGEgYXMgRnVuY3Rpb25SZXF1ZXN0U3B5RXZlbnQpLmNvbnRleHQuYXdzUmVxdWVzdElkXG4gICAgICAgICAgICApKHBhcmFtc1cpO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICBzcHlBbmRKZXN0TWF0Y2hlcnMuZm9sbG93ZWRCeVJlc3BvbnNlID0gKHBhcmFtc1c6IFdhaXRGb3JQYXJhbXMpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNyZWF0ZVdhaXRGb3JYWFhGdW5jKFxuICAgICAgICAgICAgICBgJHtzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbn1SZXNwb25zZWAsXG4gICAgICAgICAgICAgIChtZXNzYWdlLmRhdGEgYXMgRnVuY3Rpb25SZXF1ZXN0U3B5RXZlbnQpLmNvbnRleHQuYXdzUmVxdWVzdElkXG4gICAgICAgICAgICApKHBhcmFtc1cpO1xuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcm94eSA9IG5ldyBQcm94eShzcHlBbmRKZXN0TWF0Y2hlcnMsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICh0YXJnZXQ6IGFueSwgb2JqZWN0S2V5OiBzdHJpbmcpIHtcbiAgICAgICAgICAgIGlmICh0YXJnZXQuaGFzT3duUHJvcGVydHkob2JqZWN0S2V5KSkge1xuICAgICAgICAgICAgICByZXR1cm4gdGFyZ2V0W29iamVjdEtleV07XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9iamVjdEtleSAhPT0gJ3RoZW4nKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgamVzdEZ1bmN0aW9uVG9FeGVjdXRlID0gKGV4cGVjdChtZXNzYWdlLmRhdGEpIGFzIGFueSlbXG4gICAgICAgICAgICAgICAgICBvYmplY3RLZXlcbiAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgIGplc3RGdW5jdGlvblRvRXhlY3V0ZS5hcHBseSh1bmRlZmluZWQsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb3h5O1xuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRyYWNrZXIucHJvbWlzZVJlc29sdmUocHJveHkpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSByZXNvbHZlVHJhY2tlckluT2xkTWVzc2FnZXModHJhY2tlcjogVHJhY2tlcikge1xuICAgIGZvciAoY29uc3QgbWVzc2FnZSBvZiB0aGlzLm1lc3NhZ2VzKSB7XG4gICAgICBpZiAodGhpcy50cmFja2VyTWF0Y2hNZXNzYWdlKHRyYWNrZXIsIG1lc3NhZ2UpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZU9sZFRyYWNrZXJXaXRoTmV3TWVzc2FnZShtZXNzYWdlOiBTcHlNZXNzYWdlU3RvcmFnZSkge1xuICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB0aGlzLnRyYWNrZXJzLmxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgY29uc3QgdHJhY2tlciA9IHRoaXMudHJhY2tlcnNbaW5kZXhdO1xuICAgICAgaWYgKHRoaXMudHJhY2tlck1hdGNoTWVzc2FnZSh0cmFja2VyLCBtZXNzYWdlKSkge1xuICAgICAgICB0aGlzLnRyYWNrZXJzID0gdGhpcy50cmFja2Vycy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIHRyYWNrZXJNYXRjaENvbmRpdGlvbih0cmFja2VyOiBUcmFja2VyLCBtZXNzYWdlOiBTcHlNZXNzYWdlU3RvcmFnZSkge1xuICAgIGNvbnN0IG1hdGNoQ29uZGl0aW9uID1cbiAgICAgICh0cmFja2VyLmNvbmRpdGlvbiAmJiB0cmFja2VyLmNvbmRpdGlvbihtZXNzYWdlLmRhdGEpKSB8fFxuICAgICAgIXRyYWNrZXIuY29uZGl0aW9uO1xuXG4gICAgY29uc3QgbWF0Y2hSZXF1ZXN0SWQgPVxuICAgICAgKHRyYWNrZXIuZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkICYmXG4gICAgICAgIHRyYWNrZXIuZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkID09PVxuICAgICAgICAgIG1lc3NhZ2UuZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkKSB8fFxuICAgICAgIXRyYWNrZXIuZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkO1xuXG4gICAgaWYgKG1hdGNoQ29uZGl0aW9uICYmIG1hdGNoUmVxdWVzdElkKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKFxuICAgICAgICAhbWF0Y2hDb25kaXRpb24gJiZcbiAgICAgICAgbWF0Y2hSZXF1ZXN0SWQgJiZcbiAgICAgICAgIXRyYWNrZXIucG9zc2libGVTcHlNZXNzYWdlRGF0YUZvckRlYnVnZ2luZ1xuICAgICAgKSB7XG4gICAgICAgIHRyYWNrZXIucG9zc2libGVTcHlNZXNzYWdlRGF0YUZvckRlYnVnZ2luZyA9IG1lc3NhZ2UuZGF0YTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVdhaXRGb3JYWFhGdW5jKFxuICAgIHNlcnZpY2VLZXlGb3JGdW5jdGlvbjogc3RyaW5nLFxuICAgIGZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZD86IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gKHBhcmFtc1c/OiBXYWl0Rm9yUGFyYW1zKSA9PiB7XG4gICAgICBsZXQgcmVzb2x2ZTogKHZhbHVlOiB2b2lkIHwgUHJvbWlzZUxpa2U8YW55PikgPT4gdm9pZDtcbiAgICAgIGNvbnN0IHByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzKSA9PiB7XG4gICAgICAgIHJlc29sdmUgPSByZXM7XG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHRyYWNrZXI6IFRyYWNrZXIgPSB7XG4gICAgICAgIGZpbmlzaGVkOiBmYWxzZSxcbiAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICBwcm9taXNlUmVzb2x2ZTogcmVzb2x2ZSxcbiAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uLFxuICAgICAgICBmdW5jdGlvbkNvbnRleHRBd3NSZXF1ZXN0SWQsXG4gICAgICB9O1xuXG4gICAgICB0cmFja2VyLmNvbmRpdGlvbiA9IHBhcmFtc1c/LmNvbmRpdGlvbjtcblxuICAgICAgbGV0IHRpbWVvdXRQaWQ6IE5vZGVKUy5UaW1lb3V0IHwgdW5kZWZpbmVkO1xuICAgICAgY29uc3QgdGltZXIgPSBuZXcgUHJvbWlzZSgoXywgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRpbWVvdXRQaWQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICBpZiAodHJhY2tlci5maW5pc2hlZCkgcmV0dXJuO1xuICAgICAgICAgIHRyYWNrZXIuZmluaXNoZWQgPSB0cnVlO1xuICAgICAgICAgIGxldCBtZXNzYWdlID0gYFRpbWVvdXQgd2FpdGluZyBmb3IgU2VydmVybGVzcyBTcHkgbWVzc2FnZSAke3NlcnZpY2VLZXlGb3JGdW5jdGlvbn0uYDtcblxuICAgICAgICAgIGlmICh0cmFja2VyLnBvc3NpYmxlU3B5TWVzc2FnZURhdGFGb3JEZWJ1Z2dpbmcpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UgKz0gYCBTaW1pbGFyIG1hdGNoaW5nIHNweSBldmVudCBkYXRhOiAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICB0cmFja2VyLnBvc3NpYmxlU3B5TWVzc2FnZURhdGFGb3JEZWJ1Z2dpbmcsXG4gICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgIDJcbiAgICAgICAgICAgICl9YDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKG1lc3NhZ2UpKTtcbiAgICAgICAgfSwgcGFyYW1zVz8udGltb3V0TXMgfHwgMTAwMDApO1xuICAgICAgfSk7XG5cbiAgICAgIGlmICghdGhpcy5yZXNvbHZlVHJhY2tlckluT2xkTWVzc2FnZXModHJhY2tlcikpIHtcbiAgICAgICAgdGhpcy50cmFja2Vycy5wdXNoKHRyYWNrZXIpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gUHJvbWlzZS5yYWNlKFtwcm9taXNlLCB0aW1lcl0pLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICBpZiAoISF0aW1lb3V0UGlkKSB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRQaWQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGNyZWF0ZVByb3h5KCkge1xuICAgIGNvbnN0IHNweUxpc3RlbmVyID0ge30gYXMgU2VydmVybGVzc1NweUxpc3RlbmVyPFRTcHlFdmVudHM+O1xuXG4gICAgc3B5TGlzdGVuZXIuc3RvcCA9IGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMuc3RvcCgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gbmV3IFByb3h5PFNlcnZlcmxlc3NTcHlMaXN0ZW5lcjxUU3B5RXZlbnRzPj4oc3B5TGlzdGVuZXIsIHtcbiAgICAgIGdldDogKHRhcmdldDogYW55LCBvYmplY3RLZXk6IHN0cmluZykgPT4ge1xuICAgICAgICBpZiAodGFyZ2V0Lmhhc093blByb3BlcnR5KG9iamVjdEtleSkpIHtcbiAgICAgICAgICByZXR1cm4gdGFyZ2V0W29iamVjdEtleV0uYmluZCh0YXJnZXQpO1xuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIHR5cGVvZiBvYmplY3RLZXkgPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgb2JqZWN0S2V5LnN0YXJ0c1dpdGgodGhpcy5mdW5jdGlvblByZWZpeClcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3Qgc2VydmljZUtleUZvckZ1bmN0aW9uID0gb2JqZWN0S2V5LnN1YnN0cmluZyhcbiAgICAgICAgICAgIHRoaXMuZnVuY3Rpb25QcmVmaXgubGVuZ3RoXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIHJldHVybiB0aGlzLmNyZWF0ZVdhaXRGb3JYWFhGdW5jKHNlcnZpY2VLZXlGb3JGdW5jdGlvbik7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGxvZyhtZXNzYWdlOiBzdHJpbmcsIC4uLm9wdGlvbmFsUGFyYW1zOiBhbnlbXSkge1xuICAgIGlmICh0aGlzLmRlYnVnTW9kZSAmJiAhdGhpcy5jbG9zZWQpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoXG4gICAgICAgICdTU1BZJyxcbiAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAuLi5vcHRpb25hbFBhcmFtc1xuICAgICAgKTtcbiAgICB9XG4gIH1cbn1cblxudHlwZSBUcmFja2VyID0ge1xuICBwcm9taXNlUmVzb2x2ZTogKGRhdGE6IGFueSkgPT4gdm9pZDtcbiAgZmluaXNoZWQ6IGJvb2xlYW47XG4gIHNlcnZpY2VLZXk/OiBzdHJpbmc7XG4gIHNlcnZpY2VLZXlGb3JGdW5jdGlvbj86IHN0cmluZztcbiAgY29uZGl0aW9uPzogKGRhdGE6IGFueSkgPT4gYm9vbGVhbjtcbiAgdGltb3V0TXM/OiBudW1iZXI7XG4gIGZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZD86IHN0cmluZztcbiAgcG9zc2libGVTcHlNZXNzYWdlRGF0YUZvckRlYnVnZ2luZz86IGFueTtcbn07XG5cbnR5cGUgU3B5TWVzc2FnZVN0b3JhZ2UgPSBTcHlNZXNzYWdlICYge1xuICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb246IHN0cmluZztcbiAgZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkPzogc3RyaW5nO1xufTtcbiJdfQ==