Commit 33600eee authored by JC Brand's avatar JC Brand

No need for a separate `archive_id` value.

With MAM2 we can just use stanza-id
parent be6a5d9c
This diff is collapsed.
This diff is collapsed.
...@@ -2223,7 +2223,7 @@ ...@@ -2223,7 +2223,7 @@
await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy'); await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy');
const view = _converse.chatboxviews.get('room@muc.example.com'); const view = _converse.chatboxviews.get('room@muc.example.com');
spyOn(view.model, 'hasDuplicateStanzaID').and.callThrough(); spyOn(view.model, 'findDuplicateFromStanzaID').and.callThrough();
let stanza = u.toStanza(` let stanza = u.toStanza(`
<message xmlns="jabber:client" <message xmlns="jabber:client"
from="room@muc.example.com/some1" from="room@muc.example.com/some1"
...@@ -2238,9 +2238,9 @@ ...@@ -2238,9 +2238,9 @@
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => _converse.api.chats.get().length); await test_utils.waitUntil(() => _converse.api.chats.get().length);
await test_utils.waitUntil(() => view.model.messages.length === 1); await test_utils.waitUntil(() => view.model.messages.length === 1);
await test_utils.waitUntil(() => view.model.hasDuplicateStanzaID.calls.count() === 1); await test_utils.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 1);
let result = await view.model.hasDuplicateStanzaID.calls.all()[0].returnValue; let result = await view.model.findDuplicateFromStanzaID.calls.all()[0].returnValue;
expect(result).toBe(false); expect(result).toBe(undefined);
stanza = u.toStanza(` stanza = u.toStanza(`
<message xmlns="jabber:client" <message xmlns="jabber:client"
...@@ -2254,9 +2254,9 @@ ...@@ -2254,9 +2254,9 @@
<origin-id xmlns="urn:xmpp:sid:0" id="de305d54-75b4-431b-adb2-eb6b9e546013"/> <origin-id xmlns="urn:xmpp:sid:0" id="de305d54-75b4-431b-adb2-eb6b9e546013"/>
</message>`); </message>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.hasDuplicateStanzaID.calls.count() === 2); await test_utils.waitUntil(() => view.model.findDuplicateFromStanzaID.calls.count() === 2);
result = await view.model.hasDuplicateStanzaID.calls.all()[1].returnValue; result = await view.model.findDuplicateFromStanzaID.calls.all()[1].returnValue;
expect(result).toBe(true); expect(result instanceof _converse.Message).toBe(true);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
done(); done();
})); }));
...@@ -2477,7 +2477,13 @@ ...@@ -2477,7 +2477,13 @@
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/> <origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
</message>`); </message>`);
await view.model.onMessage(stanza); await view.model.onMessage(stanza);
await test_utils.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1); expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1);
expect(view.model.messages.length).toBe(1);
const message = view.model.messages.at(0);
expect(message.get('stanza_id lounge@localhost')).toBe('5f3dbc5e-e1d3-4077-a492-693f3769c7ad');
expect(message.get('origin_id')).toBe(msg_obj.get('origin_id'));
done(); done();
})); }));
...@@ -2518,9 +2524,9 @@ ...@@ -2518,9 +2524,9 @@
by="room@muc.example.com"/> by="room@muc.example.com"/>
<origin-id xmlns="urn:xmpp:sid:0" id="${attrs.origin_id}"/> <origin-id xmlns="urn:xmpp:sid:0" id="${attrs.origin_id}"/>
</message>`); </message>`);
spyOn(view.model, 'handleReflection').and.callThrough(); spyOn(view.model, 'updateMessage').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.handleReflection.calls.count() === 1); await test_utils.waitUntil(() => view.model.updateMessage.calls.count() === 1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad"); expect(view.model.messages.at(0).get('stanza_id room@muc.example.com')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad");
expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id); expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id);
......
...@@ -290,6 +290,10 @@ converse.plugins.add('converse-chatboxes', { ...@@ -290,6 +290,10 @@ converse.plugins.add('converse-chatboxes', {
return this.vcard.get('fullname') || this.get('jid'); return this.vcard.get('fullname') || this.get('jid');
}, },
updateMessage (message, stanza) {
// Overridden in converse-muc and converse-mam
},
handleMessageCorrection (stanza) { handleMessageCorrection (stanza) {
const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop(); const replace = sizzle(`replace[xmlns="${Strophe.NS.MESSAGE_CORRECT}"]`, stanza).pop();
if (replace) { if (replace) {
...@@ -316,10 +320,14 @@ converse.plugins.add('converse-chatboxes', { ...@@ -316,10 +320,14 @@ converse.plugins.add('converse-chatboxes', {
return false; return false;
}, },
getDuplicateMessage (stanza) {
return this.findDuplicateFromOriginID(stanza) || this.findDuplicateFromStanzaID(stanza);
},
findDuplicateFromOriginID (stanza) { findDuplicateFromOriginID (stanza) {
const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!origin_id) { if (!origin_id) {
return false; return null;
} }
return this.messages.findWhere({ return this.messages.findWhere({
'origin_id': origin_id.getAttribute('id'), 'origin_id': origin_id.getAttribute('id'),
...@@ -327,23 +335,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -327,23 +335,7 @@ converse.plugins.add('converse-chatboxes', {
}); });
}, },
async hasDuplicateArchiveID (stanza) { async findDuplicateFromStanzaID(stanza) {
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!result) {
return false;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return false;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
const msg = this.messages.findWhere(query);
return !_.isNil(msg);
},
async hasDuplicateStanzaID (stanza) {
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop(); const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!stanza_id) { if (!stanza_id) {
return false; return false;
...@@ -355,8 +347,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -355,8 +347,7 @@ converse.plugins.add('converse-chatboxes', {
} }
const query = {}; const query = {};
query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id'); query[`stanza_id ${by_jid}`] = stanza_id.getAttribute('id');
const msg = this.messages.findWhere(query); return this.messages.findWhere(query);
return !_.isNil(msg);
}, },
...@@ -654,6 +645,10 @@ converse.plugins.add('converse-chatboxes', { ...@@ -654,6 +645,10 @@ converse.plugins.add('converse-chatboxes', {
return attrs; return attrs;
}, },
isArchived (original_stanza) {
return !_.isNil(sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop());
},
getMessageAttributesFromStanza (stanza, original_stanza) { getMessageAttributesFromStanza (stanza, original_stanza) {
/* Parses a passed in message stanza and returns an object /* Parses a passed in message stanza and returns an object
* of attributes. * of attributes.
...@@ -666,8 +661,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -666,8 +661,7 @@ converse.plugins.add('converse-chatboxes', {
* that contains the message stanza, if it was * that contains the message stanza, if it was
* contained, otherwise it's the message stanza itself. * contained, otherwise it's the message stanza itself.
*/ */
const archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(), const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(), delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
text = _converse.chatboxes.getMessageBody(stanza) || undefined, text = _converse.chatboxes.getMessageBody(stanza) || undefined,
chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING || chat_state = stanza.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING ||
...@@ -678,7 +672,7 @@ converse.plugins.add('converse-chatboxes', { ...@@ -678,7 +672,7 @@ converse.plugins.add('converse-chatboxes', {
const attrs = _.extend({ const attrs = _.extend({
'chat_state': chat_state, 'chat_state': chat_state,
'is_archived': !_.isNil(archive), 'is_archived': this.isArchived(original_stanza),
'is_delayed': !_.isNil(delay), 'is_delayed': !_.isNil(delay),
'is_spoiler': !_.isNil(spoiler), 'is_spoiler': !_.isNil(spoiler),
'is_single_emoji': text ? u.isSingleEmoji(text) : false, 'is_single_emoji': text ? u.isSingleEmoji(text) : false,
...@@ -926,18 +920,21 @@ converse.plugins.add('converse-chatboxes', { ...@@ -926,18 +920,21 @@ converse.plugins.add('converse-chatboxes', {
roster_nick = _.get(_converse.api.contacts.get(contact_jid), 'attributes.nickname'), roster_nick = _.get(_converse.api.contacts.get(contact_jid), 'attributes.nickname'),
chatbox = this.getChatBox(contact_jid, {'nickname': roster_nick}, has_body); chatbox = this.getChatBox(contact_jid, {'nickname': roster_nick}, has_body);
if (chatbox && if (chatbox) {
!chatbox.findDuplicateFromOriginID(stanza) && const message = await chatbox.getDuplicateMessage(stanza);
!await chatbox.hasDuplicateArchiveID(original_stanza) && if (message) {
!await chatbox.hasDuplicateStanzaID(stanza) && chatbox.updateMessage(message, original_stanza);
!chatbox.handleMessageCorrection(stanza) && }
!chatbox.handleReceipt (stanza, from_jid, is_carbon, is_me) && if (!message &&
!chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) { !chatbox.handleMessageCorrection(stanza) &&
!chatbox.handleReceipt (stanza, from_jid, is_carbon, is_me) &&
const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza); !chatbox.handleChatMarker(stanza, from_jid, is_carbon, is_roster_contact)) {
if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = chatbox.messages.create(attrs); const attrs = await chatbox.getMessageAttributesFromStanza(stanza, original_stanza);
chatbox.incrementUnreadMsgCounter(msg); if (attrs['chat_state'] || !u.isEmptyMessage(attrs)) {
const msg = chatbox.messages.create(attrs);
chatbox.incrementUnreadMsgCounter(msg);
}
} }
} }
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox}); _converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
......
...@@ -23,17 +23,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou ...@@ -23,17 +23,6 @@ const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'cou
const MAM_ATTRIBUTES = ['with', 'start', 'end']; const MAM_ATTRIBUTES = ['with', 'start', 'end'];
function getMessageArchiveID (stanza) {
// See https://xmpp.org/extensions/xep-0313.html#results
//
// The result messages MUST contain a <result/> element with an 'id'
// attribute that gives the current message's archive UID
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
if (!_.isUndefined(result)) {
return result.getAttribute('id');
}
}
function queryForArchivedMessages (_converse, options, callback, errback) { function queryForArchivedMessages (_converse, options, callback, errback) {
/* Internal function, called by the "archive.query" API method. /* Internal function, called by the "archive.query" API method.
*/ */
...@@ -128,10 +117,38 @@ converse.plugins.add('converse-mam', { ...@@ -128,10 +117,38 @@ converse.plugins.add('converse-mam', {
// New functions which don't exist yet can also be added. // New functions which don't exist yet can also be added.
ChatBox: { ChatBox: {
async getMessageAttributesFromStanza (message, original_stanza) { async findDuplicateFromArchiveID (stanza) {
const attrs = await this.__super__.getMessageAttributesFromStanza.apply(this, arguments); const { _converse } = this.__super__;
attrs.archive_id = getMessageArchiveID(original_stanza); const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
return attrs; if (!result) {
return null;
}
const by_jid = stanza.getAttribute('from') || this.get('jid');
const supported = await _converse.api.disco.supports(Strophe.NS.MAM, by_jid);
if (!supported.length) {
return null;
}
const query = {};
query[`stanza_id ${by_jid}`] = result.getAttribute('id');
return this.messages.findWhere(query);
},
async getDuplicateMessage (stanza) {
const message = await this.__super__.getDuplicateMessage.apply(this, arguments);
if (!message) {
return this.findDuplicateFromArchiveID(stanza);
}
return message;
},
updateMessage (message, stanza) {
this.__super__.updateMessage.apply(this, arguments);
if (message && !message.get('is_archived')) {
message.save(_.extend({
'is_archived': this.isArchived(stanza)
}, this.getStanzaIDs(stanza)));
}
} }
}, },
...@@ -155,15 +172,11 @@ converse.plugins.add('converse-mam', { ...@@ -155,15 +172,11 @@ converse.plugins.add('converse-mam', {
if (_.isNil(most_recent_msg)) { if (_.isNil(most_recent_msg)) {
this.fetchArchivedMessages(); this.fetchArchivedMessages();
} else { } else {
const archive_id = most_recent_msg.get('archive_id'); const stanza_id = most_recent_msg.get(`stanza_id ${this.model.get('jid')}`);
if (archive_id) { if (stanza_id) {
this.fetchArchivedMessages({ this.fetchArchivedMessages({'after': stanza_id});
'after': most_recent_msg.get('archive_id')
});
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
'start': most_recent_msg.get('time')
});
} }
} }
}, },
...@@ -250,11 +263,10 @@ converse.plugins.add('converse-mam', { ...@@ -250,11 +263,10 @@ converse.plugins.add('converse-mam', {
const { _converse } = this.__super__; const { _converse } = this.__super__;
if (this.content.scrollTop === 0 && this.model.messages.length) { if (this.content.scrollTop === 0 && this.model.messages.length) {
const oldest_message = this.model.messages.at(0); const oldest_message = this.model.messages.at(0);
const archive_id = oldest_message.get('archive_id'); const by_jid = this.model.get('jid');
if (archive_id) { const stanza_id = oldest_message.get(`stanza_id ${by_jid}`);
this.fetchArchivedMessages({ if (stanza_id) {
'before': archive_id this.fetchArchivedMessages({'before': stanza_id});
});
} else { } else {
this.fetchArchivedMessages({ this.fetchArchivedMessages({
'end': oldest_message.get('time') 'end': oldest_message.get('time')
...@@ -264,20 +276,6 @@ converse.plugins.add('converse-mam', { ...@@ -264,20 +276,6 @@ converse.plugins.add('converse-mam', {
}, },
}, },
ChatRoom: {
isDuplicate (message, original_stanza) {
const result = this.__super__.isDuplicate.apply(this, arguments);
if (result) {
return result;
}
const archive_id = getMessageArchiveID(original_stanza);
if (archive_id) {
return this.messages.filter({'archive_id': archive_id}).length > 0;
}
}
},
ChatRoomView: { ChatRoomView: {
initialize () { initialize () {
......
...@@ -972,33 +972,6 @@ converse.plugins.add('converse-muc', { ...@@ -972,33 +972,6 @@ converse.plugins.add('converse-muc', {
acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0; acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0;
}, },
handleReflection (stanza) {
/* Handle a MUC reflected message and return true if so.
*
* Parameters:
* (XMLElement) stanza: The message stanza
*/
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const msg = this.findDuplicateFromOriginID(stanza);
if (msg) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!msg.get('received')) {
attrs.received = moment().format();
}
msg.save(attrs);
}
return msg ? true : false;
}
},
subjectChangeHandled (attrs) { subjectChangeHandled (attrs) {
/* Handle a subject change and return `true` if so. /* Handle a subject change and return `true` if so.
* *
...@@ -1029,6 +1002,28 @@ converse.plugins.add('converse-muc', { ...@@ -1029,6 +1002,28 @@ converse.plugins.add('converse-muc', {
return is_csn && (attrs.is_delayed || own_message); return is_csn && (attrs.is_delayed || own_message);
}, },
updateMessage (message, stanza) {
/* Make sure that the already cached message is updated with
* the stanza ID.
*/
_converse.ChatBox.prototype.updateMessage.call(this, message, stanza);
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const attrs = {};
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const by_jid = stanza_id ? stanza_id.getAttribute('by') : undefined;
if (by_jid) {
const key = `stanza_id ${by_jid}`;
attrs[key] = stanza_id.getAttribute('id');
}
if (!message.get('received')) {
attrs.received = moment().format();
}
message.save(attrs);
}
},
async onMessage (stanza) { async onMessage (stanza) {
/* Handler for all MUC messages sent to this groupchat. /* Handler for all MUC messages sent to this groupchat.
* *
...@@ -1042,9 +1037,11 @@ converse.plugins.add('converse-muc', { ...@@ -1042,9 +1037,11 @@ converse.plugins.add('converse-muc', {
if (forwarded) { if (forwarded) {
stanza = forwarded.querySelector('message'); stanza = forwarded.querySelector('message');
} }
if (this.handleReflection(stanza) || const message = await this.getDuplicateMessage(original_stanza);
await this.hasDuplicateArchiveID(original_stanza) || if (message) {
await this.hasDuplicateStanzaID(stanza) || this.updateMessage(message, original_stanza);
}
if (message ||
this.handleMessageCorrection(stanza) || this.handleMessageCorrection(stanza) ||
this.isReceipt(stanza) || this.isReceipt(stanza) ||
this.isChatMarker(stanza)) { this.isChatMarker(stanza)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment