UNPKG

matrix-react-sdk

Version:
170 lines (164 loc) 27.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.CallStoreEvent = exports.CallStore = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _logger = require("matrix-js-sdk/src/logger"); var _groupCallEventHandler = require("matrix-js-sdk/src/webrtc/groupCallEventHandler"); var _matrixrtc = require("matrix-js-sdk/src/matrixrtc"); var _dispatcher = _interopRequireDefault(require("../dispatcher/dispatcher")); var _AsyncStore = require("./AsyncStore"); var _AsyncStoreWithClient = require("./AsyncStoreWithClient"); var _WidgetStore = _interopRequireDefault(require("./WidgetStore")); var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore")); var _SettingLevel = require("../settings/SettingLevel"); var _Call = require("../models/Call"); /* Copyright 2024 New Vector Ltd. Copyright 2022 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ let CallStoreEvent = exports.CallStoreEvent = /*#__PURE__*/function (CallStoreEvent) { CallStoreEvent["Call"] = "call"; CallStoreEvent["ConnectedCalls"] = "connected_calls"; return CallStoreEvent; }({}); class CallStore extends _AsyncStoreWithClient.AsyncStoreWithClient { static get instance() { if (!this._instance) { this._instance = new CallStore(); this._instance.start(); } return this._instance; } constructor() { super(_dispatcher.default); (0, _defineProperty2.default)(this, "_connectedCalls", new Set()); (0, _defineProperty2.default)(this, "calls", new Map()); // Key is room ID (0, _defineProperty2.default)(this, "callListeners", new Map()); (0, _defineProperty2.default)(this, "onWidgets", roomId => { if (!this.matrixClient) return; if (roomId === null) { // This store happened to start before the widget store was done // loading all rooms, so we need to initialize each room again for (const room of this.matrixClient.getRooms()) { this.updateRoom(room); } } else { const room = this.matrixClient.getRoom(roomId); // Widget updates can arrive before the room does, empirically if (room !== null) this.updateRoom(room); } }); (0, _defineProperty2.default)(this, "onGroupCall", groupCall => this.updateRoom(groupCall.room)); (0, _defineProperty2.default)(this, "onRTCSessionStart", (roomId, session) => { this.updateRoom(session.room); }); this.setMaxListeners(100); // One for each RoomTile } async onAction() { // nothing to do } async onReady() { if (!this.matrixClient) return; // We assume that the calls present in a room are a function of room // widgets and group calls, so we initialize the room map here and then // update it whenever those change for (const room of this.matrixClient.getRooms()) { this.updateRoom(room); } this.matrixClient.on(_groupCallEventHandler.GroupCallEventHandlerEvent.Incoming, this.onGroupCall); this.matrixClient.on(_groupCallEventHandler.GroupCallEventHandlerEvent.Outgoing, this.onGroupCall); this.matrixClient.matrixRTC.on(_matrixrtc.MatrixRTCSessionManagerEvents.SessionStarted, this.onRTCSessionStart); _WidgetStore.default.instance.on(_AsyncStore.UPDATE_EVENT, this.onWidgets); // If the room ID of a previously connected call is still in settings at // this time, that's a sign that we failed to disconnect from it // properly, and need to clean up after ourselves const uncleanlyDisconnectedRoomIds = _SettingsStore.default.getValue("activeCallRoomIds"); if (uncleanlyDisconnectedRoomIds.length) { await Promise.all([...uncleanlyDisconnectedRoomIds.map(async uncleanlyDisconnectedRoomId => { _logger.logger.log(`Cleaning up call state for room ${uncleanlyDisconnectedRoomId}`); await this.getCall(uncleanlyDisconnectedRoomId)?.clean(); }), _SettingsStore.default.setValue("activeCallRoomIds", null, _SettingLevel.SettingLevel.DEVICE, [])]); } } async onNotReady() { for (const [call, listenerMap] of this.callListeners) { // It's important that we remove the listeners before destroying the // call, because otherwise the call's onDestroy callback would fire // and immediately repopulate the map for (const [event, listener] of listenerMap) call.off(event, listener); call.destroy(); } this.callListeners.clear(); this.calls.clear(); this._connectedCalls.clear(); if (this.matrixClient) { this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Incoming, this.onGroupCall); this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Outgoing, this.onGroupCall); this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Ended, this.onGroupCall); this.matrixClient.matrixRTC.off(_matrixrtc.MatrixRTCSessionManagerEvents.SessionStarted, this.onRTCSessionStart); } _WidgetStore.default.instance.off(_AsyncStore.UPDATE_EVENT, this.onWidgets); } /** * The calls to which the user is currently connected. */ get connectedCalls() { return this._connectedCalls; } set connectedCalls(value) { this._connectedCalls = value; this.emit(CallStoreEvent.ConnectedCalls, value); // The room IDs are persisted to settings so we can detect unclean disconnects _SettingsStore.default.setValue("activeCallRoomIds", null, _SettingLevel.SettingLevel.DEVICE, [...value].map(call => call.roomId)); } updateRoom(room) { if (!this.calls.has(room.roomId)) { const call = _Call.Call.get(room); if (call) { const onConnectionState = state => { if (state === _Call.ConnectionState.Connected) { this.connectedCalls = new Set([...this.connectedCalls, call]); } else if (state === _Call.ConnectionState.Disconnected) { this.connectedCalls = new Set([...this.connectedCalls].filter(c => c !== call)); } }; const onDestroy = () => { this.calls.delete(room.roomId); for (const [event, listener] of this.callListeners.get(call)) call.off(event, listener); this.updateRoom(room); }; call.on(_Call.CallEvent.ConnectionState, onConnectionState); call.on(_Call.CallEvent.Destroy, onDestroy); this.calls.set(room.roomId, call); this.callListeners.set(call, new Map([[_Call.CallEvent.ConnectionState, onConnectionState], [_Call.CallEvent.Destroy, onDestroy]])); } this.emit(CallStoreEvent.Call, call, room.roomId); } } /** * Gets the call associated with the given room, if any. * @param {string} roomId The room's ID. * @returns {Call | null} The call. */ getCall(roomId) { return this.calls.get(roomId) ?? null; } /** * Gets the active call associated with the given room, if any. * @param roomId The room's ID. * @returns The active call. */ getActiveCall(roomId) { const call = this.getCall(roomId); return call !== null && this.connectedCalls.has(call) ? call : null; } } exports.CallStore = CallStore; (0, _defineProperty2.default)(CallStore, "_instance", void 0); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9ncm91cENhbGxFdmVudEhhbmRsZXIiLCJfbWF0cml4cnRjIiwiX2Rpc3BhdGNoZXIiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX0FzeW5jU3RvcmUiLCJfQXN5bmNTdG9yZVdpdGhDbGllbnQiLCJfV2lkZ2V0U3RvcmUiLCJfU2V0dGluZ3NTdG9yZSIsIl9TZXR0aW5nTGV2ZWwiLCJfQ2FsbCIsIkNhbGxTdG9yZUV2ZW50IiwiZXhwb3J0cyIsIkNhbGxTdG9yZSIsIkFzeW5jU3RvcmVXaXRoQ2xpZW50IiwiaW5zdGFuY2UiLCJfaW5zdGFuY2UiLCJzdGFydCIsImNvbnN0cnVjdG9yIiwiZGVmYXVsdERpc3BhdGNoZXIiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsIlNldCIsIk1hcCIsInJvb21JZCIsIm1hdHJpeENsaWVudCIsInJvb20iLCJnZXRSb29tcyIsInVwZGF0ZVJvb20iLCJnZXRSb29tIiwiZ3JvdXBDYWxsIiwic2Vzc2lvbiIsInNldE1heExpc3RlbmVycyIsIm9uQWN0aW9uIiwib25SZWFkeSIsIm9uIiwiR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQiLCJJbmNvbWluZyIsIm9uR3JvdXBDYWxsIiwiT3V0Z29pbmciLCJtYXRyaXhSVEMiLCJNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cyIsIlNlc3Npb25TdGFydGVkIiwib25SVENTZXNzaW9uU3RhcnQiLCJXaWRnZXRTdG9yZSIsIlVQREFURV9FVkVOVCIsIm9uV2lkZ2V0cyIsInVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZHMiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJsZW5ndGgiLCJQcm9taXNlIiwiYWxsIiwibWFwIiwidW5jbGVhbmx5RGlzY29ubmVjdGVkUm9vbUlkIiwibG9nZ2VyIiwibG9nIiwiZ2V0Q2FsbCIsImNsZWFuIiwic2V0VmFsdWUiLCJTZXR0aW5nTGV2ZWwiLCJERVZJQ0UiLCJvbk5vdFJlYWR5IiwiY2FsbCIsImxpc3RlbmVyTWFwIiwiY2FsbExpc3RlbmVycyIsImV2ZW50IiwibGlzdGVuZXIiLCJvZmYiLCJkZXN0cm95IiwiY2xlYXIiLCJjYWxscyIsIl9jb25uZWN0ZWRDYWxscyIsIkVuZGVkIiwiY29ubmVjdGVkQ2FsbHMiLCJ2YWx1ZSIsImVtaXQiLCJDb25uZWN0ZWRDYWxscyIsImhhcyIsIkNhbGwiLCJnZXQiLCJvbkNvbm5lY3Rpb25TdGF0ZSIsInN0YXRlIiwiQ29ubmVjdGlvblN0YXRlIiwiQ29ubmVjdGVkIiwiRGlzY29ubmVjdGVkIiwiZmlsdGVyIiwiYyIsIm9uRGVzdHJveSIsImRlbGV0ZSIsIkNhbGxFdmVudCIsIkRlc3Ryb3kiLCJzZXQiLCJnZXRBY3RpdmVDYWxsIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0b3Jlcy9DYWxsU3RvcmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvd2VicnRjL2dyb3VwQ2FsbEV2ZW50SGFuZGxlclwiO1xuaW1wb3J0IHsgTWF0cml4UlRDU2Vzc2lvbiwgTWF0cml4UlRDU2Vzc2lvbk1hbmFnZXJFdmVudHMgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4cnRjXCI7XG5cbmltcG9ydCB0eXBlIHsgR3JvdXBDYWxsLCBSb29tIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IGRlZmF1bHREaXNwYXRjaGVyIGZyb20gXCIuLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IFVQREFURV9FVkVOVCB9IGZyb20gXCIuL0FzeW5jU3RvcmVcIjtcbmltcG9ydCB7IEFzeW5jU3RvcmVXaXRoQ2xpZW50IH0gZnJvbSBcIi4vQXN5bmNTdG9yZVdpdGhDbGllbnRcIjtcbmltcG9ydCBXaWRnZXRTdG9yZSBmcm9tIFwiLi9XaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IFNldHRpbmdMZXZlbCB9IGZyb20gXCIuLi9zZXR0aW5ncy9TZXR0aW5nTGV2ZWxcIjtcbmltcG9ydCB7IENhbGwsIENhbGxFdmVudCwgQ29ubmVjdGlvblN0YXRlIH0gZnJvbSBcIi4uL21vZGVscy9DYWxsXCI7XG5cbmV4cG9ydCBlbnVtIENhbGxTdG9yZUV2ZW50IHtcbiAgICAvLyBTaWduYWxzIGEgY2hhbmdlIGluIHRoZSBjYWxsIGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIHJvb21cbiAgICBDYWxsID0gXCJjYWxsXCIsXG4gICAgLy8gU2lnbmFscyBhIGNoYW5nZSBpbiB0aGUgYWN0aXZlIGNhbGxzXG4gICAgQ29ubmVjdGVkQ2FsbHMgPSBcImNvbm5lY3RlZF9jYWxsc1wiLFxufVxuXG5leHBvcnQgY2xhc3MgQ2FsbFN0b3JlIGV4dGVuZHMgQXN5bmNTdG9yZVdpdGhDbGllbnQ8e30+IHtcbiAgICBwcml2YXRlIHN0YXRpYyBfaW5zdGFuY2U6IENhbGxTdG9yZTtcbiAgICBwdWJsaWMgc3RhdGljIGdldCBpbnN0YW5jZSgpOiBDYWxsU3RvcmUge1xuICAgICAgICBpZiAoIXRoaXMuX2luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLl9pbnN0YW5jZSA9IG5ldyBDYWxsU3RvcmUoKTtcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlLnN0YXJ0KCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2luc3RhbmNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKGRlZmF1bHREaXNwYXRjaGVyKTtcbiAgICAgICAgdGhpcy5zZXRNYXhMaXN0ZW5lcnMoMTAwKTsgLy8gT25lIGZvciBlYWNoIFJvb21UaWxlXG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uQWN0aW9uKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBub3RoaW5nIHRvIGRvXG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uUmVhZHkoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgaWYgKCF0aGlzLm1hdHJpeENsaWVudCkgcmV0dXJuO1xuICAgICAgICAvLyBXZSBhc3N1bWUgdGhhdCB0aGUgY2FsbHMgcHJlc2VudCBpbiBhIHJvb20gYXJlIGEgZnVuY3Rpb24gb2Ygcm9vbVxuICAgICAgICAvLyB3aWRnZXRzIGFuZCBncm91cCBjYWxscywgc28gd2UgaW5pdGlhbGl6ZSB0aGUgcm9vbSBtYXAgaGVyZSBhbmQgdGhlblxuICAgICAgICAvLyB1cGRhdGUgaXQgd2hlbmV2ZXIgdGhvc2UgY2hhbmdlXG4gICAgICAgIGZvciAoY29uc3Qgcm9vbSBvZiB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tcygpKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVJvb20ocm9vbSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQub24oR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQuSW5jb21pbmcsIHRoaXMub25Hcm91cENhbGwpO1xuICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vbihHcm91cENhbGxFdmVudEhhbmRsZXJFdmVudC5PdXRnb2luZywgdGhpcy5vbkdyb3VwQ2FsbCk7XG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50Lm1hdHJpeFJUQy5vbihNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cy5TZXNzaW9uU3RhcnRlZCwgdGhpcy5vblJUQ1Nlc3Npb25TdGFydCk7XG4gICAgICAgIFdpZGdldFN0b3JlLmluc3RhbmNlLm9uKFVQREFURV9FVkVOVCwgdGhpcy5vbldpZGdldHMpO1xuXG4gICAgICAgIC8vIElmIHRoZSByb29tIElEIG9mIGEgcHJldmlvdXNseSBjb25uZWN0ZWQgY2FsbCBpcyBzdGlsbCBpbiBzZXR0aW5ncyBhdFxuICAgICAgICAvLyB0aGlzIHRpbWUsIHRoYXQncyBhIHNpZ24gdGhhdCB3ZSBmYWlsZWQgdG8gZGlzY29ubmVjdCBmcm9tIGl0XG4gICAgICAgIC8vIHByb3Blcmx5LCBhbmQgbmVlZCB0byBjbGVhbiB1cCBhZnRlciBvdXJzZWx2ZXNcbiAgICAgICAgY29uc3QgdW5jbGVhbmx5RGlzY29ubmVjdGVkUm9vbUlkcyA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWU8c3RyaW5nW10+KFwiYWN0aXZlQ2FsbFJvb21JZHNcIik7XG4gICAgICAgIGlmICh1bmNsZWFubHlEaXNjb25uZWN0ZWRSb29tSWRzLmxlbmd0aCkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIC4uLnVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZHMubWFwKGFzeW5jICh1bmNsZWFubHlEaXNjb25uZWN0ZWRSb29tSWQpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmxvZyhgQ2xlYW5pbmcgdXAgY2FsbCBzdGF0ZSBmb3Igcm9vbSAke3VuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5nZXRDYWxsKHVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZCk/LmNsZWFuKCk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImFjdGl2ZUNhbGxSb29tSWRzXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIFtdKSxcbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uTm90UmVhZHkoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgZm9yIChjb25zdCBbY2FsbCwgbGlzdGVuZXJNYXBdIG9mIHRoaXMuY2FsbExpc3RlbmVycykge1xuICAgICAgICAgICAgLy8gSXQncyBpbXBvcnRhbnQgdGhhdCB3ZSByZW1vdmUgdGhlIGxpc3RlbmVycyBiZWZvcmUgZGVzdHJveWluZyB0aGVcbiAgICAgICAgICAgIC8vIGNhbGwsIGJlY2F1c2Ugb3RoZXJ3aXNlIHRoZSBjYWxsJ3Mgb25EZXN0cm95IGNhbGxiYWNrIHdvdWxkIGZpcmVcbiAgICAgICAgICAgIC8vIGFuZCBpbW1lZGlhdGVseSByZXBvcHVsYXRlIHRoZSBtYXBcbiAgICAgICAgICAgIGZvciAoY29uc3QgW2V2ZW50LCBsaXN0ZW5lcl0gb2YgbGlzdGVuZXJNYXApIGNhbGwub2ZmKGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICAgICAgICBjYWxsLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNhbGxMaXN0ZW5lcnMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5jYWxscy5jbGVhcigpO1xuICAgICAgICB0aGlzLl9jb25uZWN0ZWRDYWxscy5jbGVhcigpO1xuXG4gICAgICAgIGlmICh0aGlzLm1hdHJpeENsaWVudCkge1xuICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQub2ZmKEdyb3VwQ2FsbEV2ZW50SGFuZGxlckV2ZW50LkluY29taW5nLCB0aGlzLm9uR3JvdXBDYWxsKTtcbiAgICAgICAgICAgIHRoaXMubWF0cml4Q2xpZW50Lm9mZihHcm91cENhbGxFdmVudEhhbmRsZXJFdmVudC5PdXRnb2luZywgdGhpcy5vbkdyb3VwQ2FsbCk7XG4gICAgICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vZmYoR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQuRW5kZWQsIHRoaXMub25Hcm91cENhbGwpO1xuICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQubWF0cml4UlRDLm9mZihNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cy5TZXNzaW9uU3RhcnRlZCwgdGhpcy5vblJUQ1Nlc3Npb25TdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgV2lkZ2V0U3RvcmUuaW5zdGFuY2Uub2ZmKFVQREFURV9FVkVOVCwgdGhpcy5vbldpZGdldHMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Nvbm5lY3RlZENhbGxzOiBTZXQ8Q2FsbD4gPSBuZXcgU2V0KCk7XG4gICAgLyoqXG4gICAgICogVGhlIGNhbGxzIHRvIHdoaWNoIHRoZSB1c2VyIGlzIGN1cnJlbnRseSBjb25uZWN0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCBjb25uZWN0ZWRDYWxscygpOiBTZXQ8Q2FsbD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fY29ubmVjdGVkQ2FsbHM7XG4gICAgfVxuICAgIHByaXZhdGUgc2V0IGNvbm5lY3RlZENhbGxzKHZhbHVlOiBTZXQ8Q2FsbD4pIHtcbiAgICAgICAgdGhpcy5fY29ubmVjdGVkQ2FsbHMgPSB2YWx1ZTtcbiAgICAgICAgdGhpcy5lbWl0KENhbGxTdG9yZUV2ZW50LkNvbm5lY3RlZENhbGxzLCB2YWx1ZSk7XG5cbiAgICAgICAgLy8gVGhlIHJvb20gSURzIGFyZSBwZXJzaXN0ZWQgdG8gc2V0dGluZ3Mgc28gd2UgY2FuIGRldGVjdCB1bmNsZWFuIGRpc2Nvbm5lY3RzXG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXG4gICAgICAgICAgICBcImFjdGl2ZUNhbGxSb29tSWRzXCIsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgU2V0dGluZ0xldmVsLkRFVklDRSxcbiAgICAgICAgICAgIFsuLi52YWx1ZV0ubWFwKChjYWxsKSA9PiBjYWxsLnJvb21JZCksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYWxscyA9IG5ldyBNYXA8c3RyaW5nLCBDYWxsPigpOyAvLyBLZXkgaXMgcm9vbSBJRFxuICAgIHByaXZhdGUgY2FsbExpc3RlbmVycyA9IG5ldyBNYXA8Q2FsbCwgTWFwPENhbGxFdmVudCwgKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gdW5rbm93bj4+KCk7XG5cbiAgICBwcml2YXRlIHVwZGF0ZVJvb20ocm9vbTogUm9vbSk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuY2FsbHMuaGFzKHJvb20ucm9vbUlkKSkge1xuICAgICAgICAgICAgY29uc3QgY2FsbCA9IENhbGwuZ2V0KHJvb20pO1xuXG4gICAgICAgICAgICBpZiAoY2FsbCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG9uQ29ubmVjdGlvblN0YXRlID0gKHN0YXRlOiBDb25uZWN0aW9uU3RhdGUpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHN0YXRlID09PSBDb25uZWN0aW9uU3RhdGUuQ29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZENhbGxzID0gbmV3IFNldChbLi4udGhpcy5jb25uZWN0ZWRDYWxscywgY2FsbF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHN0YXRlID09PSBDb25uZWN0aW9uU3RhdGUuRGlzY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZENhbGxzID0gbmV3IFNldChbLi4udGhpcy5jb25uZWN0ZWRDYWxsc10uZmlsdGVyKChjKSA9PiBjICE9PSBjYWxsKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGNvbnN0IG9uRGVzdHJveSA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxscy5kZWxldGUocm9vbS5yb29tSWQpO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtldmVudCwgbGlzdGVuZXJdIG9mIHRoaXMuY2FsbExpc3RlbmVycy5nZXQoY2FsbCkhKSBjYWxsLm9mZihldmVudCwgbGlzdGVuZXIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVJvb20ocm9vbSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGNhbGwub24oQ2FsbEV2ZW50LkNvbm5lY3Rpb25TdGF0ZSwgb25Db25uZWN0aW9uU3RhdGUpO1xuICAgICAgICAgICAgICAgIGNhbGwub24oQ2FsbEV2ZW50LkRlc3Ryb3ksIG9uRGVzdHJveSk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxzLnNldChyb29tLnJvb21JZCwgY2FsbCk7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsTGlzdGVuZXJzLnNldChcbiAgICAgICAgICAgICAgICAgICAgY2FsbCxcbiAgICAgICAgICAgICAgICAgICAgbmV3IE1hcDxDYWxsRXZlbnQsICguLi5hcmdzOiBhbnlbXSkgPT4gdW5rbm93bj4oW1xuICAgICAgICAgICAgICAgICAgICAgICAgW0NhbGxFdmVudC5Db25uZWN0aW9uU3RhdGUsIG9uQ29ubmVjdGlvblN0YXRlXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFtDYWxsRXZlbnQuRGVzdHJveSwgb25EZXN0cm95XSxcbiAgICAgICAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5lbWl0KENhbGxTdG9yZUV2ZW50LkNhbGwsIGNhbGwsIHJvb20ucm9vbUlkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGNhbGwgYXNzb2NpYXRlZCB3aXRoIHRoZSBnaXZlbiByb29tLCBpZiBhbnkuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJvb21JZCBUaGUgcm9vbSdzIElELlxuICAgICAqIEByZXR1cm5zIHtDYWxsIHwgbnVsbH0gVGhlIGNhbGwuXG4gICAgICovXG4gICAgcHVibGljIGdldENhbGwocm9vbUlkOiBzdHJpbmcpOiBDYWxsIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGxzLmdldChyb29tSWQpID8/IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgYWN0aXZlIGNhbGwgYXNzb2NpYXRlZCB3aXRoIHRoZSBnaXZlbiByb29tLCBpZiBhbnkuXG4gICAgICogQHBhcmFtIHJvb21JZCBUaGUgcm9vbSdzIElELlxuICAgICAqIEByZXR1cm5zIFRoZSBhY3RpdmUgY2FsbC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0QWN0aXZlQ2FsbChyb29tSWQ6IHN0cmluZyk6IENhbGwgfCBudWxsIHtcbiAgICAgICAgY29uc3QgY2FsbCA9IHRoaXMuZ2V0Q2FsbChyb29tSWQpO1xuICAgICAgICByZXR1cm4gY2FsbCAhPT0gbnVsbCAmJiB0aGlzLmNvbm5lY3RlZENhbGxzLmhhcyhjYWxsKSA/IGNhbGwgOiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25XaWRnZXRzID0gKHJvb21JZDogc3RyaW5nIHwgbnVsbCk6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoIXRoaXMubWF0cml4Q2xpZW50KSByZXR1cm47XG4gICAgICAgIGlmIChyb29tSWQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgc3RvcmUgaGFwcGVuZWQgdG8gc3RhcnQgYmVmb3JlIHRoZSB3aWRnZXQgc3RvcmUgd2FzIGRvbmVcbiAgICAgICAgICAgIC8vIGxvYWRpbmcgYWxsIHJvb21zLCBzbyB3ZSBuZWVkIHRvIGluaXRpYWxpemUgZWFjaCByb29tIGFnYWluXG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJvb20gb2YgdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbXMoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlUm9vbShyb29tKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tKHJvb21JZCk7XG4gICAgICAgICAgICAvLyBXaWRnZXQgdXBkYXRlcyBjYW4gYXJyaXZlIGJlZm9yZSB0aGUgcm9vbSBkb2VzLCBlbXBpcmljYWxseVxuICAgICAgICAgICAgaWYgKHJvb20gIT09IG51bGwpIHRoaXMudXBkYXRlUm9vbShyb29tKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uR3JvdXBDYWxsID0gKGdyb3VwQ2FsbDogR3JvdXBDYWxsKTogdm9pZCA9PiB0aGlzLnVwZGF0ZVJvb20oZ3JvdXBDYWxsLnJvb20pO1xuICAgIHByaXZhdGUgb25SVENTZXNzaW9uU3RhcnQgPSAocm9vbUlkOiBzdHJpbmcsIHNlc3Npb246IE1hdHJpeFJUQ1Nlc3Npb24pOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGVSb29tKHNlc3Npb24ucm9vbSk7XG4gICAgfTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxzQkFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsVUFBQSxHQUFBRixPQUFBO0FBR0EsSUFBQUcsV0FBQSxHQUFBQyxzQkFBQSxDQUFBSixPQUFBO0FBQ0EsSUFBQUssV0FBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0scUJBQUEsR0FBQU4sT0FBQTtBQUNBLElBQUFPLFlBQUEsR0FBQUgsc0JBQUEsQ0FBQUosT0FBQTtBQUNBLElBQUFRLGNBQUEsR0FBQUosc0JBQUEsQ0FBQUosT0FBQTtBQUNBLElBQUFTLGFBQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLEtBQUEsR0FBQVYsT0FBQTtBQW5CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU5BLElBcUJZVyxjQUFjLEdBQUFDLE9BQUEsQ0FBQUQsY0FBQSwwQkFBZEEsY0FBYztFQUFkQSxjQUFjO0VBQWRBLGNBQWM7RUFBQSxPQUFkQSxjQUFjO0FBQUE7QUFP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