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

strophe.ping.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { getLogger } from 'jitsi-meet-logger';
  2. import { $iq, Strophe } from 'strophe.js';
  3. import GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
  4. import ConnectionPlugin from './ConnectionPlugin';
  5. const logger = getLogger(__filename);
  6. /**
  7. * Default ping every 10 sec
  8. */
  9. const PING_DEFAULT_INTERVAL = 10000;
  10. /**
  11. * Default ping timeout error after 5 sec of waiting.
  12. */
  13. const PING_DEFAULT_TIMEOUT = 5000;
  14. /**
  15. * Default value for how many ping failures will be tolerated before the WebSocket connection is killed.
  16. * The worst case scenario in case of ping timing out without a response is (25 seconds at the time of this writing):
  17. * PING_THRESHOLD * PING_INTERVAL + PING_TIMEOUT
  18. */
  19. const PING_DEFAULT_THRESHOLD = 2;
  20. /**
  21. * How often to send ping requests.
  22. */
  23. let pingInterval;
  24. /**
  25. * The time to wait for ping responses.
  26. */
  27. let pingTimeout;
  28. /**
  29. * How many ping failures will be tolerated before the connection is killed.
  30. */
  31. let pingThreshold;
  32. /**
  33. * XEP-0199 ping plugin.
  34. *
  35. * Registers "urn:xmpp:ping" namespace under Strophe.NS.PING.
  36. */
  37. export default class PingConnectionPlugin extends ConnectionPlugin {
  38. /**
  39. * Constructs new object
  40. * @param {Object} options
  41. * @param {Function} options.onPingThresholdExceeded - Callback called when ping fails too many times (controlled
  42. * by the {@link PING_THRESHOLD} constant).
  43. * @param {Function} options._getTimeSinceLastServerResponse - A function to obtain the last seen
  44. * response from the server.
  45. * @param {Object} options.pingOptions - The ping options if any.
  46. * @constructor
  47. */
  48. constructor({ getTimeSinceLastServerResponse, onPingThresholdExceeded, pingOptions = {} }) {
  49. super();
  50. this.failedPings = 0;
  51. this._onPingThresholdExceeded = onPingThresholdExceeded;
  52. this._getTimeSinceLastServerResponse = getTimeSinceLastServerResponse;
  53. this.pingInterval = typeof pingOptions.interval === 'number' ? pingOptions.interval : PING_DEFAULT_INTERVAL;
  54. this.pingTimeout = typeof pingOptions.timeout === 'number' ? pingOptions.timeout : PING_DEFAULT_TIMEOUT;
  55. this.pingThreshold = typeof pingOptions.threshold === 'number'
  56. ? pingOptions.threshold : PING_DEFAULT_THRESHOLD;
  57. // The number of timestamps of send pings to keep.
  58. // The current value is 2 minutes.
  59. this.pingTimestampsToKeep = Math.round(120000 / this.pingInterval);
  60. this.pingExecIntervals = new Array(this.pingTimestampsToKeep);
  61. }
  62. /**
  63. * Initializes the plugin. Method called by Strophe.
  64. * @param connection Strophe connection instance.
  65. */
  66. init(connection) {
  67. super.init(connection);
  68. Strophe.addNamespace('PING', 'urn:xmpp:ping');
  69. }
  70. /* eslint-disable max-params */
  71. /**
  72. * Sends "ping" to given <tt>jid</tt>
  73. * @param jid the JID to which ping request will be sent.
  74. * @param success callback called on success.
  75. * @param error callback called on error.
  76. * @param timeout ms how long are we going to wait for the response. On
  77. * timeout <tt>error<//t> callback is called with undefined error argument.
  78. */
  79. ping(jid, success, error, timeout) {
  80. this._addPingExecutionTimestamp();
  81. const iq = $iq({
  82. type: 'get',
  83. to: jid
  84. });
  85. iq.c('ping', { xmlns: Strophe.NS.PING });
  86. this.connection.sendIQ2(iq, { timeout })
  87. .then(success, error);
  88. }
  89. /* eslint-enable max-params */
  90. /**
  91. * Starts to send ping in given interval to specified remote JID.
  92. * This plugin supports only one such task and <tt>stopInterval</tt>
  93. * must be called before starting a new one.
  94. * @param remoteJid remote JID to which ping requests will be sent to.
  95. */
  96. startInterval(remoteJid) {
  97. clearInterval(this.intervalId);
  98. this.intervalId = window.setInterval(() => {
  99. // when there were some server responses in the interval since the last time we checked (_lastServerCheck)
  100. // let's skip the ping
  101. // server response is measured on raw input and ping response time is measured after all the xmpp
  102. // processing is done, and when the last server response is a ping there can be slight misalignment of the
  103. // times, we give it 100ms for that processing.
  104. if (this._getTimeSinceLastServerResponse() + 100 < new Date() - this._lastServerCheck) {
  105. // do this just to keep in sync the intervals so we can detect suspended device
  106. this._addPingExecutionTimestamp();
  107. this._lastServerCheck = new Date();
  108. this.failedPings = 0;
  109. return;
  110. }
  111. this.ping(remoteJid, () => {
  112. this._lastServerCheck = new Date();
  113. this.failedPings = 0;
  114. }, error => {
  115. this.failedPings += 1;
  116. const errmsg = `Ping ${error ? 'error' : 'timeout'}`;
  117. if (this.failedPings >= pingThreshold) {
  118. GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));
  119. logger.error(errmsg, error);
  120. this._onPingThresholdExceeded && this._onPingThresholdExceeded();
  121. } else {
  122. logger.warn(errmsg, error);
  123. }
  124. }, pingTimeout);
  125. }, this.pingInterval);
  126. logger.info(`XMPP pings will be sent every ${this.pingInterval} ms`);
  127. }
  128. /**
  129. * Stops current "ping" interval task.
  130. */
  131. stopInterval() {
  132. if (this.intervalId) {
  133. window.clearInterval(this.intervalId);
  134. this.intervalId = null;
  135. this.failedPings = 0;
  136. logger.info('Ping interval cleared');
  137. }
  138. }
  139. /**
  140. * Adds the current time to the array of send ping timestamps.
  141. * @private
  142. */
  143. _addPingExecutionTimestamp() {
  144. this.pingExecIntervals.push(new Date().getTime());
  145. // keep array length to PING_TIMESTAMPS_TO_KEEP
  146. if (this.pingExecIntervals.length > this.pingTimestampsToKeep) {
  147. this.pingExecIntervals.shift();
  148. }
  149. }
  150. /**
  151. * Returns the maximum time between the recent sent pings, if there is a
  152. * big value it means the computer was inactive for some time(suspended).
  153. * Checks the maximum gap between sending pings, considering and the
  154. * current time. Trying to detect computer inactivity (sleep).
  155. *
  156. * @returns {int} the time ping was suspended, if it was not 0 is returned.
  157. */
  158. getPingSuspendTime() {
  159. const pingIntervals = this.pingExecIntervals.slice();
  160. // we need current time, as if ping was sent now
  161. // if computer sleeps we will get correct interval after next
  162. // scheduled ping, bet we sometimes need that interval before waiting
  163. // for the next ping, on closing the connection on error.
  164. pingIntervals.push(new Date().getTime());
  165. let maxInterval = 0;
  166. let previousTS = pingIntervals[0];
  167. pingIntervals.forEach(e => {
  168. const currentInterval = e - previousTS;
  169. if (currentInterval > maxInterval) {
  170. maxInterval = currentInterval;
  171. }
  172. previousTS = e;
  173. });
  174. // remove the interval between the ping sent
  175. // this way in normal execution there is no suspend and the return
  176. // will be 0 or close to 0.
  177. maxInterval -= pingInterval;
  178. // make sure we do not return less than 0
  179. return Math.max(maxInterval, 0);
  180. }
  181. }