UNPKG

@pazznetwork/ngx-chat

Version:

[![Build status](https://api.travis-ci.com/pazznetwork/ngx-chat.svg?branch=master)](https://travis-ci.com/pazznetwork/ngx-chat) [![Coverage](https://coveralls.io/repos/github/pazznetwork/ngx-chat/badge.svg?branch=master)](https://coveralls.io/github/pazzn

172 lines 30.8 kB
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 = new Map(); this.chatMessageListRegistry.openChats$ .pipe(filter(() => xmppChatAdapter.state$.getValue() === 'online')) .subscribe(contacts => { contacts.forEach(async (contact) => { if (contact.mostRecentMessageReceived) { await this.sendMessageStateNotification(contact.jidBare, contact.mostRecentMessageReceived.id, MessageState.RECIPIENT_SEEN); } }); }); this.publishSubscribePlugin.publish$ .subscribe((event) => this.handlePubSubEvent(event)); } async onBeforeOnline() { this.parseContactMessageStates().catch(err => this.logService.error('error parsing contact message states', err)); } async parseContactMessageStates() { const itemElements = await 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); } async persistContactMessageStates() { 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()), })); await 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; } } async afterSendMessage(message, messageStanza) { const { type, to } = messageStanza.attrs; if (type === 'chat') { this.updateContactMessageState(parseJid(to).bare().toString(), MessageState.SENT, new Date(await 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)); } async sendMessageStateNotification(recipient, messageId, state) { 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(await this.entityTimePlugin.getNow()).toISOString(), state })); await 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?.attrs.node; const itemElements = items?.getChildren('item'); if (itemsNode === STORAGE_NGX_CHAT_CONTACT_MESSAGE_STATES && itemElements) { this.processPubSub(itemElements); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1zdGF0ZS5wbHVnaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2FkYXB0ZXJzL3htcHAvcGx1Z2lucy9tZXNzYWdlLXN0YXRlLnBsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsR0FBRyxJQUFJLFFBQVEsRUFBRSxHQUFHLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFHbEQsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3RDLE9BQU8sRUFBQyxTQUFTLEVBQVcsWUFBWSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFLMUUsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFFMUQsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFZeEQsTUFBTSx1Q0FBdUMsR0FBRyw4QkFBOEIsQ0FBQztBQUMvRSxNQUFNLGVBQWUsR0FBRyxTQUFTLENBQUM7QUFDbEMsTUFBTSxRQUFRLEdBQUcsdUJBQXVCLENBQUM7QUFFekM7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxrQkFBbUIsU0FBUSxrQkFBa0I7SUFJdEQsWUFDcUIsc0JBQThDLEVBQzlDLGVBQWdDLEVBQ2hDLHVCQUF1RCxFQUN2RCxVQUFzQixFQUN0QixnQkFBa0M7UUFFbkQsS0FBSyxFQUFFLENBQUM7UUFOUywyQkFBc0IsR0FBdEIsc0JBQXNCLENBQXdCO1FBQzlDLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNoQyw0QkFBdUIsR0FBdkIsdUJBQXVCLENBQWdDO1FBQ3ZELGVBQVUsR0FBVixVQUFVLENBQVk7UUFDdEIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQVAvQywwQkFBcUIsR0FBMEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQVc3RCxJQUFJLENBQUMsdUJBQXVCLENBQUMsVUFBVTthQUNsQyxJQUFJ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QzdDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQzFCLFVBQVUsRUFDVjtnQkFDSSxxQkFBcUIsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ2xDLGlCQUFpQixFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDOUIsUUFBUSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQzthQUN4QixDQUNKLENBQUM7U0FDTDtRQUNELE9BQU8sSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRU8saUJBQWlCLENBQUMsS0FBYztRQUNwQyxNQUFNLEtBQUssR0FBd0IsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzRCxNQUFNLFNBQVMsR0FBRyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQztRQUNwQyxNQUFNLFlBQVksR0FBMEIsS0FBSyxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2RSxJQUFJLFNBQVMsS0FBSyx1Q0FBdUMsSUFBSSxZQUFZLEVBQUU7WUFDdkUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUNwQztJQUNMLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7amlkIGFzIHBhcnNlSmlkLCB4bWx9IGZyb20gJ0B4bXBwL2NsaWVudCc7XG5pbXBvcnQge0pJRH0gZnJvbSAnQHhtcHAvamlkJztcbmltcG9ydCB7RWxlbWVudH0gZnJvbSAnbHR4JztcbmltcG9ydCB7ZmlsdGVyfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge0RpcmVjdGlvbiwgTWVzc2FnZSwgTWVzc2FnZVN0YXRlfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL21lc3NhZ2UnO1xuaW1wb3J0IHtNZXNzYWdlV2l0aEJvZHlTdGFuemEsIFN0YW56YX0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9zdGFuemEnO1xuaW1wb3J0IHtDaGF0TWVzc2FnZUxpc3RSZWdpc3RyeVNlcnZpY2V9IGZyb20gJy4uLy4uLy4uL2NoYXQtbWVzc2FnZS1saXN0LXJlZ2lzdHJ5LnNlcnZpY2UnO1xuaW1wb3J0IHtMb2dTZXJ2aWNlfSBmcm9tICcuLi8uLi8uLi9sb2cuc2VydmljZSc7XG5pbXBvcnQge1htcHBDaGF0QWRhcHRlcn0gZnJvbSAnLi4veG1wcC1jaGF0LWFkYXB0ZXIuc2VydmljZSc7XG5pbXBvcnQge0Fic3RyYWN0WG1wcFBsdWdpbn0gZnJvbSAnLi9hYnN0cmFjdC14bXBwLXBsdWdpbic7XG5pbXBvcnQge0VudGl0eVRpbWVQbHVnaW59IGZyb20gJy4vZW50aXR5LXRpbWUucGx1Z2luJztcbmltcG9ydCB7TWVzc2FnZVV1aWRQbHVnaW59IGZyb20gJy4vbWVzc2FnZS11dWlkLnBsdWdpbic7XG5pbXBvcnQge01lc3NhZ2VSZWNlaXZlZEV2ZW50fSBmcm9tICcuL21lc3NhZ2UucGx1Z2luJztcbmltcG9ydCB7UHVibGlzaFN1YnNjcmliZVBsdWdpbn0gZnJvbSAnLi9wdWJsaXNoLXN1YnNjcmliZS5wbHVnaW4nO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRlRGF0ZSB7XG4gICAgbGFzdFJlY2lwaWVudFJlY2VpdmVkOiBEYXRlO1xuICAgIGxhc3RSZWNpcGllbnRTZWVuOiBEYXRlO1xuICAgIGxhc3RTZW50OiBEYXRlO1xufVxuXG5leHBvcnQgdHlwZSBKaWRUb01lc3NhZ2VTdGF0ZURhdGUgPSBNYXA8c3RyaW5nLCBTdGF0ZURhdGU+O1xuXG5jb25zdCBTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMgPSAnbmd4Y2hhdDpjb250YWN0bWVzc2FnZXN0YXRlcyc7XG5jb25zdCB3cmFwcGVyTm9kZU5hbWUgPSAnZW50cmllcyc7XG5jb25zdCBub2RlTmFtZSA9ICdjb250YWN0LW1lc3NhZ2Utc3RhdGUnO1xuXG4vKipcbiAqIFBsdWdpbiB1c2luZyBQdWJTdWIgdG8gcGVyc2lzdCBtZXNzYWdlIHJlYWQgc3RhdGVzLlxuICogQ3VzdG9tIG5vdCBwYXJ0IG9mIHRoZSBYTVBQIFNwZWNpZmljYXRpb25cbiAqIFN0YW5kYXJkaXplZCBpbXBsZW1lbnRhdGlvbiBzcGVjaWZpY2F0aW9uIHdvdWxkIGJlIGh0dHBzOi8veG1wcC5vcmcvZXh0ZW5zaW9ucy94ZXAtMDE4NC5odG1sXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlU3RhdGVQbHVnaW4gZXh0ZW5kcyBBYnN0cmFjdFhtcHBQbHVnaW4ge1xuXG4gICAgcHJpdmF0ZSBqaWRUb01lc3NhZ2VTdGF0ZURhdGU6IEppZFRvTWVzc2FnZVN0YXRlRGF0ZSA9IG5ldyBNYXAoKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHB1Ymxpc2hTdWJzY3JpYmVQbHVnaW46IFB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4sXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgeG1wcENoYXRBZGFwdGVyOiBYbXBwQ2hhdEFkYXB0ZXIsXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnk6IENoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5U2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBsb2dTZXJ2aWNlOiBMb2dTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGVudGl0eVRpbWVQbHVnaW46IEVudGl0eVRpbWVQbHVnaW4sXG4gICAgKSB7XG4gICAgICAgIHN1cGVyKCk7XG5cbiAgICAgICAgdGhpcy5jaGF0TWVzc2FnZUxpc3RSZWdpc3RyeS5vcGVuQ2hhdHMkXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBmaWx0ZXIoKCkgPT4geG1wcENoYXRBZGFwdGVyLnN0YXRlJC5nZXRWYWx1ZSgpID09PSAnb25saW5lJyksXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKGNvbnRhY3RzID0+IHtcbiAgICAgICAgICAgICAgICBjb250YWN0cy5mb3JFYWNoKGFzeW5jIGNvbnRhY3QgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY29udGFjdC5tb3N0UmVjZW50TWVzc2FnZVJlY2VpdmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRNZXNzYWdlU3RhdGVOb3RpZmljYXRpb24oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGFjdC5qaWRCYXJlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhY3QubW9zdFJlY2VudE1lc3NhZ2VSZWNlaXZlZC5pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNZXNzYWdlU3RhdGUuUkVDSVBJRU5UX1NFRU4pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4ucHVibGlzaCRcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50KSA9PiB0aGlzLmhhbmRsZVB1YlN1YkV2ZW50KGV2ZW50IGFzIFN0YW56YSkpO1xuICAgIH1cblxuICAgIGFzeW5jIG9uQmVmb3JlT25saW5lKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLnBhcnNlQ29udGFjdE1lc3NhZ2VTdGF0ZXMoKS5jYXRjaChlcnIgPT4gdGhpcy5sb2dTZXJ2aWNlLmVycm9yKCdlcnJvciBwYXJzaW5nIGNvbnRhY3QgbWVzc2FnZSBzdGF0ZXMnLCBlcnIpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHBhcnNlQ29udGFjdE1lc3NhZ2VTdGF0ZXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGl0ZW1FbGVtZW50cyA9IGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5yZXRyaWV2ZU5vZGVJdGVtcyhTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMpO1xuICAgICAgICB0aGlzLnByb2Nlc3NQdWJTdWIoaXRlbUVsZW1lbnRzKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHByb2Nlc3NQdWJTdWIoaXRlbUVsZW1lbnRzOiBFbGVtZW50W10pOiB2b2lkIHtcbiAgICAgICAgbGV0IHJlc3VsdHMgPSBbXSBhcyBbc3RyaW5nLCBTdGF0ZURhdGVdW107XG4gICAgICAgIGlmIChpdGVtRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICByZXN1bHRzID0gaXRlbUVsZW1lbnRzWzBdXG4gICAgICAgICAgICAgICAgLmdldENoaWxkKHdyYXBwZXJOb2RlTmFtZSlcbiAgICAgICAgICAgICAgICAuZ2V0Q2hpbGRyZW4obm9kZU5hbWUpXG4gICAgICAgICAgICAgICAgLm1hcCgoY29udGFjdE1lc3NhZ2VTdGF0ZUVsZW1lbnQ6IFN0YW56YSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB7bGFzdFJlY2lwaWVudFJlY2VpdmVkLCBsYXN0UmVjaXBpZW50U2VlbiwgbGFzdFNlbnQsIGppZH0gPSBjb250YWN0TWVzc2FnZVN0YXRlRWxlbWVudC5hdHRycztcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0UmVjaXBpZW50U2VlbjogbmV3IERhdGUoK2xhc3RSZWNpcGllbnRTZWVuIHx8IDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RSZWNpcGllbnRSZWNlaXZlZDogbmV3IERhdGUoK2xhc3RSZWNpcGllbnRSZWNlaXZlZCB8fCAwKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0U2VudDogbmV3IERhdGUoK2xhc3RTZW50IHx8IDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuamlkVG9NZXNzYWdlU3RhdGVEYXRlID0gbmV3IE1hcChyZXN1bHRzKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHBlcnNpc3RDb250YWN0TWVzc2FnZVN0YXRlcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgbWVzc2FnZVN0YXRlRWxlbWVudHMgPVxuICAgICAgICAgICAgWy4uLnRoaXMuamlkVG9NZXNzYWdlU3RhdGVEYXRlLmVudHJpZXMoKV1cbiAgICAgICAgICAgICAgICAubWFwKChbamlkLCBzdGF0ZURhdGVzXSkgPT5cbiAgICAgICAgICAgICAgICAgICAgeG1sKG5vZGVOYW1lLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBqaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXN0UmVjaXBpZW50UmVjZWl2ZWQ6IFN0cmluZyhzdGF0ZURhdGVzLmxhc3RSZWNpcGllbnRSZWNlaXZlZC5nZXRUaW1lKCkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFNlZW46IFN0cmluZyhzdGF0ZURhdGVzLmxhc3RSZWNpcGllbnRTZWVuLmdldFRpbWUoKSksXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXN0U2VudDogU3RyaW5nKHN0YXRlRGF0ZXMubGFzdFNlbnQuZ2V0VGltZSgpKSxcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgIGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5zdG9yZVByaXZhdGVQYXlsb2FkUGVyc2lzdGVudChcbiAgICAgICAgICAgIFNUT1JBR0VfTkdYX0NIQVRfQ09OVEFDVF9NRVNTQUdFX1NUQVRFUyxcbiAgICAgICAgICAgICdjdXJyZW50JyxcbiAgICAgICAgICAgIHhtbCh3cmFwcGVyTm9kZU5hbWUsIHt9LCAuLi5tZXNzYWdlU3RhdGVFbGVtZW50cykpO1xuICAgIH1cblxuICAgIG9uT2ZmbGluZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuY2xlYXIoKTtcbiAgICB9XG5cbiAgICBiZWZvcmVTZW5kTWVzc2FnZShtZXNzYWdlU3RhbnphOiBFbGVtZW50LCBtZXNzYWdlOiBNZXNzYWdlKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHt0eXBlfSA9IG1lc3NhZ2VTdGFuemEuYXR0cnM7XG4gICAgICAgIGlmICh0eXBlID09PSAnY2hhdCcgJiYgbWVzc2FnZSkge1xuICAgICAgICAgICAgbWVzc2FnZS5zdGF0ZSA9IE1lc3NhZ2VTdGF0ZS5TRU5ESU5HO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgYWZ0ZXJTZW5kTWVzc2FnZShtZXNzYWdlOiBNZXNzYWdlLCBtZXNzYWdlU3RhbnphOiBFbGVtZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHt0eXBlLCB0b30gPSBtZXNzYWdlU3RhbnphLmF0dHJzO1xuICAgICAgICBpZiAodHlwZSA9PT0gJ2NoYXQnKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUNvbnRhY3RNZXNzYWdlU3RhdGUoXG4gICAgICAgICAgICAgICAgcGFyc2VKaWQodG8pLmJhcmUoKS50b1N0cmluZygpLFxuICAgICAgICAgICAgICAgIE1lc3NhZ2VTdGF0ZS5TRU5ULFxuICAgICAgICAgICAgICAgIG5ldyBEYXRlKGF3YWl0IHRoaXMuZW50aXR5VGltZVBsdWdpbi5nZXROb3coKSkpO1xuICAgICAgICAgICAgZGVsZXRlIG1lc3NhZ2Uuc3RhdGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhZnRlclJlY2VpdmVNZXNzYWdlKG1lc3NhZ2VSZWNlaXZlZDogTWVzc2FnZSwgc3RhbnphOiBNZXNzYWdlV2l0aEJvZHlTdGFuemEsIG1lc3NhZ2VSZWNlaXZlZEV2ZW50OiBNZXNzYWdlUmVjZWl2ZWRFdmVudCk6IHZvaWQge1xuICAgICAgICBjb25zdCBtZXNzYWdlU3RhdGVFbGVtZW50ID0gc3RhbnphLmdldENoaWxkKCdtZXNzYWdlLXN0YXRlJywgU1RPUkFHRV9OR1hfQ0hBVF9DT05UQUNUX01FU1NBR0VfU1RBVEVTKTtcbiAgICAgICAgaWYgKG1lc3NhZ2VTdGF0ZUVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIHdlIHJlY2VpdmVkIGEgbWVzc2FnZSBzdGF0ZSBvciBhIG1lc3NhZ2UgdmlhIGNhcmJvbiBmcm9tIGFub3RoZXIgcmVzb3VyY2UsIGRpc2NhcmQgaXRcbiAgICAgICAgICAgIG1lc3NhZ2VSZWNlaXZlZEV2ZW50LmRpc2NhcmQgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2VSZWNlaXZlZC5kaXJlY3Rpb24gPT09IERpcmVjdGlvbi5pbiAmJiAhbWVzc2FnZVJlY2VpdmVkLmZyb21BcmNoaXZlICYmIHN0YW56YS5hdHRycy50eXBlICE9PSAnZ3JvdXBjaGF0Jykge1xuICAgICAgICAgICAgdGhpcy5hY2tub3dsZWRnZVJlY2VpdmVkTWVzc2FnZShzdGFuemEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhY2tub3dsZWRnZVJlY2VpdmVkTWVzc2FnZShzdGFuemE6IE1lc3NhZ2VXaXRoQm9keVN0YW56YSk6IHZvaWQge1xuICAgICAgICBjb25zdCB7ZnJvbX0gPSBzdGFuemEuYXR0cnM7XG4gICAgICAgIGNvbnN0IGlzQ2hhdFdpdGhDb250YWN0T3BlbiA9IHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuaXNDaGF0T3Blbih0aGlzLnhtcHBDaGF0QWRhcHRlci5nZXRPckNyZWF0ZUNvbnRhY3RCeUlkKGZyb20pKTtcbiAgICAgICAgY29uc3Qgc3RhdGUgPSBpc0NoYXRXaXRoQ29udGFjdE9wZW4gPyBNZXNzYWdlU3RhdGUuUkVDSVBJRU5UX1NFRU4gOiBNZXNzYWdlU3RhdGUuUkVDSVBJRU5UX1JFQ0VJVkVEO1xuICAgICAgICBjb25zdCBtZXNzYWdlSWQgPSBNZXNzYWdlVXVpZFBsdWdpbi5leHRyYWN0SWRGcm9tU3RhbnphKHN0YW56YSk7XG4gICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VTdGF0ZU5vdGlmaWNhdGlvbihwYXJzZUppZChmcm9tKSwgbWVzc2FnZUlkLCBzdGF0ZSkuY2F0Y2goZSA9PiB0aGlzLmxvZ1NlcnZpY2UuZXJyb3IoJ2Vycm9yIHNlbmRpbmcgc3RhdGUgbm90aWZpY2F0aW9uJywgZSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgc2VuZE1lc3NhZ2VTdGF0ZU5vdGlmaWNhdGlvbihyZWNpcGllbnQ6IEpJRCwgbWVzc2FnZUlkOiBzdHJpbmcsIHN0YXRlOiBNZXNzYWdlU3RhdGUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgbWVzc2FnZVN0YXRlUmVzcG9uc2UgPSB4bWwoJ21lc3NhZ2UnLCB7XG4gICAgICAgICAgICAgICAgdG86IHJlY2lwaWVudC5iYXJlKCkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgICAgICBmcm9tOiB0aGlzLnhtcHBDaGF0QWRhcHRlci5jaGF0Q29ubmVjdGlvblNlcnZpY2UudXNlckppZC50b1N0cmluZygpLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdjaGF0J1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHhtbCgnbWVzc2FnZS1zdGF0ZScsIHtcbiAgICAgICAgICAgICAgICB4bWxuczogU1RPUkFHRV9OR1hfQ0hBVF9DT05UQUNUX01FU1NBR0VfU1RBVEVTLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2VJZCxcbiAgICAgICAgICAgICAgICBkYXRlOiBuZXcgRGF0ZShhd2FpdCB0aGlzLmVudGl0eVRpbWVQbHVnaW4uZ2V0Tm93KCkpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgICAgICAgICAgc3RhdGVcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IHRoaXMueG1wcENoYXRBZGFwdGVyLmNoYXRDb25uZWN0aW9uU2VydmljZS5zZW5kKG1lc3NhZ2VTdGF0ZVJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICBoYW5kbGVTdGFuemEoc3RhbnphOiBTdGFuemEpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3Qge3R5cGUsIGZyb219ID0gc3RhbnphLmF0dHJzO1xuICAgICAgICBjb25zdCBzdGF0ZUVsZW1lbnQgPSBzdGFuemEuZ2V0Q2hpbGQoJ21lc3NhZ2Utc3RhdGUnLCBTVE9SQUdFX05HWF9DSEFUX0NPTlRBQ1RfTUVTU0FHRV9TVEFURVMpO1xuICAgICAgICBpZiAodHlwZSA9PT0gJ2NoYXQnICYmIHN0YXRlRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVTdGF0ZU5vdGlmaWNhdGlvblN0YW56YShzdGF0ZUVsZW1lbnQsIGZyb20pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFuZGxlU3RhdGVOb3RpZmljYXRpb25TdGFuemEoc3RhdGVFbGVtZW50OiBFbGVtZW50LCBmcm9tOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qge3N0YXRlLCBkYXRlfSA9IHN0YXRlRWxlbWVudC5hdHRycztcbiAgICAgICAgY29uc3QgY29udGFjdCA9IHRoaXMueG1wcENoYXRBZGFwdGVyLmdldE9yQ3JlYXRlQ29udGFjdEJ5SWQoZnJvbSk7XG4gICAgICAgIGNvbnN0IHN0YXRlRGF0ZSA9IG5ldyBEYXRlKGRhdGUpO1xuICAgICAgICB0aGlzLnVwZGF0ZUNvbnRhY3RNZXNzYWdlU3RhdGUoY29udGFjdC5qaWRCYXJlLnRvU3RyaW5nKCksIHN0YXRlLCBzdGF0ZURhdGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlQ29udGFjdE1lc3NhZ2VTdGF0ZShjb250YWN0SmlkOiBzdHJpbmcsIHN0YXRlOiBNZXNzYWdlU3RhdGUsIHN0YXRlRGF0ZTogRGF0ZSk6IHZvaWQge1xuICAgICAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5nZXRDb250YWN0TWVzc2FnZVN0YXRlKGNvbnRhY3RKaWQpO1xuICAgICAgICBsZXQgY2hhbmdlZCA9IGZhbHNlO1xuICAgICAgICBpZiAoc3RhdGUgPT09IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfUkVDRUlWRUQgJiYgY3VycmVudC5sYXN0UmVjaXBpZW50UmVjZWl2ZWQgPCBzdGF0ZURhdGUpIHtcbiAgICAgICAgICAgIGN1cnJlbnQubGFzdFJlY2lwaWVudFJlY2VpdmVkID0gc3RhdGVEYXRlO1xuICAgICAgICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAoc3RhdGUgPT09IE1lc3NhZ2VTdGF0ZS5SRUNJUElFTlRfU0VFTiAmJiBjdXJyZW50Lmxhc3RSZWNpcGllbnRTZWVuIDwgc3RhdGVEYXRlKSB7XG4gICAgICAgICAgICBjdXJyZW50Lmxhc3RSZWNpcGllbnRSZWNlaXZlZCA9IHN0YXRlRGF0ZTtcbiAgICAgICAgICAgIGN1cnJlbnQubGFzdFJlY2lwaWVudFNlZW4gPSBzdGF0ZURhdGU7XG4gICAgICAgICAgICBjaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIGlmIChzdGF0ZSA9PT0gTWVzc2FnZVN0YXRlLlNFTlQgJiYgY3VycmVudC5sYXN0U2VudCA8IHN0YXRlRGF0ZSkge1xuICAgICAgICAgICAgY3VycmVudC5sYXN0U2VudCA9IHN0YXRlRGF0ZTtcbiAgICAgICAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VkKSB7XG4gICAgICAgICAgICB0aGlzLnBlcnNpc3RDb250YWN0TWVzc2FnZVN0YXRlcygpLmNhdGNoKGVyciA9PiB0aGlzLmxvZ1NlcnZpY2UuZXJyb3IoJ2Vycm9yIHBlcnNpc3RpbmcgY29udGFjdCBtZXNzYWdlIHN0YXRlcycsIGVycikpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGdldENvbnRhY3RNZXNzYWdlU3RhdGUoY29udGFjdEppZDogc3RyaW5nKTogU3RhdGVEYXRlIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgaWYgKCF0aGlzLmppZFRvTWVzc2FnZVN0YXRlRGF0ZS5oYXMoY29udGFjdEppZCkpIHtcbiAgICAgICAgICAgIHRoaXMuamlkVG9NZXNzYWdlU3RhdGVEYXRlLnNldChcbiAgICAgICAgICAgICAgICBjb250YWN0SmlkLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFJlY2VpdmVkOiBuZXcgRGF0ZSgwKSxcbiAgICAgICAgICAgICAgICAgICAgbGFzdFJlY2lwaWVudFNlZW46IG5ldyBEYXRlKDApLFxuICAgICAgICAgICAgICAgICAgICBsYXN0U2VudDogbmV3IERhdGUoMCksXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5qaWRUb01lc3NhZ2VTdGF0ZURhdGUuZ2V0KGNvbnRhY3RKaWQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaGFuZGxlUHViU3ViRXZlbnQoZXZlbnQ6IEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaXRlbXM6IEVsZW1lbnQgfCB1bmRlZmluZWQgPSBldmVudC5nZXRDaGlsZCgnaXRlbXMnKTtcbiAgICAgICAgY29uc3QgaXRlbXNOb2RlID0gaXRlbXM/LmF0dHJzLm5vZGU7XG4gICAgICAgIGNvbnN0IGl0ZW1FbGVtZW50czogRWxlbWVudFtdIHwgdW5kZWZpbmVkID0gaXRlbXM/LmdldENoaWxkcmVuKCdpdGVtJyk7XG4gICAgICAgIGlmIChpdGVtc05vZGUgPT09IFNUT1JBR0VfTkdYX0NIQVRfQ09OVEFDVF9NRVNTQUdFX1NUQVRFUyAmJiBpdGVtRWxlbWVudHMpIHtcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc1B1YlN1YihpdGVtRWxlbWVudHMpO1xuICAgICAgICB9XG4gICAgfVxufVxuIl19