|
@@ -5,7 +5,8 @@
|
|
|
*/
|
|
|
import './polyfill';
|
|
|
import 'strophe.js/src/websocket';
|
|
|
-import * as strophe from 'strophe.js/src/core';
|
|
|
+import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
|
|
+import { Connection, MockConnection } from '@converse/headless/connection.js';
|
|
|
import Storage from '@converse/skeletor/src/storage.js';
|
|
|
import _ from './lodash.noconflict';
|
|
|
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
|
@@ -22,11 +23,6 @@ import { Router } from '@converse/skeletor/src/router.js';
|
|
|
import { __, i18n } from './i18n';
|
|
|
import { assignIn, debounce, invoke, isFunction, isObject, isString, pick } from 'lodash-es';
|
|
|
|
|
|
-const Strophe = strophe.default.Strophe;
|
|
|
-const $build = strophe.default.$build;
|
|
|
-const $iq = strophe.default.$iq;
|
|
|
-const $msg = strophe.default.$msg;
|
|
|
-const $pres = strophe.default.$pres;
|
|
|
|
|
|
dayjs.extend(advancedFormat);
|
|
|
|
|
@@ -82,8 +78,6 @@ class IllegalMessage extends Error {}
|
|
|
// Setting wait to 59 instead of 60 to avoid timing conflicts with the
|
|
|
// webserver, which is often also set to 60 and might therefore sometimes
|
|
|
// return a 504 error page instead of passing through to the BOSH proxy.
|
|
|
-const BOSH_WAIT = 59;
|
|
|
-
|
|
|
const PROMISES = [
|
|
|
'afterResourceBinding',
|
|
|
'connectionInitialized',
|
|
@@ -233,7 +227,9 @@ export const _converse = {
|
|
|
TimeoutError: TimeoutError,
|
|
|
IllegalMessage: IllegalMessage,
|
|
|
|
|
|
- isTestEnv: () => (Strophe.Connection.name === 'MockConnection'),
|
|
|
+ isTestEnv: () => {
|
|
|
+ return initialization_settings.bosh_service_url === 'montague.lit/http-bind';
|
|
|
+ },
|
|
|
|
|
|
/**
|
|
|
* Translate the given string based on the current locale.
|
|
@@ -296,7 +292,7 @@ function initUserSettings () {
|
|
|
if (!user_settings?.fetched) {
|
|
|
const id = `converse.user-settings.${_converse.bare_jid}`;
|
|
|
user_settings = new Model({id});
|
|
|
- user_settings.browserStorage = _converse.createStore(id);
|
|
|
+ user_settings.browserStorage = createStore(id);
|
|
|
user_settings.fetched = user_settings.fetch({'promise': true});
|
|
|
}
|
|
|
return user_settings.fetched;
|
|
@@ -394,9 +390,9 @@ export const api = _converse.api = {
|
|
|
}
|
|
|
|
|
|
if (_converse.connection.reconnecting) {
|
|
|
- debouncedReconnect();
|
|
|
+ _converse.connection.debouncedReconnect();
|
|
|
} else {
|
|
|
- return reconnect();
|
|
|
+ return _converse.connection.reconnect();
|
|
|
}
|
|
|
},
|
|
|
|
|
@@ -407,11 +403,7 @@ export const api = _converse.api = {
|
|
|
* @returns {boolean}
|
|
|
*/
|
|
|
isType (type) {
|
|
|
- if (type.toLowerCase() === 'websocket') {
|
|
|
- return _converse.connection._proto instanceof Strophe.Websocket;
|
|
|
- } else if (type.toLowerCase() === 'bosh') {
|
|
|
- return Strophe.BOSH && _converse.connection._proto instanceof Strophe.Bosh;
|
|
|
- }
|
|
|
+ return _converse.connection.isType(type);
|
|
|
}
|
|
|
},
|
|
|
|
|
@@ -508,8 +500,15 @@ export const api = _converse.api = {
|
|
|
* fails to restore a previous auth'd session.
|
|
|
*/
|
|
|
async login (jid, password, automatic=false) {
|
|
|
- if (jid || _converse.jid) {
|
|
|
- jid = await _converse.setUserJID(jid || _converse.jid);
|
|
|
+ jid = jid || _converse.jid;
|
|
|
+ if (!_converse.connection?.jid || (jid && !u.isSameDomain(_converse.connection.jid, jid))) {
|
|
|
+ await _converse.initConnection();
|
|
|
+ }
|
|
|
+ if (api.settings.get("connection_options")?.worker && (await _converse.connection.restoreWorkerSession())) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (jid) {
|
|
|
+ jid = await _converse.setUserJID(jid);
|
|
|
}
|
|
|
|
|
|
// See whether there is a BOSH session to re-attach to
|
|
@@ -521,7 +520,6 @@ export const api = _converse.api = {
|
|
|
return _converse.startNewPreboundBOSHSession();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
password = password || api.settings.get("password");
|
|
|
const credentials = (jid && password) ? { jid, password } : null;
|
|
|
attemptNonPreboundSession(credentials, automatic);
|
|
@@ -546,7 +544,7 @@ export const api = _converse.api = {
|
|
|
promise.resolve();
|
|
|
}
|
|
|
|
|
|
- _converse.setDisconnectionCause(_converse.LOGOUT, undefined, true);
|
|
|
+ _converse.connection.setDisconnectionCause(_converse.LOGOUT, undefined, true);
|
|
|
if (_converse.connection !== undefined) {
|
|
|
api.listen.once('disconnected', () => complete());
|
|
|
_converse.connection.disconnect();
|
|
@@ -933,16 +931,6 @@ function replacePromise (name) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-_converse.haveResumed = function () {
|
|
|
- if (_converse.api.connection.isType('bosh')) {
|
|
|
- return _converse.connfeedback.get('connection_status') === Strophe.Status.ATTACHED;
|
|
|
- } else {
|
|
|
- // XXX: Not binding means that the session was resumed.
|
|
|
- // This seems very fragile. Perhaps a better way is possible.
|
|
|
- return !_converse.connection.do_bind;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
_converse.isUniView = function () {
|
|
|
/* We distinguish between UniView and MultiView instances.
|
|
|
*
|
|
@@ -984,11 +972,13 @@ function initPersistentStorage () {
|
|
|
}
|
|
|
|
|
|
|
|
|
-_converse.createStore = function (id, storage) {
|
|
|
+function createStore (id, storage) {
|
|
|
const s = _converse.storage[storage ? storage : _converse.config.get('storage')];
|
|
|
return new Storage(id, s);
|
|
|
}
|
|
|
|
|
|
+_converse.createStore = createStore;
|
|
|
+
|
|
|
|
|
|
function initPlugins () {
|
|
|
// If initialize gets called a second time (e.g. during tests), then we
|
|
@@ -1046,7 +1036,7 @@ function initClientConfig () {
|
|
|
'trusted': _converse.api.settings.get("trusted") && true || false,
|
|
|
'storage': _converse.api.settings.get("trusted") ? 'persistent' : 'session'
|
|
|
});
|
|
|
- _converse.config.browserStorage = _converse.createStore(id, "session");
|
|
|
+ _converse.config.browserStorage = createStore(id, "session");
|
|
|
_converse.config.fetch();
|
|
|
/**
|
|
|
* Triggered once the XMPP-client configuration has been initialized.
|
|
@@ -1061,7 +1051,7 @@ function initClientConfig () {
|
|
|
}
|
|
|
|
|
|
|
|
|
-async function tearDown () {
|
|
|
+export async function tearDown () {
|
|
|
await _converse.api.trigger('beforeTearDown', {'synchronous': true});
|
|
|
window.removeEventListener('click', _converse.onUserActivity);
|
|
|
window.removeEventListener('focus', _converse.onUserActivity);
|
|
@@ -1075,7 +1065,8 @@ async function tearDown () {
|
|
|
|
|
|
|
|
|
async function attemptNonPreboundSession (credentials, automatic) {
|
|
|
- if (_converse.api.settings.get("authentication") === _converse.LOGIN) {
|
|
|
+ const { api } = _converse;
|
|
|
+ if (api.settings.get("authentication") === _converse.LOGIN) {
|
|
|
// XXX: If EITHER ``keepalive`` or ``auto_login`` is ``true`` and
|
|
|
// ``authentication`` is set to ``login``, then Converse will try to log the user in,
|
|
|
// since we don't have a way to distinguish between wether we're
|
|
@@ -1112,12 +1103,7 @@ function connect (credentials) {
|
|
|
if (!_converse.connection.reconnecting) {
|
|
|
_converse.connection.reset();
|
|
|
}
|
|
|
- _converse.connection.connect(
|
|
|
- _converse.jid.toLowerCase(),
|
|
|
- null,
|
|
|
- _converse.onConnectStatusChanged,
|
|
|
- BOSH_WAIT
|
|
|
- );
|
|
|
+ _converse.connection.connect(_converse.jid.toLowerCase());
|
|
|
} else if (_converse.api.settings.get("authentication") === _converse.LOGIN) {
|
|
|
const password = credentials ? credentials.password : (_converse.connection?.pass || _converse.api.settings.get("password"));
|
|
|
if (!password) {
|
|
@@ -1125,51 +1111,25 @@ function connect (credentials) {
|
|
|
throw new Error("autoLogin: If you use auto_login and "+
|
|
|
"authentication='login' then you also need to provide a password.");
|
|
|
}
|
|
|
- _converse.setDisconnectionCause(Strophe.Status.AUTHFAIL, undefined, true);
|
|
|
+ _converse.connection.setDisconnectionCause(Strophe.Status.AUTHFAIL, undefined, true);
|
|
|
_converse.api.connection.disconnect();
|
|
|
return;
|
|
|
}
|
|
|
if (!_converse.connection.reconnecting) {
|
|
|
_converse.connection.reset();
|
|
|
}
|
|
|
- _converse.connection.connect(_converse.jid, password, _converse.onConnectStatusChanged, BOSH_WAIT);
|
|
|
+ _converse.connection.connect(_converse.jid, password);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
-async function reconnect () {
|
|
|
- log.debug('RECONNECTING: the connection has dropped, attempting to reconnect.');
|
|
|
- _converse.setConnectionStatus(
|
|
|
- Strophe.Status.RECONNECTING,
|
|
|
- __('The connection has dropped, attempting to reconnect.')
|
|
|
- );
|
|
|
- /**
|
|
|
- * Triggered when the connection has dropped, but Converse will attempt
|
|
|
- * to reconnect again.
|
|
|
- *
|
|
|
- * @event _converse#will-reconnect
|
|
|
- */
|
|
|
- _converse.api.trigger('will-reconnect');
|
|
|
-
|
|
|
- _converse.connection.reconnecting = true;
|
|
|
- await tearDown();
|
|
|
- return _converse.api.user.login();
|
|
|
-}
|
|
|
-
|
|
|
-const debouncedReconnect = debounce(reconnect, 2000);
|
|
|
-
|
|
|
-
|
|
|
_converse.shouldClearCache = () => (!_converse.config.get('trusted') || _converse.isTestEnv());
|
|
|
|
|
|
|
|
|
-function clearSession () {
|
|
|
- if (_converse.session !== undefined) {
|
|
|
- _converse.session.destroy();
|
|
|
- delete _converse.session;
|
|
|
- }
|
|
|
- if (_converse.shouldClearCache()) {
|
|
|
- _converse.api.user.settings.clear();
|
|
|
- }
|
|
|
+export function clearSession () {
|
|
|
+ _converse.session?.destroy();
|
|
|
+ delete _converse.session;
|
|
|
+ _converse.shouldClearCache() && _converse.api.user.settings.clear();
|
|
|
/**
|
|
|
* Synchronouse event triggered once the user session has been cleared,
|
|
|
* for example when the user has logged out or when Converse has
|
|
@@ -1180,77 +1140,31 @@ function clearSession () {
|
|
|
}
|
|
|
|
|
|
|
|
|
-async function onDomainDiscovered (response) {
|
|
|
- const text = await response.text();
|
|
|
- const xrd = (new window.DOMParser()).parseFromString(text, "text/xml").firstElementChild;
|
|
|
- if (xrd.nodeName != "XRD" || xrd.namespaceURI != "http://docs.oasis-open.org/ns/xri/xrd-1.0") {
|
|
|
- return log.warn("Could not discover XEP-0156 connection methods");
|
|
|
- }
|
|
|
- const bosh_links = sizzle(`Link[rel="urn:xmpp:alt-connections:xbosh"]`, xrd);
|
|
|
- const ws_links = sizzle(`Link[rel="urn:xmpp:alt-connections:websocket"]`, xrd);
|
|
|
- const bosh_methods = bosh_links.map(el => el.getAttribute('href'));
|
|
|
- const ws_methods = ws_links.map(el => el.getAttribute('href'));
|
|
|
- // TODO: support multiple endpoints
|
|
|
- _converse.api.settings.set("websocket_url", ws_methods.pop());
|
|
|
- _converse.api.settings.set('bosh_service_url', bosh_methods.pop());
|
|
|
- if (bosh_methods.length === 0 && ws_methods.length === 0) {
|
|
|
- log.warn(
|
|
|
- "onDomainDiscovered: neither BOSH nor WebSocket connection methods have been specified with XEP-0156."
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-async function discoverConnectionMethods (domain) {
|
|
|
- // Use XEP-0156 to check whether this host advertises websocket or BOSH connection methods.
|
|
|
- const options = {
|
|
|
- 'mode': 'cors',
|
|
|
- 'headers': {
|
|
|
- 'Accept': 'application/xrd+xml, text/xml'
|
|
|
- }
|
|
|
- };
|
|
|
- const url = `https://${domain}/.well-known/host-meta`;
|
|
|
- let response;
|
|
|
- try {
|
|
|
- response = await fetch(url, options);
|
|
|
- } catch (e) {
|
|
|
- log.error(`Failed to discover alternative connection methods at ${url}`);
|
|
|
- log.error(e);
|
|
|
- return;
|
|
|
- }
|
|
|
- if (response.status >= 200 && response.status < 400) {
|
|
|
- await onDomainDiscovered(response);
|
|
|
- } else {
|
|
|
- log.warn("Could not discover XEP-0156 connection methods");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
+_converse.initConnection = function () {
|
|
|
+ const api = _converse.api;
|
|
|
|
|
|
-_converse.initConnection = async function (domain) {
|
|
|
- if (_converse.api.settings.get("discover_connection_methods")) {
|
|
|
- await discoverConnectionMethods(domain);
|
|
|
- }
|
|
|
- if (! _converse.api.settings.get('bosh_service_url')) {
|
|
|
- if (_converse.api.settings.get("authentication") === _converse.PREBIND) {
|
|
|
+ if (! api.settings.get('bosh_service_url')) {
|
|
|
+ if (api.settings.get("authentication") === _converse.PREBIND) {
|
|
|
throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection");
|
|
|
}
|
|
|
- if (! _converse.api.settings.get("websocket_url")) {
|
|
|
+ if (! api.settings.get("websocket_url")) {
|
|
|
throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (('WebSocket' in window || 'MozWebSocket' in window) && _converse.api.settings.get("websocket_url")) {
|
|
|
- _converse.connection = new Strophe.Connection(
|
|
|
- _converse.api.settings.get("websocket_url"),
|
|
|
- Object.assign(_converse.default_connection_options, _converse.api.settings.get("connection_options"))
|
|
|
+ const XMPPConnection = _converse.isTestEnv() ? MockConnection : Connection;
|
|
|
+ if (('WebSocket' in window || 'MozWebSocket' in window) && api.settings.get("websocket_url")) {
|
|
|
+ _converse.connection = new XMPPConnection(
|
|
|
+ api.settings.get("websocket_url"),
|
|
|
+ Object.assign(_converse.default_connection_options, api.settings.get("connection_options"))
|
|
|
);
|
|
|
- } else if (_converse.api.settings.get('bosh_service_url')) {
|
|
|
- _converse.connection = new Strophe.Connection(
|
|
|
- _converse.api.settings.get('bosh_service_url'),
|
|
|
+ } else if (api.settings.get('bosh_service_url')) {
|
|
|
+ _converse.connection = new XMPPConnection(
|
|
|
+ api.settings.get('bosh_service_url'),
|
|
|
Object.assign(
|
|
|
_converse.default_connection_options,
|
|
|
- _converse.api.settings.get("connection_options"),
|
|
|
- {'keepalive': _converse.api.settings.get("keepalive")}
|
|
|
+ api.settings.get("connection_options"),
|
|
|
+ {'keepalive': api.settings.get("keepalive")}
|
|
|
)
|
|
|
);
|
|
|
} else {
|
|
@@ -1259,23 +1173,28 @@ _converse.initConnection = async function (domain) {
|
|
|
}
|
|
|
setUpXMLLogging();
|
|
|
/**
|
|
|
- * Triggered once the `Strophe.Connection` constructor has been initialized, which
|
|
|
+ * Triggered once the `Connection` constructor has been initialized, which
|
|
|
* will be responsible for managing the connection to the XMPP server.
|
|
|
*
|
|
|
* @event _converse#connectionInitialized
|
|
|
*/
|
|
|
- _converse.api.trigger('connectionInitialized');
|
|
|
+ api.trigger('connectionInitialized');
|
|
|
}
|
|
|
|
|
|
|
|
|
async function initSession (jid) {
|
|
|
+ const is_shared_session = api.settings.get('connection_options').worker;
|
|
|
+
|
|
|
const bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase();
|
|
|
const id = `converse.session-${bare_jid}`;
|
|
|
- if (!_converse.session || _converse.session.get('id') !== id) {
|
|
|
+ if (_converse.session?.get('id') !== id) {
|
|
|
_converse.session = new Model({id});
|
|
|
- _converse.session.browserStorage = _converse.createStore(id, "session");
|
|
|
+ _converse.session.browserStorage = createStore(id, is_shared_session ? "persistent" : "session");
|
|
|
await new Promise(r => _converse.session.fetch({'success': r, 'error': r}));
|
|
|
- if (_converse.session.get('active')) {
|
|
|
+
|
|
|
+ if (!is_shared_session && _converse.session.get('active')) {
|
|
|
+ // If the `active` flag is set, it means this tab was cloned from
|
|
|
+ // another (e.g. via middle-click), and its session data was copied over.
|
|
|
_converse.session.clear();
|
|
|
_converse.session.save({id});
|
|
|
}
|
|
@@ -1297,7 +1216,7 @@ async function initSession (jid) {
|
|
|
function saveJIDtoSession (jid) {
|
|
|
jid = _converse.session.get('jid') || jid;
|
|
|
if (_converse.api.settings.get("authentication") !== _converse.ANONYMOUS && !Strophe.getResourceFromJid(jid)) {
|
|
|
- jid = jid.toLowerCase() + _converse.generateResource();
|
|
|
+ jid = jid.toLowerCase() + Connection.generateResource();
|
|
|
}
|
|
|
_converse.jid = jid;
|
|
|
_converse.bare_jid = Strophe.getBareJidFromJid(jid);
|
|
@@ -1308,6 +1227,9 @@ function saveJIDtoSession (jid) {
|
|
|
'bare_jid': _converse.bare_jid,
|
|
|
'resource': _converse.resource,
|
|
|
'domain': _converse.domain,
|
|
|
+ // We use the `active` flag to determine whether we should use the values from sessionStorage.
|
|
|
+ // When "cloning" a tab (e.g. via middle-click), the `active` flag will be set and we'll create
|
|
|
+ // a new empty user session, otherwise it'll be false and we can re-use the user session.
|
|
|
'active': true
|
|
|
});
|
|
|
// Set JID on the connection object so that when we call `connection.bind`
|
|
@@ -1330,10 +1252,6 @@ function saveJIDtoSession (jid) {
|
|
|
* @params { String } jid
|
|
|
*/
|
|
|
_converse.setUserJID = async function (jid) {
|
|
|
- if (!_converse.connection || !u.isSameDomain(_converse.connection.jid, jid)) {
|
|
|
- const domain = Strophe.getDomainFromJid(jid)
|
|
|
- await _converse.initConnection(domain);
|
|
|
- }
|
|
|
await initSession(jid);
|
|
|
/**
|
|
|
* Triggered whenever the user's JID has been updated
|
|
@@ -1405,95 +1323,6 @@ function cleanup () {
|
|
|
_converse.off();
|
|
|
}
|
|
|
|
|
|
-_converse.generateResource = () => `/converse.js-${Math.floor(Math.random()*139749528).toString()}`;
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * Callback method called by Strophe as the Strophe.Connection goes
|
|
|
- * through various states while establishing or tearing down a
|
|
|
- * connection.
|
|
|
- * @method _converse#onConnectStatusChanged
|
|
|
- * @private
|
|
|
- * @memberOf _converse
|
|
|
- */
|
|
|
-_converse.onConnectStatusChanged = function (status, message) {
|
|
|
- log.debug(`Status changed to: ${_converse.CONNECTION_STATUS[status]}`);
|
|
|
- if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
|
|
|
- _converse.setConnectionStatus(status);
|
|
|
- // By default we always want to send out an initial presence stanza.
|
|
|
- _converse.send_initial_presence = true;
|
|
|
- _converse.setDisconnectionCause();
|
|
|
- if (_converse.connection.reconnecting) {
|
|
|
- log.debug(status === Strophe.Status.CONNECTED ? 'Reconnected' : 'Reattached');
|
|
|
- onConnected(true);
|
|
|
- } else {
|
|
|
- log.debug(status === Strophe.Status.CONNECTED ? 'Connected' : 'Attached');
|
|
|
- if (_converse.connection.restored) {
|
|
|
- // No need to send an initial presence stanza when
|
|
|
- // we're restoring an existing session.
|
|
|
- _converse.send_initial_presence = false;
|
|
|
- }
|
|
|
- onConnected();
|
|
|
- }
|
|
|
- } else if (status === Strophe.Status.DISCONNECTED) {
|
|
|
- _converse.setDisconnectionCause(status, message);
|
|
|
- _converse.onDisconnected();
|
|
|
- } else if (status === Strophe.Status.BINDREQUIRED) {
|
|
|
- _converse.bindResource();
|
|
|
- } else if (status === Strophe.Status.ERROR) {
|
|
|
- _converse.setConnectionStatus(
|
|
|
- status,
|
|
|
- __('An error occurred while connecting to the chat server.')
|
|
|
- );
|
|
|
- } else if (status === Strophe.Status.CONNECTING) {
|
|
|
- _converse.setConnectionStatus(status);
|
|
|
- } else if (status === Strophe.Status.AUTHENTICATING) {
|
|
|
- _converse.setConnectionStatus(status);
|
|
|
- } else if (status === Strophe.Status.AUTHFAIL) {
|
|
|
- if (!message) {
|
|
|
- message = __('Your XMPP address and/or password is incorrect. Please try again.');
|
|
|
- }
|
|
|
- _converse.setConnectionStatus(status, message);
|
|
|
- _converse.setDisconnectionCause(status, message, true);
|
|
|
- _converse.onDisconnected();
|
|
|
- } else if (status === Strophe.Status.CONNFAIL) {
|
|
|
- let feedback = message;
|
|
|
- if (message === "host-unknown" || message == "remote-connection-failed") {
|
|
|
- feedback = __("Sorry, we could not connect to the XMPP host with domain: %1$s",
|
|
|
- `\"${Strophe.getDomainFromJid(_converse.connection.jid)}\"`);
|
|
|
- } else if (message !== undefined && message === Strophe?.ErrorCondition?.NO_AUTH_MECH) {
|
|
|
- feedback = __("The XMPP server did not offer a supported authentication mechanism");
|
|
|
- }
|
|
|
- _converse.setConnectionStatus(status, feedback);
|
|
|
- _converse.setDisconnectionCause(status, message);
|
|
|
- } else if (status === Strophe.Status.DISCONNECTING) {
|
|
|
- _converse.setDisconnectionCause(status, message);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-_converse.setConnectionStatus = function (connection_status, message) {
|
|
|
- _converse.connfeedback.set({
|
|
|
- 'connection_status': connection_status,
|
|
|
- 'message': message
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * Used to keep track of why we got disconnected, so that we can
|
|
|
- * decide on what the next appropriate action is (in onDisconnected)
|
|
|
- */
|
|
|
-_converse.setDisconnectionCause = function (cause, reason, override) {
|
|
|
- if (cause === undefined) {
|
|
|
- delete _converse.disconnection_cause;
|
|
|
- delete _converse.disconnection_reason;
|
|
|
- } else if (_converse.disconnection_cause === undefined || override) {
|
|
|
- _converse.disconnection_cause = cause;
|
|
|
- _converse.disconnection_reason = reason;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
|
|
|
function enableCarbons () {
|
|
|
/* Ask the XMPP server to enable Message Carbons
|
|
@@ -1519,65 +1348,7 @@ function enableCarbons () {
|
|
|
_converse.connection.send(carbons_iq);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-async function onConnected (reconnecting) {
|
|
|
- /* Called as soon as a new connection has been established, either
|
|
|
- * by logging in or by attaching to an existing BOSH session.
|
|
|
- */
|
|
|
- delete _converse.connection.reconnecting;
|
|
|
- _converse.connection.flush(); // Solves problem of returned PubSub BOSH response not received by browser
|
|
|
- await _converse.setUserJID(_converse.connection.jid);
|
|
|
-
|
|
|
- /**
|
|
|
- * Synchronous event triggered after we've sent an IQ to bind the
|
|
|
- * user's JID resource for this session.
|
|
|
- * @event _converse#afterResourceBinding
|
|
|
- */
|
|
|
- await api.trigger('afterResourceBinding', reconnecting, {'synchronous': true});
|
|
|
- enableCarbons();
|
|
|
-
|
|
|
- if (reconnecting) {
|
|
|
- /**
|
|
|
- * After the connection has dropped and converse.js has reconnected.
|
|
|
- * Any Strophe stanza handlers (as registered via `converse.listen.stanza`) will
|
|
|
- * have to be registered anew.
|
|
|
- * @event _converse#reconnected
|
|
|
- * @example _converse.api.listen.on('reconnected', () => { ... });
|
|
|
- */
|
|
|
- api.trigger('reconnected');
|
|
|
- } else {
|
|
|
- /**
|
|
|
- * Triggered once converse.js has been initialized.
|
|
|
- * See also {@link _converse#event:pluginsInitialized}.
|
|
|
- * @event _converse#initialized
|
|
|
- */
|
|
|
- api.trigger('initialized');
|
|
|
- /**
|
|
|
- * Triggered after the connection has been established and Converse
|
|
|
- * has got all its ducks in a row.
|
|
|
- * @event _converse#initialized
|
|
|
- */
|
|
|
- api.trigger('connected');
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-async function finishDisconnection () {
|
|
|
- // Properly tear down the session so that it's possible to manually connect again.
|
|
|
- log.debug('DISCONNECTED');
|
|
|
- delete _converse.connection.reconnecting;
|
|
|
- _converse.connection.reset();
|
|
|
- tearDown();
|
|
|
- await clearSession();
|
|
|
- delete _converse.connection;
|
|
|
- /**
|
|
|
- * Triggered after converse.js has disconnected from the XMPP server.
|
|
|
- * @event _converse#disconnected
|
|
|
- * @memberOf _converse
|
|
|
- * @example _converse.api.listen.on('disconnected', () => { ... });
|
|
|
- */
|
|
|
- api.trigger('disconnected');
|
|
|
-}
|
|
|
+api.listen.on('afterResourceBinding', () => enableCarbons());
|
|
|
|
|
|
|
|
|
function fetchLoginCredentials (wait=0) {
|
|
@@ -1659,55 +1430,6 @@ function unregisterGlobalEventHandlers () {
|
|
|
}
|
|
|
|
|
|
|
|
|
-/**
|
|
|
- * Gets called once strophe's status reaches Strophe.Status.DISCONNECTED.
|
|
|
- * Will either start a teardown process for converse.js or attempt
|
|
|
- * to reconnect.
|
|
|
- * @method onDisconnected
|
|
|
- * @private
|
|
|
- * @memberOf _converse
|
|
|
- */
|
|
|
-_converse.onDisconnected = function () {
|
|
|
- if (api.settings.get("auto_reconnect")) {
|
|
|
- const reason = _converse.disconnection_reason;
|
|
|
- if (_converse.disconnection_cause === Strophe.Status.AUTHFAIL) {
|
|
|
- if (api.settings.get("credentials_url") || api.settings.get("authentication") === _converse.ANONYMOUS) {
|
|
|
- // If `credentials_url` is set, we reconnect, because we might
|
|
|
- // be receiving expirable tokens from the credentials_url.
|
|
|
- //
|
|
|
- // If `authentication` is anonymous, we reconnect because we
|
|
|
- // might have tried to attach with stale BOSH session tokens
|
|
|
- // or with a cached JID and password
|
|
|
- return api.connection.reconnect();
|
|
|
- } else {
|
|
|
- return finishDisconnection();
|
|
|
- }
|
|
|
- } else if (
|
|
|
- _converse.disconnection_cause === _converse.LOGOUT ||
|
|
|
- reason === Strophe.ErrorCondition.NO_AUTH_MECH ||
|
|
|
- reason === "host-unknown" ||
|
|
|
- reason === "remote-connection-failed"
|
|
|
- ) {
|
|
|
- return finishDisconnection();
|
|
|
- }
|
|
|
- api.connection.reconnect();
|
|
|
- } else {
|
|
|
- return finishDisconnection();
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-_converse.bindResource = async function () {
|
|
|
- /**
|
|
|
- * Synchronous event triggered before we send an IQ to bind the user's
|
|
|
- * JID resource for this session.
|
|
|
- * @event _converse#beforeResourceBinding
|
|
|
- */
|
|
|
- await api.trigger('beforeResourceBinding', {'synchronous': true});
|
|
|
- _converse.connection.bind();
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
_converse.ConnectionFeedback = Model.extend({
|
|
|
defaults: {
|
|
|
'connection_status': Strophe.Status.DISCONNECTED,
|