You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strophe.ping.js 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* global $, $iq, Strophe */
  2. import {getLogger} from "jitsi-meet-logger";
  3. const logger = getLogger(__filename);
  4. import GlobalOnErrorHandler from "../util/GlobalOnErrorHandler";
  5. import XMPPEvents from "../../service/xmpp/XMPPEvents";
  6. import ConnectionPlugin from "./ConnectionPlugin";
  7. /**
  8. * Ping every 10 sec
  9. */
  10. const PING_INTERVAL = 10000;
  11. /**
  12. * Ping timeout error after 15 sec of waiting.
  13. */
  14. const PING_TIMEOUT = 15000;
  15. /**
  16. * Will close the connection after 3 consecutive ping errors.
  17. */
  18. const PING_THRESHOLD = 3;
  19. /**
  20. * XEP-0199 ping plugin.
  21. *
  22. * Registers "urn:xmpp:ping" namespace under Strophe.NS.PING.
  23. */
  24. class PingConnectionPlugin extends ConnectionPlugin {
  25. constructor() {
  26. super();
  27. this.failedPings = 0;
  28. }
  29. /**
  30. * Initializes the plugin. Method called by Strophe.
  31. * @param connection Strophe connection instance.
  32. */
  33. init (connection) {
  34. super.init(connection);
  35. Strophe.addNamespace('PING', "urn:xmpp:ping");
  36. }
  37. /**
  38. * Sends "ping" to given <tt>jid</tt>
  39. * @param jid the JID to which ping request will be sent.
  40. * @param success callback called on success.
  41. * @param error callback called on error.
  42. * @param timeout ms how long are we going to wait for the response. On
  43. * timeout <tt>error<//t> callback is called with undefined error
  44. * argument.
  45. */
  46. ping (jid, success, error, timeout) {
  47. const iq = $iq({type: 'get', to: jid});
  48. iq.c('ping', {xmlns: Strophe.NS.PING});
  49. this.connection.sendIQ(iq, success, error, timeout);
  50. }
  51. /**
  52. * Checks if given <tt>jid</tt> has XEP-0199 ping support.
  53. * @param jid the JID to be checked for ping support.
  54. * @param callback function with boolean argument which will be
  55. * <tt>true</tt> if XEP-0199 ping is supported by given <tt>jid</tt>
  56. */
  57. hasPingSupport (jid, callback) {
  58. const disco = this.connection.disco;
  59. // XXX The following disco.info was observed to throw a "TypeError:
  60. // Cannot read property 'info' of undefined" during porting to React
  61. // Native. Since disco is checked in multiple places (e.g.
  62. // strophe.jingle.js, strophe.rayo.js), check it here as well.
  63. if (disco) {
  64. disco.info(jid, null, (result) => {
  65. const ping
  66. = $(result).find('>>feature[var="urn:xmpp:ping"]');
  67. callback(ping.length > 0);
  68. }, (error) => {
  69. const errmsg = "Ping feature discovery error";
  70. GlobalOnErrorHandler.callErrorHandler(new Error(
  71. errmsg + ": " + error));
  72. logger.error(errmsg, error);
  73. callback(false);
  74. });
  75. } else {
  76. // FIXME Should callback be invoked here? Maybe with false as an
  77. // argument?
  78. }
  79. }
  80. /**
  81. * Starts to send ping in given interval to specified remote JID.
  82. * This plugin supports only one such task and <tt>stopInterval</tt>
  83. * must be called before starting a new one.
  84. * @param remoteJid remote JID to which ping requests will be sent to.
  85. * @param interval task interval in ms.
  86. */
  87. startInterval (remoteJid, interval = PING_INTERVAL) {
  88. if (this.intervalId) {
  89. const errmsg = "Ping task scheduled already";
  90. GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));
  91. logger.error(errmsg);
  92. return;
  93. }
  94. this.intervalId = window.setInterval(() => {
  95. this.ping(remoteJid, (result) => {
  96. this.failedPings = 0;
  97. }, (error) => {
  98. this.failedPings += 1;
  99. const errmsg = "Ping " + (error ? "error" : "timeout");
  100. if (this.failedPings >= PING_THRESHOLD) {
  101. GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));
  102. logger.error(errmsg, error);
  103. // FIXME it doesn't help to disconnect when 3rd PING
  104. // times out, it only stops Strophe from retrying.
  105. // Not really sure what's the right thing to do in that
  106. // situation, but just closing the connection makes no
  107. // sense.
  108. //self.connection.disconnect();
  109. } else {
  110. logger.warn(errmsg, error);
  111. }
  112. }, PING_TIMEOUT);
  113. }, interval);
  114. logger.info("XMPP pings will be sent every " + interval + " ms");
  115. }
  116. /**
  117. * Stops current "ping" interval task.
  118. */
  119. stopInterval () {
  120. if (this.intervalId) {
  121. window.clearInterval(this.intervalId);
  122. this.intervalId = null;
  123. this.failedPings = 0;
  124. logger.info("Ping interval cleared");
  125. }
  126. }
  127. }
  128. export default function () {
  129. Strophe.addConnectionPlugin('ping', new PingConnectionPlugin());
  130. }