Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/jsxc/jsxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormightymop <totzkotz@gmail.com>2022-02-26 22:28:42 +0300
committermightymop <totzkotz@gmail.com>2022-02-27 05:50:58 +0300
commit1592fd1306c55b403b023c22b53c7439be51e8c4 (patch)
tree57b49131b2b2e0cfdda95872a47c4881bad52abf
parentfda803221c0e44590c80db8d124519cf3b5c151b (diff)
feat: sync muc messages on join
-rw-r--r--src/connection/AbstractConnection.ts42
-rw-r--r--src/connection/Connection.interface.ts2
-rw-r--r--src/plugins/mam/Archive.ts58
-rw-r--r--src/plugins/mam/Plugin.ts58
4 files changed, 148 insertions, 12 deletions
diff --git a/src/connection/AbstractConnection.ts b/src/connection/AbstractConnection.ts
index f678ec17..99ba62a6 100644
--- a/src/connection/AbstractConnection.ts
+++ b/src/connection/AbstractConnection.ts
@@ -316,6 +316,48 @@ abstract class AbstractConnection {
return this.sendIQ(iq);
}
+ public queryArchiveNewMessages(startDate: Date, archive: JID, version: string, queryId: string): Promise<Element> {
+ let iq = $iq({
+ type: 'set',
+ to: archive.bare,
+ });
+
+ iq.c('query', {
+ xmlns: version,
+ queryid: queryId,
+ });
+
+ iq.c('x', {
+ xmlns: 'jabber:x:data',
+ type: 'submit',
+ });
+
+ iq.c('field', {
+ var: 'FORM_TYPE',
+ type: 'hidden',
+ })
+ .c('value')
+ .t(version)
+ .up()
+ .up();
+
+ iq.c('field', {
+ var: 'start',
+ })
+ .c('value')
+ .t(startDate.toISOString())
+ .up()
+ .up();
+
+ iq.up().c('set', {
+ xmlns: 'http://jabber.org/protocol/rsm',
+ });
+
+ iq.up();
+
+ return this.sendIQ(iq);
+ }
+
public changePassword(newPassword: string): Promise<Element> {
let iq = $iq({
type: 'set',
diff --git a/src/connection/Connection.interface.ts b/src/connection/Connection.interface.ts
index c05cdde4..51cfaa2e 100644
--- a/src/connection/Connection.interface.ts
+++ b/src/connection/Connection.interface.ts
@@ -58,6 +58,8 @@ export interface IConnection {
end?: Date
): Promise<Element>;
+ queryArchiveNewMessages(startDate: Date, archive: IJID, version: string, queryId: string): Promise<Element>;
+
changePassword(newPassword: string): Promise<Element>;
close();
diff --git a/src/plugins/mam/Archive.ts b/src/plugins/mam/Archive.ts
index befdfe28..eb77efb2 100644
--- a/src/plugins/mam/Archive.ts
+++ b/src/plugins/mam/Archive.ts
@@ -14,6 +14,7 @@ import MultiUserContact from '@src/MultiUserContact';
export default class Archive {
private archiveJid: IJID;
private messageCache: JQuery<HTMLElement>[] = [];
+ private syncNewMessages: boolean = false;
constructor(private plugin: MessageArchiveManagementPlugin, private contact: Contact) {
let jid = contact.isGroupChat() ? contact.getJid() : plugin.getConnection().getJID();
@@ -53,6 +54,38 @@ export default class Archive {
storage.registerHook(key, hook);
}
+ public newMessages() {
+ if (this.messageCache.length > 0) {
+ Log.debug('Ongoing message retrieval');
+ return false;
+ }
+
+ let queryId = UUID.v4();
+
+ this.plugin.addQueryContactRelation(queryId, this.contact);
+ let connection = this.plugin.getConnection();
+
+ let firstMessage = this.contact.getTranscript().getFirstChatMessage();
+
+ if (firstMessage !== undefined && firstMessage !== null && (<any>firstMessage).data !== undefined) {
+ let startDate = firstMessage.getStamp();
+ startDate.setMilliseconds(startDate.getMilliseconds() + 1);
+ this.plugin
+ .determineServerSupport(this.archiveJid)
+ .then(version => {
+ if (!version) {
+ throw new Error(`Archive JID ${this.archiveJid.full} has no support for MAM.`);
+ }
+ this.syncNewMessages = true;
+ return connection.queryArchiveNewMessages(startDate, this.archiveJid, <string>version, queryId);
+ })
+ .then(this.onComplete)
+ .catch(stanza => {
+ Log.warn('Error while requesting archive', stanza);
+ });
+ }
+ }
+
public nextMessages() {
if (this.isExhausted()) {
Log.debug('No more archived messages.');
@@ -90,7 +123,7 @@ export default class Archive {
}
let jid = !this.contact.isGroupChat() ? this.contact.getJid() : undefined;
-
+ this.syncNewMessages = false;
return connection.queryArchive(this.archiveJid, <string>version, queryId, jid, firstResultId, endDate);
})
.then(this.onComplete)
@@ -178,6 +211,9 @@ export default class Archive {
}
let transcript = this.contact.getTranscript();
+ if (this.syncNewMessages) {
+ this.messageCache.reverse();
+ }
while (this.messageCache.length > 0) {
let messageElement = this.messageCache.pop();
@@ -185,7 +221,13 @@ export default class Archive {
try {
let message = await this.parseForwardedMessage(messageElement);
- transcript.unshiftMessage(message);
+ if (this.syncNewMessages) {
+ if (!transcript.findMessageByAttrId(message.getAttrId())) {
+ transcript.pushMessage(message);
+ }
+ } else {
+ transcript.unshiftMessage(message);
+ }
} catch (err) {
continue;
}
@@ -204,7 +246,17 @@ export default class Archive {
unread: false,
});
- transcript.unshiftMessage(archiveExhaustedMessage);
+ if (this.syncNewMessages) {
+ if (
+ !transcript.getFirstMessage().isSystem() ||
+ (transcript.getFirstMessage().isSystem() &&
+ transcript.getFirstMessage().getPlaintextMessage() !== Translation.t('Archive_exhausted'))
+ ) {
+ transcript.pushMessage(archiveExhaustedMessage);
+ }
+ } else {
+ transcript.unshiftMessage(archiveExhaustedMessage);
+ }
}
this.setExhausted(isArchiveExhausted);
diff --git a/src/plugins/mam/Plugin.ts b/src/plugins/mam/Plugin.ts
index fe6c7737..dd6131fb 100644
--- a/src/plugins/mam/Plugin.ts
+++ b/src/plugins/mam/Plugin.ts
@@ -9,6 +9,7 @@ import Archive from './Archive';
import Contact from '@src/Contact';
import PluginAPI from '@src/plugin/PluginAPI';
import { IContact } from '@src/Contact.interface';
+import Client from '@src/Client';
const MIN_VERSION = '4.0.0';
const MAX_VERSION = '99.0.0';
@@ -56,19 +57,41 @@ export default class MessageArchiveManagementPlugin extends AbstractPlugin {
pluginAPI.registerChatWindowInitializedHook((chatWindow: ChatWindow, contact: Contact) => {
this.addLoadButtonIfEnabled(chatWindow, contact);
+ if (contact.isGroupChat()) {
+ this.syncMUCConversation(contact);
+ }
});
pluginAPI.registerChatWindowClearedHook((chatWindow: ChatWindow, contact: Contact) => {
let archiveJid = this.getArchiveJid(contact);
+ let fadeElement = chatWindow.getDom().find('.jsxc-window-fade');
+ if (fadeElement.find('.jsxc-mam-load-more').length > 0) {
+ fadeElement.find('.jsxc-mam-load-more').remove();
+ }
+
+ let messageAreaElement = chatWindow.getDom().find('.jsxc-message-area');
+ messageAreaElement.off('scroll');
+
if (this.supportCache[archiveJid.bare]) {
this.getArchive(contact.getJid()).clear();
}
+
+ setTimeout(() => {
+ this.addLoadButtonIfEnabled(chatWindow, contact, false);
+ }, 500);
});
this.pluginAPI.getConnection().registerHandler(this.onMamMessage, null, 'message', null);
}
+ private syncMUCConversation(contact: IContact) {
+ let archive = this.getArchive(contact.getJid());
+ Promise.resolve(archive.newMessages()).then(() => {
+ this.pluginAPI.Log.debug('Finished MAM Sync');
+ });
+ }
+
public getStorage() {
return this.pluginAPI.getStorage();
}
@@ -122,21 +145,24 @@ export default class MessageArchiveManagementPlugin extends AbstractPlugin {
return new JID(jid.bare);
}
- private addLoadButtonIfEnabled(chatWindow: ChatWindow, contact: Contact) {
+ private addLoadButtonIfEnabled(chatWindow: ChatWindow, contact: Contact, loadNow: boolean = true) {
let archivingJid = this.getArchiveJid(contact);
this.determineServerSupport(archivingJid).then(version => {
if (version) {
- this.addLoadButton(chatWindow.getDom(), contact);
+ this.addLoadButton(chatWindow.getDom(), contact, loadNow);
}
});
}
- private addLoadButton(chatWindowElement: JQuery<HTMLElement>, contact: Contact) {
+ private addLoadButton(chatWindowElement: JQuery<HTMLElement>, contact: Contact, loadNow: boolean) {
+ let fadeElement = chatWindowElement.find('.jsxc-window-fade');
+ if (fadeElement.find('.jsxc-mam-load-more').length > 0) {
+ return;
+ }
let classNameShow = 'jsxc-show';
let classNameMamEnable = 'jsxc-mam-enabled';
let messageAreaElement = chatWindowElement.find('.jsxc-message-area');
- let fadeElement = chatWindowElement.find('.jsxc-window-fade');
let archive = this.getArchive(contact.getJid());
@@ -150,18 +176,32 @@ export default class MessageArchiveManagementPlugin extends AbstractPlugin {
element.append(spanElement);
messageAreaElement.on('scroll', function () {
- const topDelta = 10;
- const scrollTop = Math.abs(this.scrollTop);
- const isAtTop = this.clientHeight + scrollTop + topDelta >= this.scrollHeight;
+ let scrollHeight: number = messageAreaElement[0].scrollHeight;
+ let clientHeight: number = messageAreaElement[0].clientHeight;
+ let scrollTop: number = messageAreaElement[0].scrollTop;
+ if (scrollTop < 0) scrollTop = scrollTop * -1;
+
+ let autoLoadOnScrollToTop = Client.getOption('autoLoadOnScrollToTop') || false;
+
+ if (
+ (clientHeight + 42 > scrollHeight - scrollTop && !archive.isExhausted()) ||
+ messageAreaElement.text().trim().length === 0
+ ) {
+ if (autoLoadOnScrollToTop) {
+ archive.nextMessages();
+ }
- if (isAtTop && !archive.isExhausted()) {
element.addClass(classNameShow);
} else {
element.removeClass(classNameShow);
}
});
- setTimeout(() => messageAreaElement.trigger('scroll'), 1000);
+ if (loadNow) {
+ messageAreaElement.trigger('scroll');
+ } else {
+ element.addClass(classNameShow);
+ }
if (!archive.isExhausted()) {
chatWindowElement.addClass(classNameMamEnable);