@pazznetwork/ngx-chat
Version:
[](https://travis-ci.com/pazznetwork/ngx-chat) [](https://coveralls.io/github/pazzn
172 lines • 30.8 kB
JavaScript
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