Add timestamps to resources

So that when a higher priority resource goes offline, we can fall back to the
right chat status if at the next priority level there are multiple resources.

789654d54e (comments)
This commit is contained in:
JC Brand 2017-02-21 22:13:49 +01:00
parent 7cfd77b8ec
commit 4aa123d557
2 changed files with 173 additions and 106 deletions

View File

@ -21,115 +21,174 @@
test_utils.createContacts(_converse, 'current'); // Create some contacts so that we can test positioning test_utils.createContacts(_converse, 'current'); // Create some contacts so that we can test positioning
var contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost'; var contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost';
var contact = _converse.roster.get(contact_jid); var contact = _converse.roster.get(contact_jid);
var stanza = $( var stanza;
'<presence xmlns="jabber:client"'+ runs(function () {
' to="dummy@localhost/converse.js-21770972"'+ stanza = $(
' from="'+contact_jid+'/c71f218b-0797-4732-8a88-b42cb1d8557a">'+ '<presence xmlns="jabber:client"'+
' <priority>1</priority>'+ ' to="dummy@localhost/converse.js-21770972"'+
' <c xmlns="http://jabber.org/protocol/caps" hash="sha-1" ext="voice-v1 camera-v1 video-v1"'+ ' from="'+contact_jid+'/priority-1-resource">'+
' ver="AcN1/PEN8nq7AHD+9jpxMV4U6YM=" node="http://pidgin.im/"/>'+ ' <priority>1</priority>'+
' <x xmlns="vcard-temp:x:update">'+ ' <c xmlns="http://jabber.org/protocol/caps" hash="sha-1" ext="voice-v1 camera-v1 video-v1"'+
' <photo>ce51d94f7f22b87a21274abb93710b9eb7cc1c65</photo>'+ ' ver="AcN1/PEN8nq7AHD+9jpxMV4U6YM=" node="http://pidgin.im/"/>'+
' </x>'+ ' <x xmlns="vcard-temp:x:update">'+
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="jabbim.hu"/>'+ ' <photo>ce51d94f7f22b87a21274abb93710b9eb7cc1c65</photo>'+
'</presence>'); ' </x>'+
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); ' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="jabbim.hu"/>'+
expect(contact.get('chat_status')).toBe('online'); '</presence>');
expect(_.keys(contact.get('resources')).length).toBe(1); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1); expect(contact.get('chat_status')).toBe('online');
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online'); expect(_.keys(contact.get('resources')).length).toBe(1);
expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' id="tYRdj-35"'+ ' to="dummy@localhost/converse.js-21770972"'+
' to="dummy@localhost/converse.js-21770972"'+ ' from="'+contact_jid+'/priority-0-resource">'+
' from="'+contact_jid+'/androidkhydmcKW">'+ ' <status/>'+
' <status/>'+ ' <priority>0</priority>'+
' <priority>0</priority>'+ ' <show>xa</show>'+
' <show>xa</show>'+ ' <c xmlns="http://jabber.org/protocol/caps" ver="GyIX/Kpa4ScVmsZCxRBboJlLAYU=" hash="sha-1"'+
' <c xmlns="http://jabber.org/protocol/caps" ver="GyIX/Kpa4ScVmsZCxRBboJlLAYU=" hash="sha-1"'+ ' node="http://www.igniterealtime.org/projects/smack/"/>'+
' node="http://www.igniterealtime.org/projects/smack/"/>'+ ' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="jabbim.hu"/>'+
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T17:02:24Z" from="jabbim.hu"/>'+ '</presence>');
'</presence>'); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('online');
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('online'); expect(_.keys(contact.get('resources')).length).toBe(2);
expect(_.keys(contact.get('resources')).length).toBe(2); expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1); expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online'); expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0); expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' id="tYRdj-35"'+ ' to="dummy@localhost/converse.js-21770972"'+
' to="dummy@localhost/converse.js-21770972"'+ ' from="'+contact_jid+'/priority-2-resource">'+
' from="'+contact_jid+'/other-resource">'+ ' <priority>2</priority>'+
' <priority>2</priority>'+ ' <show>dnd</show>'+
' <show>dnd</show>'+ '</presence>');
'</presence>'); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd');
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); expect(_.keys(contact.get('resources')).length).toBe(3);
expect(_.keys(contact.get('resources')).length).toBe(3); expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1); expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online'); expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0); expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa'); expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.get('resources')['other-resource']['priority']).toBe(2); expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd');
expect(contact.get('resources')['other-resource']['status']).toBe('dnd');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' id="tYRdj-35"'+ ' to="dummy@localhost/converse.js-21770972"'+
' to="dummy@localhost/converse.js-21770972"'+ ' from="'+contact_jid+'/priority-3-resource">'+
' from="'+contact_jid+'/other-resource">'+ ' <priority>3</priority>'+
' <priority>3</priority>'+ ' <show>away</show>'+
' <show>away</show>'+ '</presence>');
'</presence>'); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away');
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away'); expect(_.keys(contact.get('resources')).length).toBe(4);
expect(_.keys(contact.get('resources')).length).toBe(3); expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1); expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online'); expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0); expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa'); expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.get('resources')['other-resource']['priority']).toBe(3); expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd');
expect(contact.get('resources')['other-resource']['status']).toBe('away'); expect(contact.get('resources')['priority-3-resource']['priority']).toBe(3);
expect(contact.get('resources')['priority-3-resource']['status']).toBe('away');
});
waits(1000); // XXX: Bit of a hack. With jasmine 2 we can mock the date instead.
runs(function () {
stanza = $(
'<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+
' from="'+contact_jid+'/newer-priority-1-resource">'+
' <priority>1</priority>'+
' <show>dnd</show>'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away');
expect(_.keys(contact.get('resources')).length).toBe(5);
expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd');
expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd');
expect(contact.get('resources')['priority-3-resource']['priority']).toBe(3);
expect(contact.get('resources')['priority-3-resource']['status']).toBe('away');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+ ' to="dummy@localhost/converse.js-21770972"'+
' type="unavailable"'+ ' type="unavailable"'+
' from="'+contact_jid+'/other-resource">'+ ' from="'+contact_jid+'/priority-3-resource">'+
'</presence>'); '</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('online'); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd');
expect(_.keys(contact.get('resources')).length).toBe(2); expect(_.keys(contact.get('resources')).length).toBe(4);
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0); expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa'); expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1); expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online'); expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2);
expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd');
expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+ ' to="dummy@localhost/converse.js-21770972"'+
' type="unavailable"'+ ' type="unavailable"'+
' from="'+contact_jid+'/c71f218b-0797-4732-8a88-b42cb1d8557a">'+ ' from="'+contact_jid+'/priority-2-resource">'+
'</presence>'); '</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('xa'); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd');
expect(_.keys(contact.get('resources')).length).toBe(1); expect(_.keys(contact.get('resources')).length).toBe(3);
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0); expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa'); expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['priority-1-resource']['status']).toBe('online');
expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd');
stanza = $( stanza = $(
'<presence xmlns="jabber:client"'+ '<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+ ' to="dummy@localhost/converse.js-21770972"'+
' type="unavailable"'+ ' type="unavailable"'+
' from="'+contact_jid+'/androidkhydmcKW">'+ ' from="'+contact_jid+'/priority-1-resource">'+
'</presence>'); '</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0])); _converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('offline'); expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd');
expect(_.keys(contact.get('resources')).length).toBe(0); expect(_.keys(contact.get('resources')).length).toBe(2);
expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1);
expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd');
stanza = $(
'<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+
' type="unavailable"'+
' from="'+contact_jid+'/newer-priority-1-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('xa');
expect(_.keys(contact.get('resources')).length).toBe(1);
expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0);
expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa');
stanza = $(
'<presence xmlns="jabber:client"'+
' to="dummy@localhost/converse.js-21770972"'+
' type="unavailable"'+
' from="'+contact_jid+'/priority-0-resource">'+
'</presence>');
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('offline');
expect(_.keys(contact.get('resources')).length).toBe(0);
});
})); }));
}); });
})); }));

View File

@ -859,8 +859,9 @@
var resources = this.get('resources'); var resources = this.get('resources');
if (!_.isObject(resources)) { resources = {}; } if (!_.isObject(resources)) { resources = {}; }
resources[resource] = { resources[resource] = {
'priority': _.isNaN(Number(priority)) ? 0 : Number(priority), 'priority': _.isNaN(parseInt(priority)) ? 0 : parseInt(priority),
'status': chat_status 'status': chat_status,
'timestamp': moment().format()
}; };
this.set({'resources': resources}); this.set({'resources': resources});
return resources; return resources;
@ -884,10 +885,17 @@
getHighestPriorityStatus: function () { getHighestPriorityStatus: function () {
/* Return the chat status assigned to the resource with the /* Return the chat status assigned to the resource with the
* highest priority. * highest priority.
*
* If multiple resources have the same priority, take the
* newest one.
*/ */
var resources = this.get('resources'); var resources = this.get('resources');
if (_.isObject(resources) && _.size(resources)) { if (_.isObject(resources) && _.size(resources)) {
var val = _.flow(_.values, _.partial(_.sortBy, _, 'priority'), _.reverse)(resources)[0]; var val = _.flow(
_.values,
_.partial(_.sortBy, _, ['priority', 'timestamp']),
_.reverse
)(resources)[0];
if (!_.isUndefined(val)) { if (!_.isUndefined(val)) {
return val.status; return val.status;
} }