quickblox 2.24.1-alpha.0 → 2.24.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,13 @@ var chatUtils = require('./qbChatHelpers'),
11
11
 
12
12
  var unsupportedError = 'This function isn\'t supported outside of the browser (...yet)';
13
13
 
14
+ /**
15
+ * [CROS-1061] How long to wait for the server to answer a Notice enable/disable
16
+ * IQ before reporting an error to the caller. Without a bound the callback is
17
+ * never invoked when the server stays silent.
18
+ */
19
+ var NOTICE_IQ_TIMEOUT_MS = 10000;
20
+
14
21
  var XMPP;
15
22
 
16
23
  /** create StropheJS or NodeXMPP connection object */
@@ -1852,6 +1859,22 @@ ChatProxy.prototype = {
1852
1859
  self._isConnecting = false;
1853
1860
  self._sessionHasExpired = false;
1854
1861
 
1862
+ // [CROS-1061] A new XMPP session never carries the previous session's
1863
+ // Notice subscription: the server binds <enable xmlns="urn:xmpp:notice:0"/>
1864
+ // to the stream, so it is gone once the stream is gone. Without this
1865
+ // reset the flag stays `true` after a transport reconnect while no
1866
+ // notices are delivered any more, and isNoticesEnabled() misleads the
1867
+ // application into skipping the re-enable (verified against a live
1868
+ // server: socket break -> reconnect -> flag true, zero notice stanzas;
1869
+ // clearing the flag and re-sending <enable> restored delivery).
1870
+ //
1871
+ // Placed in the shared preamble, above the isInitialConnect branch, and
1872
+ // above the onReconnectListener call below: with
1873
+ // config.pingLocalhostTimeInterval === 0 that listener fires
1874
+ // synchronously from this function, and a consumer re-enabling notices
1875
+ // from it must not observe a stale `true`.
1876
+ self._isNoticesEnabled = false;
1877
+
1855
1878
  self._enableCarbons();
1856
1879
 
1857
1880
  if (isInitialConnect) {
@@ -1862,7 +1885,6 @@ ChatProxy.prototype = {
1862
1885
  self._isConnectionVerified = true;
1863
1886
  self._isReconnectListenerPending = false;
1864
1887
 
1865
- // TODO(2.25.0): auto-enable Notice Feature here (see qbChat.js enableNotices JSDoc).
1866
1888
  self.roster.get(function (contacts) {
1867
1889
  xmppClient.send(presence);
1868
1890
 
@@ -1870,7 +1892,24 @@ ChatProxy.prototype = {
1870
1892
  callback(self.roster.contacts);
1871
1893
  });
1872
1894
  } else {
1895
+ // [CROS-1061] Union of the rooms still tracked on this instance and
1896
+ // the ones an explicit reconnect() had to drop. Consumed once —
1897
+ // clearing it here keeps a later session (or another user after
1898
+ // logout) from resurrecting a stale list.
1899
+ //
1900
+ // Safe to build the join stanzas at this point: setUserCurrentJid()
1901
+ // above has already installed the new JID, and muc.join() derives
1902
+ // the presence `from` out of it. Moving this block above that call
1903
+ // would send from="".
1873
1904
  var rooms = Object.keys(self.muc.joinedRooms);
1905
+ var remembered = self.muc._roomsToRejoin || [];
1906
+
1907
+ for (var r = 0; r < remembered.length; r++) {
1908
+ if (rooms.indexOf(remembered[r]) === -1) {
1909
+ rooms.push(remembered[r]);
1910
+ }
1911
+ }
1912
+ self.muc._roomsToRejoin = [];
1874
1913
 
1875
1914
  xmppClient.send(presence);
1876
1915
 
@@ -2093,6 +2132,11 @@ ChatProxy.prototype = {
2093
2132
  // connection had a chance to verify itself.
2094
2133
  this._isConnectionVerified = false;
2095
2134
  this._isReconnectListenerPending = false;
2135
+ // [CROS-1061] Remember the rooms before dropping them, so the re-join
2136
+ // loop in _postConnectActions has something to restore. Without this the
2137
+ // list is lost and group dialogs stop receiving message-level notices
2138
+ // until the page is reloaded.
2139
+ this.muc._roomsToRejoin = Object.keys(this.muc.joinedRooms);
2096
2140
  this.muc.joinedRooms = {};
2097
2141
  this.helpers.setUserCurrentJid('');
2098
2142
 
@@ -2486,6 +2530,9 @@ ChatProxy.prototype = {
2486
2530
  this._checkConnectionTimer = undefined;
2487
2531
  this._checkExpiredSessionTimer = undefined;
2488
2532
  this.muc.joinedRooms = {};
2533
+ // [CROS-1061] Never carry rooms across a logout: re-joining the previous
2534
+ // user's rooms from a new JID is answered with 403/407 by the server.
2535
+ this.muc._roomsToRejoin = [];
2489
2536
  // [QC-1550] Reset XMPP verification state on explicit disconnect so the
2490
2537
  // next connect() starts from a clean slate. _isLogout guard below also
2491
2538
  // prevents firing of deferred listeners if a pong arrives in flight,
@@ -2520,17 +2567,26 @@ ChatProxy.prototype = {
2520
2567
  * NoticeCreatedDialog / NoticeUpdatedDialog / NoticeDeletedDialog
2521
2568
  * headline stanzas.
2522
2569
  *
2523
- * The local enabled flag is reset to false on chat disconnect — consumers
2524
- * must call enableNotices() again after a reconnect (intentional divergence
2525
- * from the Android SDK, which auto-restores the subscription).
2570
+ * The subscription belongs to the XMPP session, so it does not survive a
2571
+ * reconnect: the local enabled flag is reset to false whenever a new session
2572
+ * is established (initial connect and every reconnect alike) as well as on
2573
+ * disconnect. Consumers must call enableNotices() again after a reconnect —
2574
+ * an intentional divergence from the Android SDK, which auto-restores the
2575
+ * subscription. Reacting to onReconnectListener is the supported way to do
2576
+ * that.
2526
2577
  *
2527
- * TODO(2.25.0): make auto-enable SDK-internal — fire on initial connect and
2528
- * on relogin after session-expired, skip on Stream-Management reconnect.
2529
- * Spec & three-state matrix are tracked in the internal 2.25.0 backlog
2530
- * (auto-enable notices).
2578
+ * Concurrent calls are safe: each IQ carries its own unique id, responses
2579
+ * are dispatched per id, and the flag is set independently for each result.
2580
+ * Calling enableNotices() again before the previous callback fires is
2581
+ * therefore allowed — for example when a second reconnect arrives while the
2582
+ * first enable is still in flight.
2531
2583
  *
2532
- * Do not call enableNotices again before the previous callback fires —
2533
- * concurrent enable calls are not specified.
2584
+ * If the server does not answer, the callback receives an error after a
2585
+ * timeout instead of never being called.
2586
+ *
2587
+ * TODO(2.25.0): make auto-enable SDK-internal — fire on initial connect and
2588
+ * on every reconnect. Spec & three-state matrix are tracked in the internal
2589
+ * 2.25.0 backlog (auto-enable notices).
2534
2590
  *
2535
2591
  * @memberof QB.chat
2536
2592
  * @param {enableNoticesCallback} callback - Called with (error, result) on IQ result.
@@ -2569,7 +2625,10 @@ ChatProxy.prototype = {
2569
2625
  * Returns the local Notice Feature subscription flag.
2570
2626
  * @memberof QB.chat
2571
2627
  * @return {Boolean} true after a successful enableNotices(), false otherwise.
2572
- * Reset to false on chat disconnect; not synchronized with the server.
2628
+ * Reset to false on disconnect and whenever a new XMPP session is
2629
+ * established, so after a reconnect it reports false until the consumer
2630
+ * enables notices again. Not synchronized with the server: it reflects
2631
+ * what this client last requested, not the server's own state.
2573
2632
  * @since 2.24.0
2574
2633
  */
2575
2634
  isNoticesEnabled: function () {
@@ -2622,10 +2681,34 @@ ChatProxy.prototype = {
2622
2681
  }
2623
2682
 
2624
2683
  if (Utils.getEnv().browser) {
2625
- self.connection.sendIQ(iq, _onSuccess, _onError);
2684
+ // [CROS-1061] Without the 4th argument Strophe never times the IQ out,
2685
+ // so a server that stays silent leaves the caller without any callback
2686
+ // at all — the application spins forever. On timeout Strophe calls
2687
+ // _onError(null), which reports a 'cancel' error and leaves the flag
2688
+ // untouched.
2689
+ //
2690
+ // Note: this covers "server does not answer". It does NOT cover
2691
+ // "socket died", because the timeout is an addTimedHandler and
2692
+ // connection.reset() (called from the DISCONNECTED branch) clears
2693
+ // timedHandlers. That case is covered by the consumer-side timeout.
2694
+ self.connection.sendIQ(iq, _onSuccess, _onError, NOTICE_IQ_TIMEOUT_MS);
2626
2695
  } else {
2627
2696
  // Node/NativeScript path: register callback in nodeStanzasCallbacks map.
2697
+ // This path does not go through sendIQ, so the timeout is ours to run.
2698
+ var noticeIqTimer = setTimeout(function () {
2699
+ // Drop the pending entry first: _onIQ only dispatches while the
2700
+ // entry exists, so a late answer after this point is ignored
2701
+ // instead of invoking the callback a second time.
2702
+ delete self.nodeStanzasCallbacks[iqParams.id];
2703
+ _onError(null);
2704
+ }, NOTICE_IQ_TIMEOUT_MS);
2705
+
2628
2706
  self.nodeStanzasCallbacks[iqParams.id] = function (stanza) {
2707
+ // Must be first: otherwise a timely answer still leaves the timer
2708
+ // armed, and it would fire later and call the callback a second
2709
+ // time with an error.
2710
+ clearTimeout(noticeIqTimer);
2711
+
2629
2712
  // The map handler receives the result/error stanza. Inspect type to dispatch.
2630
2713
  var iqType = chatUtils.getAttr(stanza, 'type');
2631
2714
  if (iqType === 'result') {
@@ -2954,6 +3037,20 @@ function MucProxy(options) {
2954
3037
  this.nodeStanzasCallbacks = options.nodeStanzasCallbacks;
2955
3038
  //
2956
3039
  this.joinedRooms = {};
3040
+
3041
+ /**
3042
+ * [CROS-1061] Rooms carried across an explicit QB.chat.reconnect().
3043
+ *
3044
+ * reconnect() has to clear joinedRooms — the new session holds no presence
3045
+ * yet — but until now it dropped the list without keeping a copy, so the
3046
+ * re-join loop in _postConnectActions found nothing to restore and group
3047
+ * dialogs silently stopped receiving message-level notices.
3048
+ *
3049
+ * Written only by reconnect(), read and cleared once by _postConnectActions,
3050
+ * and cleared by disconnect() so one user's rooms can never be re-joined
3051
+ * from another user's JID.
3052
+ */
3053
+ this._roomsToRejoin = [];
2957
3054
  }
2958
3055
 
2959
3056
  MucProxy.prototype = {
package/src/qbConfig.js CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  var config = {
15
- version: '2.24.1-alpha.0',
15
+ version: '2.24.1-alpha.1',
16
16
  buildNumber: '1181',
17
17
  creds: {
18
18
  'appId': 0,