UNPKG

@hsaadawy/ngx-chat

Version:
183 lines 32.4 kB
import { __awaiter } from "tslib"; import { jid as parseJid, xml } from '@xmpp/client'; import { filter } from 'rxjs/operators'; import { Direction, MessageState } from '../../../../core/message'; import { AbstractXmppPlugin } from './abstract-xmpp-plugin'; import { MessageUuidPlugin } from './message-uuid.plugin'; const STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES = 'ngxchat:contactmessagestates'; const wrapperNodeName = 'entries'; const nodeName = 'contact-message-state'; /** * Plugin using PubSub to persist message read states. * Custom not part of the XMPP Specification * Standardized implementation specification would be https://xmpp.org/extensions/xep-0184.html */ export class MessageStatePlugin extends AbstractXmppPlugin { constructor(publishSubscribePlugin, xmppChatAdapter, chatMessageListRegistry, logService, entityTimePlugin) { super(); this.publishSubscribePlugin = publishSubscribePlugin; this.xmppChatAdapter = xmppChatAdapter; this.chatMessageListRegistry = chatMessageListRegistry; this.logService = logService; this.entityTimePlugin = entityTimePlugin; this.jidToMessageStateDate = Object.create(null); this.chatMessageListRegistry.openChats$ .pipe(filter(() => xmppChatAdapter.state$.getValue() === 'online')) .subscribe(contacts => { contacts.forEach((contact) => __awaiter(this, void 0, void 0, function* () { if (contact.mostRecentMessageReceived) { yield this.sendMessageStateNotification(contact.jidBare, contact.mostRecentMessageReceived.id, MessageState.RECIPIENT_SEEN); } })); }); this.publishSubscribePlugin.publish$ .subscribe((event) => this.handlePubSubEvent(event)); } onBeforeOnline() { return __awaiter(this, void 0, void 0, function* () { this.parseContactMessageStates().catch(err => this.logService.error('error parsing contact message states', err)); }); } parseContactMessageStates() { return __awaiter(this, void 0, void 0, function* () { const itemElements = yield this.publishSubscribePlugin.retrieveNodeItems(STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES); this.processPubSub(itemElements); }); } processPubSub(itemElements) { let results = []; if (itemElements.length === 1) { results = itemElements[0] .getChild(wrapperNodeName) .getChildren(nodeName) .map((contactMessageStateElement) => { const { lastRecipientReceived, lastRecipientSeen, lastSent, jid } = contactMessageStateElement.attrs; return [ jid, { lastRecipientSeen: new Date(+lastRecipientSeen || 0), lastRecipientReceived: new Date(+lastRecipientReceived || 0), lastSent: new Date(+lastSent || 0), } ]; }); } this.jidToMessageStateDate = new Map(results); } persistContactMessageStates() { return __awaiter(this, void 0, void 0, function* () { const messageStateElements = [...this.jidToMessageStateDate.entries()] .map(([jid, stateDates]) => xml(nodeName, { jid, lastRecipientReceived: String(stateDates.lastRecipientReceived.getTime()), lastRecipientSeen: String(stateDates.lastRecipientSeen.getTime()), lastSent: String(stateDates.lastSent.getTime()), })); yield this.publishSubscribePlugin.storePrivatePayloadPersistent(STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES, 'current', xml(wrapperNodeName, {}, messageStateElements)); }); } onOffline() { this.jidToMessageStateDate.clear(); } beforeSendMessage(messageStanza, message) { const { type } = messageStanza.attrs; if (type === 'chat' && message) { message.state = MessageState.SENDING; } } afterSendMessage(message, messageStanza) { return __awaiter(this, void 0, void 0, function* () { const { type, to } = messageStanza.attrs; if (type === 'chat') { this.updateContactMessageState(parseJid(to).bare().toString(), MessageState.SENT, new Date(yield this.entityTimePlugin.getNow())); delete message.state; } }); } afterReceiveMessage(messageReceived, stanza, messageReceivedEvent) { const messageStateElement = stanza.getChild('message-state', STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES); if (messageStateElement) { // we received a message state or a message via carbon from another resource, discard it messageReceivedEvent.discard = true; } else if (messageReceived.direction === Direction.in && !messageReceived.fromArchive && stanza.attrs.type !== 'groupchat') { this.acknowledgeReceivedMessage(stanza); } } acknowledgeReceivedMessage(stanza) { const { from } = stanza.attrs; const isChatWithContactOpen = this.chatMessageListRegistry.isChatOpen(this.xmppChatAdapter.getOrCreateContactById(from)); const state = isChatWithContactOpen ? MessageState.RECIPIENT_SEEN : MessageState.RECIPIENT_RECEIVED; const messageId = MessageUuidPlugin.extractIdFromStanza(stanza); this.sendMessageStateNotification(parseJid(from), messageId, state).catch(e => this.logService.error('error sending state notification', e)); } sendMessageStateNotification(recipient, messageId, state) { return __awaiter(this, void 0, void 0, function* () { const messageStateResponse = xml('message', { to: recipient.bare().toString(), from: this.xmppChatAdapter.chatConnectionService.userJid.toString(), type: 'chat' }, xml('message-state', { xmlns: STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES, messageId, date: new Date(yield this.entityTimePlugin.getNow()).toISOString(), state })); yield this.xmppChatAdapter.chatConnectionService.send(messageStateResponse); }); } handleStanza(stanza) { const { type, from } = stanza.attrs; const stateElement = stanza.getChild('message-state', STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES); if (type === 'chat' && stateElement) { this.handleStateNotificationStanza(stateElement, from); return true; } return false; } handleStateNotificationStanza(stateElement, from) { const { state, date } = stateElement.attrs; const contact = this.xmppChatAdapter.getOrCreateContactById(from); const stateDate = new Date(date); this.updateContactMessageState(contact.jidBare.toString(), state, stateDate); } updateContactMessageState(contactJid, state, stateDate) { const current = this.getContactMessageState(contactJid); let changed = false; if (state === MessageState.RECIPIENT_RECEIVED && current.lastRecipientReceived < stateDate) { current.lastRecipientReceived = stateDate; changed = true; } else if (state === MessageState.RECIPIENT_SEEN && current.lastRecipientSeen < stateDate) { current.lastRecipientReceived = stateDate; current.lastRecipientSeen = stateDate; changed = true; } else if (state === MessageState.SENT && current.lastSent < stateDate) { current.lastSent = stateDate; changed = true; } if (changed) { this.persistContactMessageStates().catch(err => this.logService.error('error persisting contact message states', err)); } } getContactMessageState(contactJid) { if (!this.jidToMessageStateDate.has(contactJid)) { this.jidToMessageStateDate.set(contactJid, { lastRecipientReceived: new Date(0), lastRecipientSeen: new Date(0), lastSent: new Date(0), }); } return this.jidToMessageStateDate.get(contactJid); } handlePubSubEvent(event) { const items = event.getChild('items'); const itemsNode = items === null || items === void 0 ? void 0 : items.attrs.node; const itemElements = items === null || items === void 0 ? void 0 : items.getChildren('item'); if (itemsNode === STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES && itemElements) { this.processPubSub(itemElements); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1zdGF0ZS5wbHVnaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9wYXp6bmV0d29yay9uZ3gtY2hhdC9zcmMvbGliL3NlcnZpY2VzL2FkYXB0ZXJzL3htcHAvcGx1Z2lucy9tZXNzYWdlLXN0YXRlLnBsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLEdBQUcsSUFBSSxRQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBR3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QyxPQUFPLEVBQUUsU0FBUyxFQUFXLFlBQVksRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBSzVFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRTVELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBWTFELE1BQU0sdUNBQXVDLEdBQUcsOEJBQThCLENBQUM7QUFDL0UsTUFBTSxlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQ2xDLE1BQU0sUUFBUSxHQUFHLHVCQUF1QixDQUFDO0FBRXpDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsa0JBQWtCO0lBSXRELFlBQ3FCLHNCQUE4QyxFQUM5QyxlQUFnQyxFQUNoQyx1QkFBdUQsRUFDdkQsVUFBc0IsRUFDdEIsZ0JBQWtDO1FBRW5ELEtBQUssRUFBRSxDQUFDO1FBTlMsMkJBQXNCLEdBQXRCLHNCQUFzQixDQUF3QjtRQUM5QyxvQkFBZSxHQUFmLGVBQWUsQ0FBaUI7UUFDaEMsNEJBQXVCLEdBQXZCLHVCQUF1QixDQUFnQztRQUN2RCxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ3RCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFQL0MsMEJBQXFCLEdBQTBCLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFD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QkFBcUIsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDN0MsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FDMUIsVUFBVSxFQUNWO2dCQUNJLHFCQUFxQixFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDbEMsaUJBQWlCLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM5QixRQUFRLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ3hCLENBQ0osQ0FBQztTQUNMO1FBQ0QsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFTyxpQkFBaUIsQ0FBQyxLQUFhO1FBQ25DLE1BQU0sS0FBSyxHQUF1QixLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFELE1BQU0sU0FBUyxHQUFHLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxLQUFLLENBQUMsSUFBSSxDQUFDO1FBQ3BDLE1BQU0sWUFBWSxHQUF5QixLQUFLLGFBQUwsS0FBSyx1QkFBTCxLQUFLLENBQUUsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RFLElBQUksU0FBUyxLQUFLLHVDQUF1QyxJQUFJLFlBQVksRUFBRTtZQUN2RSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDO1NBQ3BDO0lBQ0wsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgamlkIGFzIHBhcnNlSmlkLCB4bWwgfSBmcm9tICdAeG1wcC9jbGllbnQnO1xyXG5pbXBvcnQgeyBKSUQgfSBmcm9tICdAeG1wcC9qaWQnO1xyXG5pbXBvcnQgeyBFbGVtZW50IH0gZnJvbSAnbHR4JztcclxuaW1wb3J0IHsgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBEaXJlY3Rpb24sIE1lc3NhZ2UsIE1lc3NhZ2VTdGF0ZSB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvbWVzc2FnZSc7XHJcbmltcG9ydCB7IE1lc3NhZ2VXaXRoQm9keVN0YW56YSwgU3RhbnphIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9zdGFuemEnO1xyXG5pbXBvcnQgeyBDaGF0TWVzc2FnZUxpc3RSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9jaGF0LW1lc3NhZ2UtbGlzdC1yZWdpc3RyeS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgTG9nU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL2xvZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgWG1wcENoYXRBZGFwdGVyIH0gZnJvbSAnLi4veG1wcC1jaGF0LWFkYXB0ZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IEFic3RyYWN0WG1wcFBsdWdpbiB9IGZyb20gJy4vYWJzdHJhY3QteG1wcC1wbHVnaW4nO1xyXG5pbXBvcnQgeyBFbnRpdHlUaW1lUGx1Z2luIH0gZnJvbSAnLi9lbnRpdHktdGltZS5wbHVnaW4nO1xyXG5pbXBvcnQgeyBNZXNzYWdlVXVpZFBsdWdpbiB9IGZyb20gJy4vbWVzc2FnZS11dWlkLnBsdWdpbic7XHJcbmltcG9ydCB7IE1lc3NhZ2VSZWNlaXZlZEV2ZW50IH0gZnJvbSAnLi9tZXNzYWdlLnBsdWdpbic7XHJcbmltcG9ydCB7IFB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4gfSBmcm9tICcuL3B1Ymxpc2gtc3Vic2NyaWJlLnBsdWdpbic7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRlRGF0ZSB7XHJcbiAgICBsYXN0UmVjaXBpZW50UmVjZWl2ZWQ6IERhdGU7XHJcbiAgICBsYXN0UmVjaXBpZW50U2VlbjogRGF0ZTtcclxuICAgIGxhc3RTZW50OiBEYXRlO1xyXG59XHJcblxyXG5leHBvcnQgdHlwZSBKaWRUb01lc3NhZ2VTdGF0ZURhdGUgPSBNYXA8c3RyaW5nLCBTdGF0ZURhdGU+O1xyXG5cclxuY29uc3QgU1RPUkFHRV9OR1hfQ0hBVF9DT05UQUNUX01FU1NBR0VfU1RBVEVTID0gJ25neGNoYXQ6Y29udGFjdG1lc3NhZ2VzdGF0ZXMnO1xyXG5jb25zdCB3cmFwcGVyTm9kZU5hbWUgPSAnZW50cmllcyc7XHJcbmNvbnN0IG5vZGVOYW1lID0gJ2NvbnRhY3QtbWVzc2FnZS1zdGF0ZSc7XHJcblxyXG4vKipcclxuICogUGx1Z2luIHVzaW5nIFB1YlN1YiB0byBwZXJzaXN0IG1lc3NhZ2UgcmVhZCBzdGF0ZXMuXHJcbiAqIEN1c3RvbSBub3QgcGFydCBvZiB0aGUgWE1QUCBTcGVjaWZpY2F0aW9uXHJcbiAqIFN0YW5kYXJkaXplZCBpbXBsZW1lbnRhdGlvbiBzcGVjaWZpY2F0aW9uIHdvdWxkIGJlIGh0dHBzOi8veG1wcC5vcmcvZXh0ZW5zaW9ucy94ZXAtMDE4NC5odG1sXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgTWVzc2FnZVN0YXRlUGx1Z2luIGV4dGVuZHMgQWJzdHJhY3RYbXBwUGx1Z2luIHtcclxuXHJcbiAgICBwcml2YXRlIGppZFRvTWVzc2FnZVN0YXRlRGF0ZTogSmlkVG9NZXNzYWdlU3RhdGVEYXRlID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHB1Ymxpc2hTdWJzY3JpYmVQbHVnaW46IFB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSB4bXBwQ2hhdEFkYXB0ZXI6IFhtcHBDaGF0QWRhcHRlcixcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGNoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5OiBDaGF0TWVzc2FnZUxpc3RSZWdpc3RyeVNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBsb2dTZXJ2aWNlOiBMb2dTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgZW50aXR5VGltZVBsdWdpbjogRW50aXR5VGltZVBsdWdpbixcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKCk7XHJcblxyXG4gICAgICAgIHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkub3BlbkNoYXRzJFxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIGZpbHRlcigoKSA9PiB4bXBwQ2hhdEFkYXB0ZXIuc3RhdGUkLmdldFZhbHVlKCkgPT09ICdvbmxpbmUnKSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKGNvbnRhY3RzID0+IHtcclxuICAgICAgICAgICAgICAgIGNvbnRhY3RzLmZvckVhY2goYXN5bmMgY29udGFjdCA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnRhY3QubW9zdFJlY2VudE1lc3NhZ2VSZWNlaXZlZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRNZXNzYWdlU3RhdGVOb3RpZmljYXRpb24oXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250YWN0LmppZEJhcmUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250YWN0Lm1vc3RSZWNlbnRNZXNzYWdlUmVjZWl2ZWQuaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNZXNzYWdlU3RhdGUuUkVDSVBJRU5UX1NFRU4pO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5wdWJsaXNoU3Vic2NyaWJlUGx1Z2luLnB1Ymxpc2gkXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50KSA9PiB0aGlzLmhhbmRsZVB1YlN1YkV2ZW50KGV2ZW50KSk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgb25CZWZvcmVPbmxpbmUoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgdGhpcy5wYXJzZUNvbnRhY3RNZXNzYWdlU3RhdGVzKCkuY2F0Y2goZXJyID0+IHRoaXMubG9nU2VydmljZS5lcnJvcignZXJyb3IgcGFyc2luZyBjb250YWN0IG1lc3NhZ2Ugc3RhdGVzJywgZXJyKSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBhc3luYyBwYXJzZUNvbnRhY3RNZXNzYWdlU3RhdGVzKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIGNvbnN0IGl0ZW1FbGVtZW50cyA9IGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5yZXRyaWV2ZU5vZGVJdGVtcyhTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMpO1xyXG4gICAgICAgIHRoaXMucHJvY2Vzc1B1YlN1YihpdGVtRWxlbWVudHMpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgcHJvY2Vzc1B1YlN1YihpdGVtRWxlbWVudHM6IFN0YW56YVtdKTogdm9pZCB7XHJcbiAgICAgICAgbGV0IHJlc3VsdHMgPSBbXSBhcyBbc3RyaW5nLCBTdGF0ZURhdGVdW107XHJcbiAgICAgICAgaWYgKGl0ZW1FbGVtZW50cy5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgcmVzdWx0cyA9IGl0ZW1FbGVtZW50c1swXVxyXG4gICAgICAgICAgICAgICAgLmdldENoaWxkKHdyYXBwZXJOb2RlTmFtZSlcclxuICAgICAgICAgICAgICAgIC5nZXRDaGlsZHJlbihub2RlTmFtZSlcclxuICAgICAgICAgICAgICAgIC5tYXAoKGNvbnRhY3RNZXNzYWdlU3RhdGVFbGVtZW50OiBTdGFuemEpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCB7bGFzdFJlY2lwaWVudFJlY2VpdmVkLCBsYXN0UmVjaXBpZW50U2VlbiwgbGFzdFNlbnQsIGppZH0gPSBjb250YWN0TWVzc2FnZVN0YXRlRWxlbWVudC5hdHRycztcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBqaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RSZWNpcGllbnRTZWVuOiBuZXcgRGF0ZSgrbGFzdFJlY2lwaWVudFNlZW4gfHwgMCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0UmVjaXBpZW50UmVjZWl2ZWQ6IG5ldyBEYXRlKCtsYXN0UmVjaXBpZW50UmVjZWl2ZWQgfHwgMCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0U2VudDogbmV3IERhdGUoK2xhc3RTZW50IHx8IDApLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgXTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmppZFRvTWVzc2FnZVN0YXRlRGF0ZSA9IG5ldyBNYXAocmVzdWx0cyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBhc3luYyBwZXJzaXN0Q29udGFjdE1lc3NhZ2VTdGF0ZXMoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgY29uc3QgbWVzc2FnZVN0YXRlRWxlbWVudHMgPVxyXG4gICAgICAgICAgICBbLi4udGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuZW50cmllcygpXVxyXG4gICAgICAgICAgICAgICAgLm1hcCgoW2ppZCwgc3RhdGVEYXRlc10pID0+XHJcbiAgICAgICAgICAgICAgICAgICAgeG1sKG5vZGVOYW1lLCB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFJlY2VpdmVkOiBTdHJpbmcoc3RhdGVEYXRlcy5sYXN0UmVjaXBpZW50UmVjZWl2ZWQuZ2V0VGltZSgpKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFNlZW46IFN0cmluZyhzdGF0ZURhdGVzLmxhc3RSZWNpcGllbnRTZWVuLmdldFRpbWUoKSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RTZW50OiBTdHJpbmcoc3RhdGVEYXRlcy5sYXN0U2VudC5nZXRUaW1lKCkpLFxyXG4gICAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApO1xyXG5cclxuICAgICAgICBhd2FpdCB0aGlzLnB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4uc3RvcmVQcml2YXRlUGF5bG9hZFBlcnNpc3RlbnQoXHJcbiAgICAgICAgICAgIFNUT1JBR0VfTkdYX0NIQVRfQ09OVEFDVF9NRVNTQUdFX1NUQVRFUyxcclxuICAgICAgICAgICAgJ2N1cnJlbnQnLFxyXG4gICAgICAgICAgICB4bWwod3JhcHBlck5vZGVOYW1lLCB7fSwgbWVzc2FnZVN0YXRlRWxlbWVudHMpKTtcclxuICAgIH1cclxuXHJcbiAgICBvbk9mZmxpbmUoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuY2xlYXIoKTtcclxuICAgIH1cclxuXHJcbiAgICBiZWZvcmVTZW5kTWVzc2FnZShtZXNzYWdlU3RhbnphOiBFbGVtZW50LCBtZXNzYWdlOiBNZXNzYWdlKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3Qge3R5cGV9ID0gbWVzc2FnZVN0YW56YS5hdHRycztcclxuICAgICAgICBpZiAodHlwZSA9PT0gJ2NoYXQnICYmIG1lc3NhZ2UpIHtcclxuICAgICAgICAgICAgbWVzc2FnZS5zdGF0ZSA9IE1lc3NhZ2VTdGF0ZS5TRU5ESU5HO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBhZnRlclNlbmRNZXNzYWdlKG1lc3NhZ2U6IE1lc3NhZ2UsIG1lc3NhZ2VTdGFuemE6IEVsZW1lbnQpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBjb25zdCB7dHlwZSwgdG99ID0gbWVzc2FnZVN0YW56YS5hdHRycztcclxuICAgICAgICBpZiAodHlwZSA9PT0gJ2NoYXQnKSB7XHJcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQ29udGFjdE1lc3NhZ2VTdGF0ZShcclxuICAgICAgICAgICAgICAgIHBhcnNlSmlkKHRvKS5iYXJlKCkudG9TdHJpbmcoKSxcclxuICAgICAgICAgICAgICAgIE1lc3NhZ2VTdGF0ZS5TRU5ULFxyXG4gICAgICAgICAgICAgICAgbmV3IERhdGUoYXdhaXQgdGhpcy5lbnRpdHlUaW1lUGx1Z2luLmdldE5vdygpKSk7XHJcbiAgICAgICAgICAgIGRlbGV0ZSBtZXNzYWdlLnN0YXRlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBhZnRlclJlY2VpdmVNZXNzYWdlKG1lc3NhZ2VSZWNlaXZlZDogTWVzc2FnZSwgc3RhbnphOiBNZXNzYWdlV2l0aEJvZHlTdGFuemEsIG1lc3NhZ2VSZWNlaXZlZEV2ZW50OiBNZXNzYWdlUmVjZWl2ZWRFdmVudCk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2VTdGF0ZUVsZW1lbnQgPSBzdGFuemEuZ2V0Q2hpbGQoJ21lc3NhZ2Utc3RhdGUnLCBTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMpO1xyXG4gICAgICAgIGlmIChtZXNzYWdlU3RhdGVFbGVtZW50KSB7XHJcbiAgICAgICAgICAgIC8vIHdlIHJlY2VpdmVkIGEgbWVzc2FnZSBzdGF0ZSBvciBhIG1lc3NhZ2UgdmlhIGNhcmJvbiBmcm9tIGFub3RoZXIgcmVzb3VyY2UsIGRpc2NhcmQgaXRcclxuICAgICAgICAgICAgbWVzc2FnZVJlY2VpdmVkRXZlbnQuZGlzY2FyZCA9IHRydWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChtZXNzYWdlUmVjZWl2ZWQuZGlyZWN0aW9uID09PSBEaXJlY3Rpb24uaW4gJiYgIW1lc3NhZ2VSZWNlaXZlZC5mcm9tQXJjaGl2ZSAmJiBzdGFuemEuYXR0cnMudHlwZSAhPT0gJ2dyb3VwY2hhdCcpIHtcclxuICAgICAgICAgICAgdGhpcy5hY2tub3dsZWRnZVJlY2VpdmVkTWVzc2FnZShzdGFuemEpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGFja25vd2xlZGdlUmVjZWl2ZWRNZXNzYWdlKHN0YW56YTogTWVzc2FnZVdpdGhCb2R5U3RhbnphKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3Qge2Zyb219ID0gc3RhbnphLmF0dHJzO1xyXG4gICAgICAgIGNvbnN0IGlzQ2hhdFdpdGhDb250YWN0T3BlbiA9IHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuaXNDaGF0T3Blbih0aGlzLnhtcHBDaGF0QWRhcHRlci5nZXRPckNyZWF0ZUNvbnRhY3RCeUlkKGZyb20pKTtcclxuICAgICAgICBjb25zdCBzdGF0ZSA9IGlzQ2hhdFdpdGhDb250YWN0T3BlbiA/IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfU0VFTiA6IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfUkVDRUlWRUQ7XHJcbiAgICAgICAgY29uc3QgbWVzc2FnZUlkID0gTWVzc2FnZVV1aWRQbHVnaW4uZXh0cmFjdElkRnJvbVN0YW56YShzdGFuemEpO1xyXG4gICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VTdGF0ZU5vdGlmaWNhdGlvbihwYXJzZUppZChmcm9tKSwgbWVzc2FnZUlkLCBzdGF0ZSkuY2F0Y2goZSA9PiB0aGlzLmxvZ1NlcnZpY2UuZXJyb3IoJ2Vycm9yIHNlbmRpbmcgc3RhdGUgbm90aWZpY2F0aW9uJywgZSkpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgc2VuZE1lc3NhZ2VTdGF0ZU5vdGlmaWNhdGlvbihyZWNpcGllbnQ6IEpJRCwgbWVzc2FnZUlkOiBzdHJpbmcsIHN0YXRlOiBNZXNzYWdlU3RhdGUpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBjb25zdCBtZXNzYWdlU3RhdGVSZXNwb25zZSA9IHhtbCgnbWVzc2FnZScsIHtcclxuICAgICAgICAgICAgICAgIHRvOiByZWNpcGllbnQuYmFyZSgpLnRvU3RyaW5nKCksXHJcbiAgICAgICAgICAgICAgICBmcm9tOiB0aGlzLnhtcHBDaGF0QWRhcHRlci5jaGF0Q29ubmVjdGlvblNlcnZpY2UudXNlckppZC50b1N0cmluZygpLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogJ2NoYXQnXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHhtbCgnbWVzc2FnZS1zdGF0ZScsIHtcclxuICAgICAgICAgICAgICAgIHhtbG5zOiBTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMsXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlSWQsXHJcbiAgICAgICAgICAgICAgICBkYXRlOiBuZXcgRGF0ZShhd2FpdCB0aGlzLmVudGl0eVRpbWVQbHVnaW4uZ2V0Tm93KCkpLnRvSVNPU3RyaW5nKCksXHJcbiAgICAgICAgICAgICAgICBzdGF0ZVxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYXdhaXQgdGhpcy54bXBwQ2hhdEFkYXB0ZXIuY2hhdENvbm5lY3Rpb25TZXJ2aWNlLnNlbmQobWVzc2FnZVN0YXRlUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGhhbmRsZVN0YW56YShzdGFuemE6IFN0YW56YSk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGNvbnN0IHt0eXBlLCBmcm9tfSA9IHN0YW56YS5hdHRycztcclxuICAgICAgICBjb25zdCBzdGF0ZUVsZW1lbnQgPSBzdGFuemEuZ2V0Q2hpbGQoJ21lc3NhZ2Utc3RhdGUnLCBTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMpO1xyXG4gICAgICAgIGlmICh0eXBlID09PSAnY2hhdCcgJiYgc3RhdGVFbGVtZW50KSB7XHJcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlU3RhdGVOb3RpZmljYXRpb25TdGFuemEoc3RhdGVFbGVtZW50LCBmcm9tKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGhhbmRsZVN0YXRlTm90aWZpY2F0aW9uU3RhbnphKHN0YXRlRWxlbWVudDogRWxlbWVudCwgZnJvbTogc3RyaW5nKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3Qge3N0YXRlLCBkYXRlfSA9IHN0YXRlRWxlbWVudC5hdHRycztcclxuICAgICAgICBjb25zdCBjb250YWN0ID0gdGhpcy54bXBwQ2hhdEFkYXB0ZXIuZ2V0T3JDcmVhdGVDb250YWN0QnlJZChmcm9tKTtcclxuICAgICAgICBjb25zdCBzdGF0ZURhdGUgPSBuZXcgRGF0ZShkYXRlKTtcclxuICAgICAgICB0aGlzLnVwZGF0ZUNvbnRhY3RNZXNzYWdlU3RhdGUoY29udGFjdC5qaWRCYXJlLnRvU3RyaW5nKCksIHN0YXRlLCBzdGF0ZURhdGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgdXBkYXRlQ29udGFjdE1lc3NhZ2VTdGF0ZShjb250YWN0SmlkOiBzdHJpbmcsIHN0YXRlOiBNZXNzYWdlU3RhdGUsIHN0YXRlRGF0ZTogRGF0ZSk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLmdldENvbnRhY3RNZXNzYWdlU3RhdGUoY29udGFjdEppZCk7XHJcbiAgICAgICAgbGV0IGNoYW5nZWQgPSBmYWxzZTtcclxuICAgICAgICBpZiAoc3RhdGUgPT09IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfUkVDRUlWRUQgJiYgY3VycmVudC5sYXN0UmVjaXBpZW50UmVjZWl2ZWQgPCBzdGF0ZURhdGUpIHtcclxuICAgICAgICAgICAgY3VycmVudC5sYXN0UmVjaXBpZW50UmVjZWl2ZWQgPSBzdGF0ZURhdGU7XHJcbiAgICAgICAgICAgIGNoYW5nZWQgPSB0cnVlO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoc3RhdGUgPT09IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfU0VFTiAmJiBjdXJyZW50Lmxhc3RSZWNpcGllbnRTZWVuIDwgc3RhdGVEYXRlKSB7XHJcbiAgICAgICAgICAgIGN1cnJlbnQubGFzdFJlY2lwaWVudFJlY2VpdmVkID0gc3RhdGVEYXRlO1xyXG4gICAgICAgICAgICBjdXJyZW50Lmxhc3RSZWNpcGllbnRTZWVuID0gc3RhdGVEYXRlO1xyXG4gICAgICAgICAgICBjaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgICB9IGVsc2UgaWYgKHN0YXRlID09PSBNZXNzYWdlU3RhdGUuU0VOVCAmJiBjdXJyZW50Lmxhc3RTZW50IDwgc3RhdGVEYXRlKSB7XHJcbiAgICAgICAgICAgIGN1cnJlbnQubGFzdFNlbnQgPSBzdGF0ZURhdGU7XHJcbiAgICAgICAgICAgIGNoYW5nZWQgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoY2hhbmdlZCkge1xyXG4gICAgICAgICAgICB0aGlzLnBlcnNpc3RDb250YWN0TWVzc2FnZVN0YXRlcygpLmNhdGNoKGVyciA9PiB0aGlzLmxvZ1NlcnZpY2UuZXJyb3IoJ2Vycm9yIHBlcnNpc3RpbmcgY29udGFjdCBtZXNzYWdlIHN0YXRlcycsIGVycikpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q29udGFjdE1lc3NhZ2VTdGF0ZShjb250YWN0SmlkOiBzdHJpbmcpOiBTdGF0ZURhdGUgfCB1bmRlZmluZWQge1xyXG4gICAgICAgIGlmICghdGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuaGFzKGNvbnRhY3RKaWQpKSB7XHJcbiAgICAgICAgICAgIHRoaXMuamlkVG9NZXNzYWdlU3RhdGVEYXRlLnNldChcclxuICAgICAgICAgICAgICAgIGNvbnRhY3RKaWQsXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFJlY2VpdmVkOiBuZXcgRGF0ZSgwKSxcclxuICAgICAgICAgICAgICAgICAgICBsYXN0UmVjaXBpZW50U2VlbjogbmV3IERhdGUoMCksXHJcbiAgICAgICAgICAgICAgICAgICAgbGFzdFNlbnQ6IG5ldyBEYXRlKDApLFxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuZ2V0KGNvbnRhY3RKaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaGFuZGxlUHViU3ViRXZlbnQoZXZlbnQ6IFN0YW56YSk6IHZvaWQge1xyXG4gICAgICAgIGNvbnN0IGl0ZW1zOiBTdGFuemEgfCB1bmRlZmluZWQgPSBldmVudC5nZXRDaGlsZCgnaXRlbXMnKTtcclxuICAgICAgICBjb25zdCBpdGVtc05vZGUgPSBpdGVtcz8uYXR0cnMubm9kZTtcclxuICAgICAgICBjb25zdCBpdGVtRWxlbWVudHM6IFN0YW56YVtdIHwgdW5kZWZpbmVkID0gaXRlbXM/LmdldENoaWxkcmVuKCdpdGVtJyk7XHJcbiAgICAgICAgaWYgKGl0ZW1zTm9kZSA9PT0gU1RPUkFHRV9OR1hfQ0hBVF9DT05UQUNUX01FU1NBR0VfU1RBVEVTICYmIGl0ZW1FbGVtZW50cykge1xyXG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NQdWJTdWIoaXRlbUVsZW1lbnRzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuIl19