2021-05-12 12:14:28 +02:00
|
|
|
import isNaN from "lodash-es/isNaN";
|
2021-01-26 14:29:11 +01:00
|
|
|
import { Collection } from "@converse/skeletor/src/collection";
|
|
|
|
import { Model } from '@converse/skeletor/src/model.js';
|
2021-03-23 14:52:08 +01:00
|
|
|
import { converse } from "@converse/headless/core";
|
2021-07-15 18:45:16 +02:00
|
|
|
import { initStorage } from '@converse/headless/utils/storage.js';
|
2021-01-26 14:29:11 +01:00
|
|
|
|
|
|
|
const { Strophe, dayjs, sizzle } = converse.env;
|
|
|
|
|
|
|
|
export const Resource = Model.extend({'idAttribute': 'name'});
|
|
|
|
export const Resources = Collection.extend({'model': Resource});
|
|
|
|
|
|
|
|
|
|
|
|
export const Presence = Model.extend({
|
2022-04-19 09:19:42 +02:00
|
|
|
idAttribute: 'jid',
|
|
|
|
|
2021-01-26 14:29:11 +01:00
|
|
|
defaults: {
|
|
|
|
'show': 'offline'
|
|
|
|
},
|
|
|
|
|
|
|
|
initialize () {
|
|
|
|
this.resources = new Resources();
|
|
|
|
const id = `converse.identities-${this.get('jid')}`;
|
2021-03-23 14:52:08 +01:00
|
|
|
initStorage(this.resources, id, 'session');
|
|
|
|
|
2021-01-26 14:29:11 +01:00
|
|
|
this.listenTo(this.resources, 'update', this.onResourcesChanged);
|
|
|
|
this.listenTo(this.resources, 'change', this.onResourcesChanged);
|
|
|
|
},
|
|
|
|
|
|
|
|
onResourcesChanged () {
|
|
|
|
const hpr = this.getHighestPriorityResource();
|
|
|
|
const show = hpr?.attributes?.show || 'offline';
|
|
|
|
if (this.get('show') !== show) {
|
|
|
|
this.save({'show': show});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2022-04-19 09:19:42 +02:00
|
|
|
* Return the resource with the highest priority.
|
|
|
|
* If multiple resources have the same priority, take the latest one.
|
|
|
|
* @private
|
|
|
|
*/
|
2021-01-26 14:29:11 +01:00
|
|
|
getHighestPriorityResource () {
|
|
|
|
return this.resources.sortBy(r => `${r.get('priority')}-${r.get('timestamp')}`).reverse()[0];
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2022-04-19 09:19:42 +02:00
|
|
|
* Adds a new resource and it's associated attributes as taken
|
|
|
|
* from the passed in presence stanza.
|
|
|
|
* Also updates the presence if the resource has higher priority (and is newer).
|
|
|
|
* @private
|
|
|
|
* @param { XMLElement } presence: The presence stanza
|
|
|
|
*/
|
2021-01-26 14:29:11 +01:00
|
|
|
addResource (presence) {
|
|
|
|
const jid = presence.getAttribute('from'),
|
|
|
|
name = Strophe.getResourceFromJid(jid),
|
|
|
|
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
|
|
|
priority = presence.querySelector('priority')?.textContent ?? 0,
|
|
|
|
resource = this.resources.get(name),
|
|
|
|
settings = {
|
|
|
|
'name': name,
|
|
|
|
'priority': isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
|
|
|
|
'show': presence.querySelector('show')?.textContent ?? 'online',
|
|
|
|
'timestamp': delay ? dayjs(delay.getAttribute('stamp')).toISOString() : (new Date()).toISOString()
|
|
|
|
};
|
|
|
|
if (resource) {
|
|
|
|
resource.save(settings);
|
|
|
|
} else {
|
|
|
|
this.resources.create(settings);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2022-04-19 09:19:42 +02:00
|
|
|
* Remove the passed in resource from the resources map.
|
|
|
|
* Also redetermines the presence given that there's one less
|
|
|
|
* resource.
|
|
|
|
* @private
|
|
|
|
* @param { string } name: The resource name
|
|
|
|
*/
|
2021-01-26 14:29:11 +01:00
|
|
|
removeResource (name) {
|
|
|
|
const resource = this.resources.get(name);
|
|
|
|
if (resource) {
|
|
|
|
resource.destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const Presences = Collection.extend({'model': Presence });
|