Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

strophe.ping.js 5.8KB

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