UNPKG

@synerty/vortexjs

Version:

Custom observable data serialisation and routing based on Angular 2+

228 lines 29.3 kB
import { dateStr } from "./UtilMisc"; import { rapuiClientEcho } from "./PayloadFilterKeys"; import { payloadIO } from "./PayloadIO"; import { VortexStateEnum } from "./VortexStatusService"; import { PayloadEnvelope } from "./PayloadEnvelope"; import { Network } from "@capacitor/network"; /** * Server response timeout in milliseconds * @type {number} */ export let SERVER_RESPONSE_TIMEOUT_SECONDS = 20.0; export var VortexClientStateE; (function (VortexClientStateE) { VortexClientStateE[VortexClientStateE["Idle"] = 0] = "Idle"; VortexClientStateE[VortexClientStateE["Connecting"] = 1] = "Connecting"; VortexClientStateE[VortexClientStateE["Online"] = 2] = "Online"; VortexClientStateE[VortexClientStateE["Closing"] = 3] = "Closing"; VortexClientStateE[VortexClientStateE["Closed"] = 4] = "Closed"; })(VortexClientStateE || (VortexClientStateE = {})); export class VortexClientABC { vortexStatusService; headers; HEART_BEAT_PERIOD_SECONDS = 10.0; HEART_BEAT_TIMEOUT_SECONDS = 180.0; RECONNECT_BACKOFF_SECONDS = 10.0; beatTimer = null; _uuid; _name; _url; _vortexState = VortexClientStateE.Idle; _isShutdown = false; serverVortexUuid = null; serverVortexName = null; processingNetworkStateChange = false; /** * RapUI VortexService, This class is responsible for sending and receiving payloads to/from * the server. */ constructor(vortexStatusService, url, vortexClientName, headers) { this.vortexStatusService = vortexStatusService; this.headers = headers; this._uuid = VortexClientABC.makeUuid(); this._name = vortexClientName; this._url = url; // If the user switches network types, then reset the abort timer Network.addListener("networkStatusChange", (status) => { // We only want to do something if we DISconnect if (status.connected) { return; } // If we're already doing something, then do nothing if (this.processingNetworkStateChange) { return; } this.processingNetworkStateChange = true; this.shutdown() .catch((e) => console.log(`ERROR: VortexClientABC - Network State Change failed - ${e}`)) .then(() => (this.processingNetworkStateChange = false)); }); } static makeUuid() { function func(c) { let r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8; return v.toString(16); } return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, func); } get url() { return this._url; } get uuid() { return this._uuid; } get name() { return this._name; } get isConnecting() { return this._vortexState === VortexClientStateE.Connecting; } get isClosed() { return this._vortexState === VortexClientStateE.Closed; } get isClosing() { return this._vortexState === VortexClientStateE.Closing; } get isOnline() { return this._vortexState === VortexClientStateE.Online; } get isShutdown() { return this._isShutdown; } async close() { this._vortexState = VortexClientStateE.Closing; this.vortexStatusService.logInfo(`VortexClientABC shutting down vortex`); this.clearBeatTimer(); await this.shutdown(); } setConnecting() { this.vortexStatusService.setVortexState(VortexStateEnum.Reconnecting); this._vortexState = VortexClientStateE.Connecting; this.restartTimer(); } setOnline() { this.vortexStatusService.logConnectionInfo("Vortex Online"); this._vortexState = VortexClientStateE.Online; this.vortexStatusService.setVortexState(VortexStateEnum.Online); this.restartTimer(); } setClosing() { this._vortexState = VortexClientStateE.Closing; this.vortexStatusService.setVortexState(VortexStateEnum.Reconnecting); } setClosed() { this._vortexState = VortexClientStateE.Closed; this.vortexStatusService.setVortexState(this.isShutdown ? VortexStateEnum.Disabled : VortexStateEnum.Reconnecting); if (!this.isShutdown) this.restartTimer(); } setShutdown() { this._isShutdown = true; } async reconnect() { this._vortexState = VortexClientStateE.Idle; await this.send(new PayloadEnvelope()); this.restartTimer(); } beat() { // We may still get a beat before the connection closes if (!this.isOnline) return; this.restartTimer(); } restartTimer() { this.clearBeatTimer(); // If we're online, then use the heartbeat timeout // If we're not online, then use the reconnect backoff const timerSeconds = this.isOnline ? this.HEART_BEAT_TIMEOUT_SECONDS : this.RECONNECT_BACKOFF_SECONDS; this.beatTimer = setTimeout(() => { if (this.isShutdown) return; this.dead(); this.reconnect() .then(() => { this.restartTimer(); }) .catch((e) => { this.vortexStatusService.logError(`restartTimer ${e}`); }); }, timerSeconds * 1000); } clearBeatTimer() { if (this.beatTimer != null) { clearTimeout(this.beatTimer); this.beatTimer = null; } } dead() { this.vortexStatusService.setVortexState(VortexStateEnum.Reconnecting); this.vortexStatusService.logInfo(`VortexService server heartbeats have timed out : ${this._url}`); } async send(payloadEnvelope) { if (this.isShutdown) { let msg = dateStr() + "VortexService is closed, Probably due to a login page reload"; console.log(msg); throw new Error("An attempt was made to reconnect a closed vortex"); } let payloadEnvelopes = []; if (payloadEnvelope instanceof Array) payloadEnvelopes = payloadEnvelope; else payloadEnvelopes = [payloadEnvelope]; for (let p of payloadEnvelopes) { // Empty payloadEnvelopes are like heart beats, don't check them if (!p.isEmpty() && p.filt["key"] == null) { throw new Error("There is no 'key' in the payloadEnvelopes filt" + ", There must be one for routing"); } } let vortexMsgs = []; let promises = []; for (let payloadEnvelope of payloadEnvelopes) { promises.push(payloadEnvelope .toVortexMsg() .then((vortexMsg) => vortexMsgs.push(vortexMsg))); } try { await Promise.all(promises); return this.sendVortexMsg(vortexMsgs); } catch (e) { let msg = `ERROR VortexClientABC: ${e.toString()}`; console.log(msg); throw new Error(msg); } } /** * Receive * This should only be called only from VortexConnection * @param payloadEnvelope {Payload} */ receive(payloadEnvelope) { this.beat(); if (payloadEnvelope.filt.hasOwnProperty(rapuiClientEcho)) { delete payloadEnvelope[rapuiClientEcho]; this.send(payloadEnvelope); } if (payloadEnvelope.isEmpty()) { if (payloadEnvelope.filt[PayloadEnvelope.vortexUuidKey] != null) this.serverVortexUuid = payloadEnvelope.filt[PayloadEnvelope.vortexUuidKey]; if (payloadEnvelope.filt[PayloadEnvelope.vortexNameKey] != null) this.serverVortexName = payloadEnvelope.filt[PayloadEnvelope.vortexNameKey]; return; } console.log(dateStr() + "Received payloadEnvelope with filt : " + JSON.stringify(payloadEnvelope.filt)); // TODO, Tell the payloadIO the vortexUuid payloadIO.process(payloadEnvelope); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVm9ydGV4Q2xpZW50QUJDLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3ZvcnRleC9Wb3J0ZXhDbGllbnRBQkMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNyQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN4QyxPQUFPLEVBQUUsZUFBZSxFQUF1QixNQUFNLHVCQUF1QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFHN0M7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLElBQUksK0JBQStCLEdBQUcsSUFBSSxDQUFDO0FBRWxELE1BQU0sQ0FBTixJQUFZLGtCQU1YO0FBTkQsV0FBWSxrQkFBa0I7SUFDMUIsMkRBQUksQ0FBQTtJQUNKLHVFQUFVLENBQUE7SUFDViwrREFBTSxDQUFBO0lBQ04saUVBQU8sQ0FBQTtJQUNQLCtEQUFNLENBQUE7QUFDVixDQUFDLEVBTlcsa0JBQWtCLEtBQWxCLGtCQUFrQixRQU03QjtBQUVELE1BQU0sT0FBZ0IsZUFBZTtJQXNCbkI7SUFHTTtJQXhCWCx5QkFBeUIsR0FBRyxJQUFJLENBQUM7SUFDakMsMEJBQTBCLEdBQUcsS0FBSyxDQUFDO0lBQ25DLHlCQUF5QixHQUFHLElBQUksQ0FBQztJQUVsQyxTQUFTLEdBQWUsSUFBSSxDQUFDO0lBQ3BCLEtBQUssQ0FBUztJQUNkLEtBQUssQ0FBUztJQUNaLElBQUksQ0FBUztJQUN0QixZQUFZLEdBQXVCLGtCQUFrQixDQUFDLElBQUksQ0FBQztJQUMzRCxXQUFXLEdBQVksS0FBSyxDQUFDO0lBRS9CLGdCQUFnQixHQUFrQixJQUFJLENBQUM7SUFDdkMs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TyxFQUFFO1lBQ0wsdUNBQXVDO1lBQ3ZDLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUMzQyxDQUFDO1FBRUYsMENBQTBDO1FBQzFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDdkMsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGF5bG9hZCB9IGZyb20gXCIuL1BheWxvYWRcIjtcbmltcG9ydCB7IGRhdGVTdHIgfSBmcm9tIFwiLi9VdGlsTWlzY1wiO1xuaW1wb3J0IHsgcmFwdWlDbGllbnRFY2hvIH0gZnJvbSBcIi4vUGF5bG9hZEZpbHRlcktleXNcIjtcbmltcG9ydCB7IHBheWxvYWRJTyB9IGZyb20gXCIuL1BheWxvYWRJT1wiO1xuaW1wb3J0IHsgVm9ydGV4U3RhdGVFbnVtLCBWb3J0ZXhTdGF0dXNTZXJ2aWNlIH0gZnJvbSBcIi4vVm9ydGV4U3RhdHVzU2VydmljZVwiO1xuaW1wb3J0IHsgUGF5bG9hZEVudmVsb3BlIH0gZnJvbSBcIi4vUGF5bG9hZEVudmVsb3BlXCI7XG5pbXBvcnQgeyBOZXR3b3JrIH0gZnJvbSBcIkBjYXBhY2l0b3IvbmV0d29ya1wiO1xuaW1wb3J0IHsgSHR0cEhlYWRlcnMgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcblxuLyoqXG4gKiBTZXJ2ZXIgcmVzcG9uc2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHNcbiAqIEB0eXBlIHtudW1iZXJ9XG4gKi9cbmV4cG9ydCBsZXQgU0VSVkVSX1JFU1BPTlNFX1RJTUVPVVRfU0VDT05EUyA9IDIwLjA7XG5cbmV4cG9ydCBlbnVtIFZvcnRleENsaWVudFN0YXRlRSB7XG4gICAgSWRsZSxcbiAgICBDb25uZWN0aW5nLFxuICAgIE9ubGluZSxcbiAgICBDbG9zaW5nLFxuICAgIENsb3NlZCxcbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFZvcnRleENsaWVudEFCQyB7XG4gICAgcmVhZG9ubHkgSEVBUlRfQkVBVF9QRVJJT0RfU0VDT05EUyA9IDEwLjA7XG4gICAgcmVhZG9ubHkgSEVBUlRfQkVBVF9USU1FT1VUX1NFQ09ORFMgPSAxODAuMDtcbiAgICByZWFkb25seSBSRUNPTk5FQ1RfQkFDS09GRl9TRUNPTkRTID0gMTAuMDtcblxuICAgIHByaXZhdGUgYmVhdFRpbWVyOiBhbnkgfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF91dWlkOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfbmFtZTogc3RyaW5nO1xuICAgIHByb3RlY3RlZCByZWFkb25seSBfdXJsOiBzdHJpbmc7XG4gICAgcHJvdGVjdGVkIF92b3J0ZXhTdGF0ZTogVm9ydGV4Q2xpZW50U3RhdGVFID0gVm9ydGV4Q2xpZW50U3RhdGVFLklkbGU7XG4gICAgcHJvdGVjdGVkIF9pc1NodXRkb3duOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBwcml2YXRlIHNlcnZlclZvcnRleFV1aWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgIHByaXZhdGUgc2VydmVyVm9ydGV4TmFtZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgICBwcml2YXRlIHByb2Nlc3NpbmdOZXR3b3JrU3RhdGVDaGFuZ2UgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFJhcFVJIFZvcnRleFNlcnZpY2UsIFRoaXMgY2xhc3MgaXMgcmVzcG9uc2libGUgZm9yIHNlbmRpbmcgYW5kIHJlY2VpdmluZyBwYXlsb2FkcyB0by9mcm9tXG4gICAgICogdGhlIHNlcnZlci5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoXG4gICAgICAgIHByb3RlY3RlZCB2b3J0ZXhTdGF0dXNTZXJ2aWNlOiBWb3J0ZXhTdGF0dXNTZXJ2aWNlLFxuICAgICAgICB1cmw6IHN0cmluZyxcbiAgICAgICAgdm9ydGV4Q2xpZW50TmFtZTogc3RyaW5nLFxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgaGVhZGVyczogSHR0cEhlYWRlcnMsXG4gICAgKSB7XG4gICAgICAgIHRoaXMuX3V1aWQgPSBWb3J0ZXhDbGllbnRBQkMubWFrZVV1aWQoKTtcbiAgICAgICAgdGhpcy5fbmFtZSA9IHZvcnRleENsaWVudE5hbWU7XG4gICAgICAgIHRoaXMuX3VybCA9IHVybDtcblxuICAgICAgICAvLyBJZiB0aGUgdXNlciBzd2l0Y2hlcyBuZXR3b3JrIHR5cGVzLCB0aGVuIHJlc2V0IHRoZSBhYm9ydCB0aW1lclxuICAgICAgICBOZXR3b3JrLmFkZExpc3RlbmVyKFwibmV0d29ya1N0YXR1c0NoYW5nZVwiLCAoc3RhdHVzKSA9PiB7XG4gICAgICAgICAgICAvLyBXZSBvbmx5IHdhbnQgdG8gZG8gc29tZXRoaW5nIGlmIHdlIERJU2Nvbm5lY3RcbiAgICAgICAgICAgIGlmIChzdGF0dXMuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSdyZSBhbHJlYWR5IGRvaW5nIHNvbWV0aGluZywgdGhlbiBkbyBub3RoaW5nXG4gICAgICAgICAgICBpZiAodGhpcy5wcm9jZXNzaW5nTmV0d29ya1N0YXRlQ2hhbmdlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NpbmdOZXR3b3JrU3RhdGVDaGFuZ2UgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5zaHV0ZG93bigpXG4gICAgICAgICAgICAgICAgLmNhdGNoKChlKSA9PlxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIGBFUlJPUjogVm9ydGV4Q2xpZW50QUJDIC0gTmV0d29yayBTdGF0ZSBDaGFuZ2UgZmFpbGVkIC0gJHtlfWAsXG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+ICh0aGlzLnByb2Nlc3NpbmdOZXR3b3JrU3RhdGVDaGFuZ2UgPSBmYWxzZSkpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgbWFrZVV1aWQoKSB7XG4gICAgICAgIGZ1bmN0aW9uIGZ1bmMoYykge1xuICAgICAgICAgICAgbGV0IHIgPSAoTWF0aC5yYW5kb20oKSAqIDE2KSB8IDAsXG4gICAgICAgICAgICAgICAgdiA9IGMgPT09IFwieFwiID8gciA6IChyICYgMHgzKSB8IDB4ODtcbiAgICAgICAgICAgIHJldHVybiB2LnRvU3RyaW5nKDE2KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBcInh4eHh4eHh4LXh4eHgtNHh4eC15eHh4LXh4eHh4eHh4eHh4eFwiLnJlcGxhY2UoL1t4eV0vZywgZnVuYyk7XG4gICAgfVxuXG4gICAgZ2V0IHVybCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5fdXJsO1xuICAgIH1cblxuICAgIGdldCB1dWlkKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl91dWlkO1xuICAgIH1cblxuICAgIGdldCBuYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9uYW1lO1xuICAgIH1cblxuICAgIGdldCBpc0Nvbm5lY3RpbmcoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl92b3J0ZXhTdGF0ZSA9PT0gVm9ydGV4Q2xpZW50U3RhdGVFLkNvbm5lY3Rpbmc7XG4gICAgfVxuXG4gICAgZ2V0IGlzQ2xvc2VkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fdm9ydGV4U3RhdGUgPT09IFZvcnRleENsaWVudFN0YXRlRS5DbG9zZWQ7XG4gICAgfVxuXG4gICAgZ2V0IGlzQ2xvc2luZygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3ZvcnRleFN0YXRlID09PSBWb3J0ZXhDbGllbnRTdGF0ZUUuQ2xvc2luZztcbiAgICB9XG5cbiAgICBnZXQgaXNPbmxpbmUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl92b3J0ZXhTdGF0ZSA9PT0gVm9ydGV4Q2xpZW50U3RhdGVFLk9ubGluZTtcbiAgICB9XG5cbiAgICBnZXQgaXNTaHV0ZG93bigpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzU2h1dGRvd247XG4gICAgfVxuXG4gICAgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuX3ZvcnRleFN0YXRlID0gVm9ydGV4Q2xpZW50U3RhdGVFLkNsb3Npbmc7XG5cbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0luZm8oXG4gICAgICAgICAgICBgVm9ydGV4Q2xpZW50QUJDIHNodXR0aW5nIGRvd24gdm9ydGV4YCxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5jbGVhckJlYXRUaW1lcigpO1xuICAgICAgICBhd2FpdCB0aGlzLnNodXRkb3duKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldENvbm5lY3RpbmcoKSB7XG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5zZXRWb3J0ZXhTdGF0ZShWb3J0ZXhTdGF0ZUVudW0uUmVjb25uZWN0aW5nKTtcbiAgICAgICAgdGhpcy5fdm9ydGV4U3RhdGUgPSBWb3J0ZXhDbGllbnRTdGF0ZUUuQ29ubmVjdGluZztcbiAgICAgICAgdGhpcy5yZXN0YXJ0VGltZXIoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc2V0T25saW5lKCkge1xuICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nQ29ubmVjdGlvbkluZm8oXCJWb3J0ZXggT25saW5lXCIpO1xuICAgICAgICB0aGlzLl92b3J0ZXhTdGF0ZSA9IFZvcnRleENsaWVudFN0YXRlRS5PbmxpbmU7XG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5zZXRWb3J0ZXhTdGF0ZShWb3J0ZXhTdGF0ZUVudW0uT25saW5lKTtcbiAgICAgICAgdGhpcy5yZXN0YXJ0VGltZXIoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc2V0Q2xvc2luZygpIHtcbiAgICAgICAgdGhpcy5fdm9ydGV4U3RhdGUgPSBWb3J0ZXhDbGllbnRTdGF0ZUUuQ2xvc2luZztcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLnNldFZvcnRleFN0YXRlKFZvcnRleFN0YXRlRW51bS5SZWNvbm5lY3RpbmcpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzZXRDbG9zZWQoKSB7XG4gICAgICAgIHRoaXMuX3ZvcnRleFN0YXRlID0gVm9ydGV4Q2xpZW50U3RhdGVFLkNsb3NlZDtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLnNldFZvcnRleFN0YXRlKFxuICAgICAgICAgICAgdGhpcy5pc1NodXRkb3duXG4gICAgICAgICAgICAgICAgPyBWb3J0ZXhTdGF0ZUVudW0uRGlzYWJsZWRcbiAgICAgICAgICAgICAgICA6IFZvcnRleFN0YXRlRW51bS5SZWNvbm5lY3RpbmcsXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmlzU2h1dGRvd24pIHRoaXMucmVzdGFydFRpbWVyKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHNldFNodXRkb3duKCkge1xuICAgICAgICB0aGlzLl9pc1NodXRkb3duID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3Qgc2h1dGRvd24oKTogUHJvbWlzZTx2b2lkPjtcblxuICAgIGFzeW5jIHJlY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5fdm9ydGV4U3RhdGUgPSBWb3J0ZXhDbGllbnRTdGF0ZUUuSWRsZTtcbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kKG5ldyBQYXlsb2FkRW52ZWxvcGUoKSk7XG4gICAgICAgIHRoaXMucmVzdGFydFRpbWVyKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGJlYXQoKTogdm9pZCB7XG4gICAgICAgIC8vIFdlIG1heSBzdGlsbCBnZXQgYSBiZWF0IGJlZm9yZSB0aGUgY29ubmVjdGlvbiBjbG9zZXNcbiAgICAgICAgaWYgKCF0aGlzLmlzT25saW5lKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5yZXN0YXJ0VGltZXIoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgcmVzdGFydFRpbWVyKCkge1xuICAgICAgICB0aGlzLmNsZWFyQmVhdFRpbWVyKCk7XG5cbiAgICAgICAgLy8gSWYgd2UncmUgb25saW5lLCB0aGVuIHVzZSB0aGUgaGVhcnRiZWF0IHRpbWVvdXRcbiAgICAgICAgLy8gSWYgd2UncmUgbm90IG9ubGluZSwgdGhlbiB1c2UgdGhlIHJlY29ubmVjdCBiYWNrb2ZmXG4gICAgICAgIGNvbnN0IHRpbWVyU2Vjb25kcyA9IHRoaXMuaXNPbmxpbmVcbiAgICAgICAgICAgID8gdGhpcy5IRUFSVF9CRUFUX1RJTUVPVVRfU0VDT05EU1xuICAgICAgICAgICAgOiB0aGlzLlJFQ09OTkVDVF9CQUNLT0ZGX1NFQ09ORFM7XG5cbiAgICAgICAgdGhpcy5iZWF0VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlzU2h1dGRvd24pIHJldHVybjtcblxuICAgICAgICAgICAgdGhpcy5kZWFkKCk7XG4gICAgICAgICAgICB0aGlzLnJlY29ubmVjdCgpXG4gICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlc3RhcnRUaW1lcigpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dFcnJvcihgcmVzdGFydFRpbWVyICR7ZX1gKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSwgdGltZXJTZWNvbmRzICogMTAwMCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGNsZWFyQmVhdFRpbWVyKCkge1xuICAgICAgICBpZiAodGhpcy5iZWF0VGltZXIgIT0gbnVsbCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuYmVhdFRpbWVyKTtcbiAgICAgICAgICAgIHRoaXMuYmVhdFRpbWVyID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgZGVhZCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLnNldFZvcnRleFN0YXRlKFZvcnRleFN0YXRlRW51bS5SZWNvbm5lY3RpbmcpO1xuICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nSW5mbyhcbiAgICAgICAgICAgIGBWb3J0ZXhTZXJ2aWNlIHNlcnZlciBoZWFydGJlYXRzIGhhdmUgdGltZWQgb3V0IDogJHt0aGlzLl91cmx9YCxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3Qgc2VuZFZvcnRleE1zZyh2b3J0ZXhNc2dzOiBzdHJpbmdbXSk6IHZvaWQ7XG5cbiAgICBhc3luYyBzZW5kKFxuICAgICAgICBwYXlsb2FkRW52ZWxvcGU6IFBheWxvYWRFbnZlbG9wZSB8IFBheWxvYWRFbnZlbG9wZVtdLFxuICAgICk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5pc1NodXRkb3duKSB7XG4gICAgICAgICAgICBsZXQgbXNnID1cbiAgICAgICAgICAgICAgICBkYXRlU3RyKCkgK1xuICAgICAgICAgICAgICAgIFwiVm9ydGV4U2VydmljZSBpcyBjbG9zZWQsIFByb2JhYmx5IGR1ZSB0byBhIGxvZ2luIHBhZ2UgcmVsb2FkXCI7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhtc2cpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQW4gYXR0ZW1wdCB3YXMgbWFkZSB0byByZWNvbm5lY3QgYSBjbG9zZWQgdm9ydGV4XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHBheWxvYWRFbnZlbG9wZXM6IFBheWxvYWRFbnZlbG9wZVtdID0gW107XG4gICAgICAgIGlmIChwYXlsb2FkRW52ZWxvcGUgaW5zdGFuY2VvZiBBcnJheSlcbiAgICAgICAgICAgIHBheWxvYWRFbnZlbG9wZXMgPSBwYXlsb2FkRW52ZWxvcGU7XG4gICAgICAgIGVsc2UgcGF5bG9hZEVudmVsb3BlcyA9IFtwYXlsb2FkRW52ZWxvcGVdO1xuXG4gICAgICAgIGZvciAobGV0IHAgb2YgcGF5bG9hZEVudmVsb3Blcykge1xuICAgICAgICAgICAgLy8gRW1wdHkgcGF5bG9hZEVudmVsb3BlcyBhcmUgbGlrZSBoZWFydCBiZWF0cywgZG9uJ3QgY2hlY2sgdGhlbVxuICAgICAgICAgICAgaWYgKCFwLmlzRW1wdHkoKSAmJiBwLmZpbHRbXCJrZXlcIl0gPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgXCJUaGVyZSBpcyBubyAna2V5JyBpbiB0aGUgcGF5bG9hZEVudmVsb3BlcyBmaWx0XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIsIFRoZXJlIG11c3QgYmUgb25lIGZvciByb3V0aW5nXCIsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCB2b3J0ZXhNc2dzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBsZXQgcHJvbWlzZXMgPSBbXTtcblxuICAgICAgICBmb3IgKGxldCBwYXlsb2FkRW52ZWxvcGUgb2YgcGF5bG9hZEVudmVsb3Blcykge1xuICAgICAgICAgICAgcHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICBwYXlsb2FkRW52ZWxvcGVcbiAgICAgICAgICAgICAgICAgICAgLnRvVm9ydGV4TXNnKClcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oKHZvcnRleE1zZykgPT4gdm9ydGV4TXNncy5wdXNoKHZvcnRleE1zZykpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kVm9ydGV4TXNnKHZvcnRleE1zZ3MpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsZXQgbXNnID0gYEVSUk9SIFZvcnRleENsaWVudEFCQzogJHtlLnRvU3RyaW5nKCl9YDtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG1zZyk7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlY2VpdmVcbiAgICAgKiBUaGlzIHNob3VsZCBvbmx5IGJlIGNhbGxlZCBvbmx5IGZyb20gVm9ydGV4Q29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBwYXlsb2FkRW52ZWxvcGUge1BheWxvYWR9XG4gICAgICovXG4gICAgcHJvdGVjdGVkIHJlY2VpdmUocGF5bG9hZEVudmVsb3BlOiBQYXlsb2FkRW52ZWxvcGUpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5iZWF0KCk7XG4gICAgICAgIGlmIChwYXlsb2FkRW52ZWxvcGUuZmlsdC5oYXNPd25Qcm9wZXJ0eShyYXB1aUNsaWVudEVjaG8pKSB7XG4gICAgICAgICAgICBkZWxldGUgcGF5bG9hZEVudmVsb3BlW3JhcHVpQ2xpZW50RWNob107XG4gICAgICAgICAgICB0aGlzLnNlbmQocGF5bG9hZEVudmVsb3BlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXlsb2FkRW52ZWxvcGUuaXNFbXB0eSgpKSB7XG4gICAgICAgICAgICBpZiAocGF5bG9hZEVudmVsb3BlLmZpbHRbUGF5bG9hZEVudmVsb3BlLnZvcnRleFV1aWRLZXldICE9IG51bGwpXG4gICAgICAgICAgICAgICAgdGhpcy5zZXJ2ZXJWb3J0ZXhVdWlkID1cbiAgICAgICAgICAgICAgICAgICAgcGF5bG9hZEVudmVsb3BlLmZpbHRbUGF5bG9hZEVudmVsb3BlLnZvcnRleFV1aWRLZXldO1xuXG4gICAgICAgICAgICBpZiAocGF5bG9hZEVudmVsb3BlLmZpbHRbUGF5bG9hZEVudmVsb3BlLnZvcnRleE5hbWVLZXldICE9IG51bGwpXG4gICAgICAgICAgICAgICAgdGhpcy5zZXJ2ZXJWb3J0ZXhOYW1lID1cbiAgICAgICAgICAgICAgICAgICAgcGF5bG9hZEVudmVsb3BlLmZpbHRbUGF5bG9hZEVudmVsb3BlLnZvcnRleE5hbWVLZXldO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgIGRhdGVTdHIoKSArXG4gICAgICAgICAgICAgICAgXCJSZWNlaXZlZCBwYXlsb2FkRW52ZWxvcGUgd2l0aCBmaWx0IDogXCIgK1xuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHBheWxvYWRFbnZlbG9wZS5maWx0KSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBUT0RPLCBUZWxsIHRoZSBwYXlsb2FkSU8gdGhlIHZvcnRleFV1aWRcbiAgICAgICAgcGF5bG9hZElPLnByb2Nlc3MocGF5bG9hZEVudmVsb3BlKTtcbiAgICB9XG59XG4iXX0=