polling.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { Transport } from "../transport.js";
  2. import yeast from "yeast";
  3. import parseqs from "parseqs";
  4. import { encodePayload, decodePayload } from "engine.io-parser";
  5. export class Polling extends Transport {
  6. constructor() {
  7. super(...arguments);
  8. this.polling = false;
  9. }
  10. /**
  11. * Transport name.
  12. */
  13. get name() {
  14. return "polling";
  15. }
  16. /**
  17. * Opens the socket (triggers polling). We write a PING message to determine
  18. * when the transport is open.
  19. *
  20. * @api private
  21. */
  22. doOpen() {
  23. this.poll();
  24. }
  25. /**
  26. * Pauses polling.
  27. *
  28. * @param {Function} callback upon buffers are flushed and transport is paused
  29. * @api private
  30. */
  31. pause(onPause) {
  32. this.readyState = "pausing";
  33. const pause = () => {
  34. this.readyState = "paused";
  35. onPause();
  36. };
  37. if (this.polling || !this.writable) {
  38. let total = 0;
  39. if (this.polling) {
  40. total++;
  41. this.once("pollComplete", function () {
  42. --total || pause();
  43. });
  44. }
  45. if (!this.writable) {
  46. total++;
  47. this.once("drain", function () {
  48. --total || pause();
  49. });
  50. }
  51. }
  52. else {
  53. pause();
  54. }
  55. }
  56. /**
  57. * Starts polling cycle.
  58. *
  59. * @api public
  60. */
  61. poll() {
  62. this.polling = true;
  63. this.doPoll();
  64. this.emit("poll");
  65. }
  66. /**
  67. * Overloads onData to detect payloads.
  68. *
  69. * @api private
  70. */
  71. onData(data) {
  72. const callback = packet => {
  73. // if its the first message we consider the transport open
  74. if ("opening" === this.readyState && packet.type === "open") {
  75. this.onOpen();
  76. }
  77. // if its a close packet, we close the ongoing requests
  78. if ("close" === packet.type) {
  79. this.onClose();
  80. return false;
  81. }
  82. // otherwise bypass onData and handle the message
  83. this.onPacket(packet);
  84. };
  85. // decode payload
  86. decodePayload(data, this.socket.binaryType).forEach(callback);
  87. // if an event did not trigger closing
  88. if ("closed" !== this.readyState) {
  89. // if we got data we're not polling
  90. this.polling = false;
  91. this.emit("pollComplete");
  92. if ("open" === this.readyState) {
  93. this.poll();
  94. }
  95. else {
  96. }
  97. }
  98. }
  99. /**
  100. * For polling, send a close packet.
  101. *
  102. * @api private
  103. */
  104. doClose() {
  105. const close = () => {
  106. this.write([{ type: "close" }]);
  107. };
  108. if ("open" === this.readyState) {
  109. close();
  110. }
  111. else {
  112. // in case we're trying to close while
  113. // handshaking is in progress (GH-164)
  114. this.once("open", close);
  115. }
  116. }
  117. /**
  118. * Writes a packets payload.
  119. *
  120. * @param {Array} data packets
  121. * @param {Function} drain callback
  122. * @api private
  123. */
  124. write(packets) {
  125. this.writable = false;
  126. encodePayload(packets, data => {
  127. this.doWrite(data, () => {
  128. this.writable = true;
  129. this.emit("drain");
  130. });
  131. });
  132. }
  133. /**
  134. * Generates uri for connection.
  135. *
  136. * @api private
  137. */
  138. uri() {
  139. let query = this.query || {};
  140. const schema = this.opts.secure ? "https" : "http";
  141. let port = "";
  142. // cache busting is forced
  143. if (false !== this.opts.timestampRequests) {
  144. query[this.opts.timestampParam] = yeast();
  145. }
  146. if (!this.supportsBinary && !query.sid) {
  147. query.b64 = 1;
  148. }
  149. // avoid port if default for schema
  150. if (this.opts.port &&
  151. (("https" === schema && Number(this.opts.port) !== 443) ||
  152. ("http" === schema && Number(this.opts.port) !== 80))) {
  153. port = ":" + this.opts.port;
  154. }
  155. const encodedQuery = parseqs.encode(query);
  156. const ipv6 = this.opts.hostname.indexOf(":") !== -1;
  157. return (schema +
  158. "://" +
  159. (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) +
  160. port +
  161. this.opts.path +
  162. (encodedQuery.length ? "?" + encodedQuery : ""));
  163. }
  164. }