/** * @typedef {import('strophe.js/src/builder.js').Builder} Strophe.Builder */ import _converse from '../_converse.js'; import log from '../../log.js'; import { Strophe, toStanza } from 'strophe.js'; import { TimeoutError } from '../errors.js'; export default { /** * Allows you to send XML stanzas. * @method _converse.api.send * @param {Element|Strophe.Builder} stanza * @return {void} * @example * const msg = converse.env.$msg({ * 'from': 'juliet@example.com/balcony', * 'to': 'romeo@example.net', * 'type':'chat' * }); * _converse.api.send(msg); */ send (stanza) { const { api } = _converse; if (!api.connection.connected()) { log.warn("Not sending stanza because we're not connected!"); log.warn(Strophe.serialize(stanza)); return; } if (typeof stanza === 'string') { stanza = toStanza(stanza); } else if (stanza?.tree) { stanza = stanza.tree(); } if (stanza.tagName === 'iq') { return api.sendIQ(stanza); } else { api.connection.get().send(stanza); api.trigger('send', stanza); } }, /** * Send an IQ stanza * @method _converse.api.sendIQ * @param {Element|Strophe.Builder} stanza * @param {number} [timeout] - The default timeout value is taken from * the `stanza_timeout` configuration setting. * @param {boolean} [reject=true] - Whether an error IQ should cause the promise * to be rejected. If `false`, the promise will resolve instead of being rejected. * @returns {Promise} A promise which resolves (or potentially rejected) once we * receive a `result` or `error` stanza or once a timeout is reached. * If the IQ stanza being sent is of type `result` or `error`, there's * nothing to wait for, so an already resolved promise is returned. */ sendIQ (stanza, timeout, reject=true) { const { api } = _converse; if (!api.connection.connected()) { throw new Error("Not sending IQ stanza because we're not connected!"); } const connection = api.connection.get(); let promise; stanza = stanza.tree?.() ?? stanza; if (['get', 'set'].includes(stanza.getAttribute('type'))) { timeout = timeout || api.settings.get('stanza_timeout'); if (reject) { promise = new Promise((resolve, reject) => connection.sendIQ(stanza, resolve, reject, timeout)); promise.catch((e) => { if (e === null) { throw new TimeoutError( `Timeout error after ${timeout}ms for the following IQ stanza: ${Strophe.serialize(stanza)}` ); } }); } else { promise = new Promise((resolve) => connection.sendIQ(stanza, resolve, resolve, timeout)); } } else { connection.sendIQ(stanza); promise = Promise.resolve(); } api.trigger('send', stanza); return promise; } }