UNPKG

@converse/headless

Version:

Converse.js Headless build

145 lines (127 loc) 5.71 kB
import _converse from '../../shared/_converse.js'; import api from '../../shared/api/index.js'; import converse from '../../shared/api/public.js'; import { Collection } from '@converse/skeletor'; import { createStore } from '../../utils/storage.js'; const { Strophe, Stanza, stx } = converse.env; /** * @param {Element} stanza */ function onDiscoInfoRequest(stanza) { const node = stanza.getElementsByTagName('query')[0].getAttribute('node'); const from = stanza.getAttribute('from'); const id = stanza.getAttribute('id'); const result = stx` <iq type="result" id="${id}" ${from ? Stanza.unsafeXML(`to="${from}"`) : ''} xmlns="jabber:client"> <query xmlns="${Strophe.NS.DISCO_INFO}" ${node ? Stanza.unsafeXML(`node="${node}"`) : ''}> ${_converse.state.disco._identities.map((identity) => { return stx` <identity category="${identity.category}" type="${identity.type}" ${identity.name ? Stanza.unsafeXML(`name="${identity.name}"`) : ''} ${identity.lang ? Stanza.unsafeXML(`xml:lang="${identity.lang}"`) : ''}> </identity>`; })} ${_converse.state.disco._features.map((f) => stx`<feature var="${f}"></feature>`)} </query> </iq>`; api.send(result); return true; } function addClientFeatures() { // See https://xmpp.org/registrar/disco-categories.html api.disco.own.identities.add('client', 'web', 'Converse'); api.disco.own.features.add(Strophe.NS.CHATSTATES); api.disco.own.features.add(Strophe.NS.DISCO_INFO); api.disco.own.features.add(Strophe.NS.ROSTERX); // Limited support api.disco.own.features.add(Strophe.NS.CARBONS); /** * Triggered in converse-disco once the core disco features of * Converse have been added. * @event _converse#addClientFeatures * @example _converse.api.listen.on('addClientFeatures', () => { ... }); */ api.trigger('addClientFeatures'); return this; } export async function initializeDisco() { addClientFeatures(); api.connection .get() .addHandler((stanza) => onDiscoInfoRequest(stanza), Strophe.NS.DISCO_INFO, 'iq', 'get', null, null); const disco_entities = new _converse.exports.DiscoEntities(); Object.assign(_converse, { disco_entities }); // XXX: DEPRECATED Object.assign(_converse.state, { disco_entities }); const bare_jid = _converse.session.get('bare_jid'); const id = `converse.disco-entities-${bare_jid}`; disco_entities.storage = createStore(id, 'session'); const collection = await disco_entities.fetchEntities(); const domain = _converse.session.get('domain'); if (collection.length === 0 || !collection.get(domain)) { // If we don't have an entity for our own XMPP server, create one. api.disco.entities.create({ 'jid': domain }, { 'ignore_cache': true }); } /** * Triggered once the `converse-disco` plugin has been initialized and the * `_converse.disco_entities` collection will be available and populated with at * least the service discovery features of the user's own server. * @event _converse#discoInitialized * @example _converse.api.listen.on('discoInitialized', () => { ... }); */ api.trigger('discoInitialized'); } export function initStreamFeatures() { // Initialize the stream_features collection, and if we're // re-attaching to a pre-existing BOSH session, we restore the // features from cache. // Otherwise the features will be created once we've received them // from the server (see populateStreamFeatures). if (!_converse.state.stream_features) { const bare_jid = _converse.session.get('bare_jid'); const id = `converse.stream-features-${bare_jid}`; api.promises.add('streamFeaturesAdded'); const stream_features = new Collection(); stream_features.storage = createStore(id, 'session'); Object.assign(_converse, { stream_features }); // XXX: DEPRECATED Object.assign(_converse.state, { stream_features }); } } export function notifyStreamFeaturesAdded() { /** * Triggered as soon as the stream features are known. * If you want to check whether a stream feature is supported before proceeding, * then you'll first want to wait for this event. * @event _converse#streamFeaturesAdded * @example _converse.api.listen.on('streamFeaturesAdded', () => { ... }); */ api.trigger('streamFeaturesAdded'); } export function populateStreamFeatures() { // Strophe.js sets the <stream:features> element on the // Strophe.Connection instance. // // Once this is we populate the stream_features collection // and trigger streamFeaturesAdded. initStreamFeatures(); Array.from(api.connection.get().features.childNodes).forEach((feature) => { _converse.state.stream_features.create({ 'name': feature.nodeName, 'xmlns': feature.getAttribute('xmlns'), }); }); notifyStreamFeaturesAdded(); } export function clearSession() { const { disco_entities } = _converse.state; disco_entities?.forEach((e) => e.features.clearStore()); disco_entities?.forEach((e) => e.identities.clearStore()); disco_entities?.forEach((e) => e.dataforms.clearStore()); disco_entities?.forEach((e) => e.fields.clearStore()); disco_entities?.clearStore(); delete _converse.state.disco_entities; Object.assign(_converse, { disco_entities: undefined }); }