Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ResumeTask.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { getLogger } from '@jitsi/logger';
  2. import {
  3. NETWORK_INFO_EVENT,
  4. default as NetworkInfo
  5. } from '../connectivity/NetworkInfo';
  6. import { getJitterDelay } from '../util/Retry';
  7. const logger = getLogger(__filename);
  8. /**
  9. * The class contains the logic for triggering connection resume via XEP-0198 stream management.
  10. * It does two things, the first one is it tracks the internet online/offline status and it makes sure that
  11. * the reconnect is attempted only while online. The seconds thing is that it tracks the retry attempts and extends
  12. * the retry interval using the full jitter pattern.
  13. */
  14. export default class ResumeTask {
  15. /**
  16. * Initializes new {@code RetryTask}.
  17. * @param {Strophe.Connection} stropheConnection - The Strophe connection instance.
  18. */
  19. constructor(stropheConnection) {
  20. this._stropheConn = stropheConnection;
  21. /**
  22. * The counter increased before each resume retry attempt, used to calculate exponential backoff.
  23. * @type {number}
  24. * @private
  25. */
  26. this._resumeRetryN = 0;
  27. this._retryDelay = undefined;
  28. }
  29. /**
  30. * @returns {number|undefined} - How much the app will wait before trying to resume the XMPP connection. When
  31. * 'undefined' it means that no resume task was not scheduled.
  32. */
  33. get retryDelay() {
  34. return this._retryDelay;
  35. }
  36. /**
  37. * Called by {@link XmppConnection} when the connection drops and it's a signal it wants to schedule a reconnect.
  38. *
  39. * @returns {void}
  40. */
  41. schedule() {
  42. this._cancelResume();
  43. this._removeNetworkOnlineListener();
  44. this._resumeRetryN += 1;
  45. this._networkOnlineListener
  46. = NetworkInfo.addCancellableListener(
  47. NETWORK_INFO_EVENT,
  48. ({ isOnline }) => {
  49. if (isOnline) {
  50. this._scheduleResume();
  51. } else {
  52. this._cancelResume();
  53. }
  54. });
  55. NetworkInfo.isOnline() && this._scheduleResume();
  56. }
  57. /**
  58. * Schedules a delayed timeout which will execute the resume action.
  59. * @private
  60. * @returns {void}
  61. */
  62. _scheduleResume() {
  63. if (this._resumeTimeout) {
  64. // NO-OP
  65. return;
  66. }
  67. // The retry delay will be:
  68. // 1st retry: 1.5s - 3s
  69. // 2nd retry: 3s - 9s
  70. // 3rd and next retry: 4.5s - 27s
  71. this._resumeRetryN = Math.min(3, this._resumeRetryN);
  72. this._retryDelay = getJitterDelay(
  73. /* retry */ this._resumeRetryN,
  74. /* minDelay */ this._resumeRetryN * 1500,
  75. 3);
  76. logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);
  77. this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);
  78. }
  79. /**
  80. * Cancels the delayed resume task.
  81. *
  82. * @private
  83. * @returns {void}
  84. */
  85. _cancelResume() {
  86. if (this._resumeTimeout) {
  87. logger.info('Canceling connection resume task');
  88. clearTimeout(this._resumeTimeout);
  89. this._resumeTimeout = undefined;
  90. this._retryDelay = undefined;
  91. }
  92. }
  93. /**
  94. * Removes network online listener for the NETWORK_INFO_EVENT event.
  95. *
  96. * @private
  97. * @returns {void}
  98. */
  99. _removeNetworkOnlineListener() {
  100. if (this._networkOnlineListener) {
  101. this._networkOnlineListener();
  102. this._networkOnlineListener = null;
  103. }
  104. }
  105. /**
  106. * Resumes the XMPP connection using the stream management plugin.
  107. *
  108. * @private
  109. * @returns {void}
  110. */
  111. _resumeConnection() {
  112. this._resumeTimeout = undefined;
  113. const { streamManagement } = this._stropheConn;
  114. const resumeToken = streamManagement.getResumeToken();
  115. // Things may have changed since when the task was scheduled
  116. if (!resumeToken) {
  117. return;
  118. }
  119. logger.info('Trying to resume the XMPP connection');
  120. const url = new URL(this._stropheConn.service);
  121. let { search } = url;
  122. const pattern = /(previd=)([\w-]+)/;
  123. const oldToken = search.match(pattern);
  124. // Replace previd if the previd value has changed.
  125. if (oldToken && oldToken.indexOf(resumeToken) === -1) {
  126. search = search.replace(pattern, `$1${resumeToken}`);
  127. // Append previd if it doesn't exist.
  128. } else if (!oldToken) {
  129. search += search.indexOf('?') === -1 ? `?previd=${resumeToken}` : `&previd=${resumeToken}`;
  130. }
  131. url.search = search;
  132. this._stropheConn.service = url.toString();
  133. try {
  134. streamManagement.resume();
  135. } catch (e) {
  136. logger.error('Failed to resume XMPP connnection', e);
  137. }
  138. }
  139. /**
  140. * Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for
  141. * example when the disconnect method is called.
  142. *
  143. * @returns {void}
  144. */
  145. cancel() {
  146. this._cancelResume();
  147. this._removeNetworkOnlineListener();
  148. this._resumeRetryN = 0;
  149. }
  150. }