選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

strophe.ping.js 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. * Ping every 10 sec
  8. */
  9. const PING_INTERVAL = 10000;
  10. /**
  11. * Ping timeout error after 5 sec of waiting.
  12. */
  13. const PING_TIMEOUT = 5000;
  14. /**
  15. * 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_THRESHOLD = 2;
  20. /**
  21. * The number of timestamps of send pings to keep.
  22. * The current value is 2 minutes.
  23. * @type {number} number of timestamps.
  24. */
  25. const PING_TIMESTAMPS_TO_KEEP = 120000 / PING_INTERVAL;
  26. /**
  27. * XEP-0199 ping plugin.
  28. *
  29. * Registers "urn:xmpp:ping" namespace under Strophe.NS.PING.
  30. */
  31. export default class PingConnectionPlugin extends ConnectionPlugin {
  32. /**
  33. * Contructs new object
  34. * @param {Object} options
  35. * @param {Function} options.onPingThresholdExceeded - Callback called when ping fails too many times (controlled
  36. * by the {@link PING_THRESHOLD} constant).
  37. * @constructor
  38. */
  39. constructor({ onPingThresholdExceeded }) {
  40. super();
  41. this.failedPings = 0;
  42. this.pingExecIntervals = new Array(PING_TIMESTAMPS_TO_KEEP);
  43. this._onPingThresholdExceeded = onPingThresholdExceeded;
  44. }
  45. /**
  46. * Initializes the plugin. Method called by Strophe.
  47. * @param connection Strophe connection instance.
  48. */
  49. init(connection) {
  50. super.init(connection);
  51. Strophe.addNamespace('PING', 'urn:xmpp:ping');
  52. }
  53. /* eslint-disable max-params */
  54. /**
  55. * Sends "ping" to given <tt>jid</tt>
  56. * @param jid the JID to which ping request will be sent.
  57. * @param success callback called on success.
  58. * @param error callback called on error.
  59. * @param timeout ms how long are we going to wait for the response. On
  60. * timeout <tt>error<//t> callback is called with undefined error argument.
  61. */
  62. ping(jid, success, error, timeout) {
  63. this._addPingExecutionTimestamp();
  64. const iq = $iq({
  65. type: 'get',
  66. to: jid
  67. });
  68. iq.c('ping', { xmlns: Strophe.NS.PING });
  69. this.connection.sendIQ2(iq, { timeout })
  70. .then(success, error);
  71. }
  72. /* eslint-enable max-params */
  73. /**
  74. * Starts to send ping in given interval to specified remote JID.
  75. * This plugin supports only one such task and <tt>stopInterval</tt>
  76. * must be called before starting a new one.
  77. * @param remoteJid remote JID to which ping requests will be sent to.
  78. * @param interval task interval in ms.
  79. */
  80. startInterval(remoteJid, interval = PING_INTERVAL) {
  81. clearInterval(this.intervalId);
  82. this.intervalId = window.setInterval(() => {
  83. this.ping(remoteJid, () => {
  84. this.failedPings = 0;
  85. }, error => {
  86. this.failedPings += 1;
  87. const errmsg = `Ping ${error ? 'error' : 'timeout'}`;
  88. if (this.failedPings >= PING_THRESHOLD) {
  89. GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));
  90. logger.error(errmsg, error);
  91. this._onPingThresholdExceeded && this._onPingThresholdExceeded();
  92. } else {
  93. logger.warn(errmsg, error);
  94. }
  95. }, PING_TIMEOUT);
  96. }, interval);
  97. logger.info(`XMPP pings will be sent every ${interval} ms`);
  98. }
  99. /**
  100. * Stops current "ping" interval task.
  101. */
  102. stopInterval() {
  103. if (this.intervalId) {
  104. window.clearInterval(this.intervalId);
  105. this.intervalId = null;
  106. this.failedPings = 0;
  107. logger.info('Ping interval cleared');
  108. }
  109. }
  110. /**
  111. * Adds the current time to the array of send ping timestamps.
  112. * @private
  113. */
  114. _addPingExecutionTimestamp() {
  115. this.pingExecIntervals.push(new Date().getTime());
  116. // keep array length to PING_TIMESTAMPS_TO_KEEP
  117. if (this.pingExecIntervals.length > PING_TIMESTAMPS_TO_KEEP) {
  118. this.pingExecIntervals.shift();
  119. }
  120. }
  121. /**
  122. * Returns the maximum time between the recent sent pings, if there is a
  123. * big value it means the computer was inactive for some time(suspended).
  124. * Checks the maximum gap between sending pings, considering and the
  125. * current time. Trying to detect computer inactivity (sleep).
  126. *
  127. * @returns {int} the time ping was suspended, if it was not 0 is returned.
  128. */
  129. getPingSuspendTime() {
  130. const pingIntervals = this.pingExecIntervals.slice();
  131. // we need current time, as if ping was sent now
  132. // if computer sleeps we will get correct interval after next
  133. // scheduled ping, bet we sometimes need that interval before waiting
  134. // for the next ping, on closing the connection on error.
  135. pingIntervals.push(new Date().getTime());
  136. let maxInterval = 0;
  137. let previousTS = pingIntervals[0];
  138. pingIntervals.forEach(e => {
  139. const currentInterval = e - previousTS;
  140. if (currentInterval > maxInterval) {
  141. maxInterval = currentInterval;
  142. }
  143. previousTS = e;
  144. });
  145. // remove the interval between the ping sent
  146. // this way in normal execution there is no suspend and the return
  147. // will be 0 or close to 0.
  148. maxInterval -= PING_INTERVAL;
  149. // make sure we do not return less than 0
  150. return Math.max(maxInterval, 0);
  151. }
  152. }