diff --git a/docs/CHANGES.md b/docs/CHANGES.md index 26ff9fc7c..fa9301476 100755 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -10,6 +10,11 @@ collection has its `browserStorage` configured. Causes `Error: A "url" property or function must be specified`. [jcbrand] - Don't open the controlbox on contact requests. [jcbrand] +- Bugfix: Reconnection fails when original connection was never established. [jcbrand] +- If a `credentials_url` is provided, then keep on attempting to reconnect when connection is down. [jcbrand] +- Remove (undocumented) `callback` config parameter for `converse.initialize`. + Instead, `converse.initialize` returns a promise which will resolve once + initialization is complete. [jcbrand] ## 2.0.1 (2016-11-07) - #203 New configuration setting [muc_domain](https://conversejs.org/docs/html/configuration.html#muc_domain) [jcbrand] diff --git a/src/converse-core.js b/src/converse-core.js index 225acbe60..abccad129 100755 --- a/src/converse-core.js +++ b/src/converse-core.js @@ -396,11 +396,7 @@ converse.connection.disconnect('re-connecting'); converse.connection.reset(); converse._tearDown(); - if (converse.authentication !== "prebind") { - converse.autoLogin(); - } else if (converse.prebind_url) { - converse.startNewBOSHSession(); - } + converse.logIn(null, true); }, 1000); this.onDisconnected = function (condition) { @@ -440,7 +436,7 @@ delete converse.disconnection_cause; if (converse.connection.reconnecting) { converse.log(status === Strophe.Status.CONNECTED ? 'Reconnected' : 'Reattached'); - converse.onReconnected(); + converse.onConnected(true); } else { converse.log(status === Strophe.Status.CONNECTED ? 'Connected' : 'Attached'); if (converse.connection.restored) { @@ -666,19 +662,33 @@ } }; - this.onStatusInitialized = function () { - converse.registerIntervalHandler(); - converse.initRoster(); + this.onStatusInitialized = function (reconnecting) { + /* Continue with session establishment (e.g. fetching chat boxes, + * populating the roster etc.) necessary once the connection has + * been established. + */ + if (reconnecting) { + // No need to recreate the roster, otherwise we lose our + // cached data. However we still emit an event, to give + // event handlers a chance to register views for the + // roster and its groups, before we start populating. + converse.emit('rosterReadyAfterReconnection'); + } else { + converse.registerIntervalHandler(); + converse.initRoster(); + } + // First set up chat boxes, before populating the roster, so that + // the controlbox is properly set up and ready for the rosterview. converse.chatboxes.onConnected(); converse.populateRoster(); converse.registerPresenceHandler(); converse.giveFeedback(__('Contacts')); - if (typeof converse.callback === 'function') { - // XXX: Deprecate in favor of init_deferred - converse.callback(); + if (reconnecting) { + converse.xmppstatus.sendPresence(); + } else { + init_deferred.resolve(); + converse.emit('initialized'); } - init_deferred.resolve(); - converse.emit('initialized'); }; this.setUserJid = function () { @@ -688,52 +698,33 @@ converse.domain = Strophe.getDomainFromJid(converse.connection.jid); }; - this.onConnected = function (callback) { + this.onConnected = function (reconnecting) { /* Called as soon as a new connection has been established, either * by logging in or by attaching to an existing BOSH session. */ - // XXX: ran into an issue where a returned PubSub BOSH response was - // not received by the browser. The solution was to flush the - // connection early on. I don't know what the underlying cause of - // this issue is, and whether it's a Strophe.js or Prosody bug. - // My suspicion is that Prosody replies to an invalid/expired - // Request, which is why the browser then doesn't receive it. - // In any case, flushing here (sending out a new BOSH request) - // solves the problem. + // Solves problem of returned PubSub BOSH response not received + // by browser. converse.connection.flush(); - // When reconnecting, there might be some open chat boxes. We don't - // know whether these boxes are of the same account or not, so we - // close them now. - converse.chatboxviews.closeAllChatBoxes(); - converse.setUserJid(); - converse.features = new converse.Features(); - converse.enableCarbons(); - converse.initStatus().done(converse.onStatusInitialized); - converse.emit('connected'); - converse.emit('ready'); // BBB: Will be removed. - }; - this.onReconnected = function () { - /* Called when converse has succesfully reconnected to the XMPP - * server after the session was dropped. - * Similar to the `onConnected` method, but skips a few unnecessary - * steps. - */ converse.setUserJid(); - converse.registerPresenceHandler(); - converse.chatboxes.registerMessageHandler(); - if (_.isUndefined(converse.roster)) { - converse.initRoster(); + converse.enableCarbons(); + + // If there's no xmppstatus obj, then we were never connected to + // begin with, so we set reconnecting to false. + reconnecting = _.isUndefined(converse.xmppstatus) ? false : reconnecting; + + if (reconnecting) { + converse.onStatusInitialized(true); + converse.emit('reconnected'); } else { - // Give event handlers a chance to register views for the - // roster and its groups, before we start populating. - converse.emit('rosterReadyAfterReconnection'); + // There might be some open chat boxes. We don't + // know whether these boxes are of the same account or not, so we + // close them now. + converse.chatboxviews.closeAllChatBoxes(); + converse.features = new converse.Features(); + converse.initStatus().done(_.partial(converse.onStatusInitialized, false)); + converse.emit('connected'); } - converse.chatboxes.onConnected(); - converse.populateRoster(); - converse.xmppstatus.sendPresence(); - converse.emit('reconnected'); - converse.giveFeedback(__('Contacts')); }; this.RosterContact = Backbone.Model.extend({ @@ -1777,10 +1768,10 @@ }); }; - this.attemptPreboundSession = function (tokens) { + this.attemptPreboundSession = function (reconnecting) { /* Handle session resumption or initialization when prebind is being used. */ - if (this.keepalive) { + if (!reconnecting && this.keepalive) { if (!this.jid) { throw new Error("attemptPreboundSession: when using 'keepalive' with 'prebind, "+ "you must supply the JID of the current user."); @@ -1794,7 +1785,7 @@ } // No keepalive, or session resumption has failed. - if (this.jid && this.sid && this.rid) { + if (!reconnecting && this.jid && this.sid && this.rid) { return this.connection.attach(this.jid, this.sid, this.rid, this.onConnectStatusChanged); } else if (this.prebind_url) { return this.startNewBOSHSession(); @@ -1841,14 +1832,14 @@ } }; - this.attemptNonPreboundSession = function (credentials) { + this.attemptNonPreboundSession = function (credentials, reconnecting) { /* Handle session resumption or initialization when prebind is not being used. * * Two potential options exist and are handled in this method: * 1. keepalive * 2. auto_login */ - if (this.keepalive) { + if (this.keepalive && !reconnecting) { try { return this.connection.restore(this.jid, this.onConnectStatusChanged); } catch (e) { @@ -1877,13 +1868,13 @@ } }; - this.logIn = function (credentials) { + this.logIn = function (credentials, reconnecting) { // We now try to resume or automatically set up a new session. // Otherwise the user will be shown a login form. if (this.authentication === converse.PREBIND) { - this.attemptPreboundSession(); + this.attemptPreboundSession(reconnecting); } else { - this.attemptNonPreboundSession(credentials); + this.attemptNonPreboundSession(credentials, reconnecting); } };