您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ResumeTask.js 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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._resumeRetryN += 1;
  44. this._networkOnlineListener
  45. = NetworkInfo.addEventListener(
  46. NETWORK_INFO_EVENT,
  47. ({ isOnline }) => {
  48. if (isOnline) {
  49. this._scheduleResume();
  50. } else {
  51. this._cancelResume();
  52. }
  53. });
  54. NetworkInfo.isOnline() && this._scheduleResume();
  55. }
  56. /**
  57. * Schedules a delayed timeout which will execute the resume action.
  58. * @private
  59. * @returns {void}
  60. */
  61. _scheduleResume() {
  62. if (this._resumeTimeout) {
  63. // NO-OP
  64. return;
  65. }
  66. // The retry delay will be:
  67. // 1st retry: 1.5s - 3s
  68. // 2nd retry: 3s - 9s
  69. // 3rd and next retry: 4.5s - 27s
  70. this._resumeRetryN = Math.min(3, this._resumeRetryN);
  71. this._retryDelay = getJitterDelay(
  72. /* retry */ this._resumeRetryN,
  73. /* minDelay */ this._resumeRetryN * 1500,
  74. 3);
  75. logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);
  76. this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);
  77. }
  78. /**
  79. * Cancels the delayed resume task.
  80. *
  81. * @private
  82. * @returns {void}
  83. */
  84. _cancelResume() {
  85. if (this._resumeTimeout) {
  86. logger.info('Canceling connection resume task');
  87. clearTimeout(this._resumeTimeout);
  88. this._resumeTimeout = undefined;
  89. this._retryDelay = undefined;
  90. }
  91. }
  92. /**
  93. * Resumes the XMPP connection using the stream management plugin.
  94. *
  95. * @private
  96. * @returns {void}
  97. */
  98. _resumeConnection() {
  99. const { streamManagement } = this._stropheConn;
  100. const resumeToken = streamManagement.getResumeToken();
  101. // Things may have changed since when the task was scheduled
  102. if (!resumeToken) {
  103. return;
  104. }
  105. logger.info('Trying to resume the XMPP connection');
  106. const url = new URL(this._stropheConn.service);
  107. let { search } = url;
  108. const pattern = /(previd=)([\w-]+)/;
  109. const oldToken = search.match(pattern);
  110. // Replace previd if the previd value has changed.
  111. if (oldToken && oldToken.indexOf(resumeToken) === -1) {
  112. search = search.replace(pattern, `$1${resumeToken}`);
  113. // Append previd if it doesn't exist.
  114. } else if (!oldToken) {
  115. search += search.indexOf('?') === -1 ? `?previd=${resumeToken}` : `&previd=${resumeToken}`;
  116. }
  117. url.search = search;
  118. this._stropheConn.service = url.toString();
  119. streamManagement.resume();
  120. }
  121. /**
  122. * Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for
  123. * example when the disconnect method is called.
  124. *
  125. * @returns {void}
  126. */
  127. cancel() {
  128. this._cancelResume();
  129. this._resumeRetryN = 0;
  130. if (this._networkOnlineListener) {
  131. this._networkOnlineListener();
  132. this._networkOnlineListener = null;
  133. }
  134. }
  135. }