src/contacts/PresenceManager.js
import {EventEmitter2} from 'eventemitter2';
import {bindMethods} from '../utils';
import {PresenceQueue} from './PresenceQueue';
import {PresenceCollection} from './PresenceCollection';
/**
* Element that manages presences.
* It stores subscribed presences in a local collection that is
* updated when WacProxy notifies a change.
* @private
*/
export class PresenceManager {
static of(presenceService) {
return new PresenceManager(presenceService);
}
/**
* Constructs a Presence Manager
* @param {PresenceService} presenceService
* @private
*/
constructor(presenceService) {
this.presenceService = presenceService;
this.emitter = new EventEmitter2();
this.emitter.setMaxListeners(0);
/**
* Property used to determine if PresenceManager has been intialized
* and wait until initialization success.
* @private
* @type {Promise}
*/
this._init = null;
/**
* Collection of subscribed presences.
* @private
* @type {PresenceCollection}
*/
this._collection = null;
/**
* Queue that subscribes to presences through WacProxy.
* @private
* @type {PresenceQueue}
*/
this._queue = null;
bindMethods(this, [
'onPresenceUpdated',
]);
// init() is now sync, so... gas!
this.init();
}
/**
* Initialize PresenceManager.
* It retrieves already subscribed presences from WacStack and subscribe
* to presence updates.
* @return {Promise} resolved after initialization.
*/
init() {
this._collection = new PresenceCollection();
this._queue = new PresenceQueue(this.presenceService, this._collection);
this.presenceService.emitter.on('presence-updated', this.onPresenceUpdated);
this._init = true;
}
/**
* Deinitialize PresenceManager.
*/
uninit() {
this.presenceService.emitter.off('presence-update', this.onPresenceUpdated);
this.presenceService = null;
this._init = null;
this._collection = null;
this._queue = null;
}
/**
* Check if PresenceManager has been initialized and wait until
* initialization success.
* @return {Promise} resolved after initialization.
*/
isInitialized() {
if (!this._init) {
this.init();
}
}
/**
* Request the presence associated with given address and subscribe
* to presence updates.
* If such address is present into local collection, this method will return it.
* Otherwise a new subscription will be created through subscription queue.
* @param {String} address The address associated with requested presence.
* @return {Promise<object>} resolved with presence object.
*/
async subscribeToPresence(address) {
return await this._collection.getPresence(address) || this._queue.subscribeToPresence(address);
}
/**
* Unsubscribe from presence updates associated with given address.
* @param {String} address The presence address to stop receiving updates.
* @return {Promise} resolved when unsubscribed from presence updates.
*/
async unsubscribeFromPresence(address) {
this._collection.removePresence(address);
return this._queue.unsubscribeFromPresence(address);
}
/**
* Callback called when WacProxy notifies a presence update.
* @private
* @param {object} presence The presence that has been updated.
*/
onPresenceUpdated(presence) {
if (this._collection) {
this._collection.updatePresence(presence);
}
this.emitter.emit('updated', presence);
}
updatePresence(address, presence) {
const updatedPresence = Object.assign({}, presence, {address});
if (this._collection) {
this._collection.updatePresence(updatedPresence);
}
return this.presenceService.update(address, presence);
}
getPresence(address) {
return this.subscribeToPresence(address);
}
}