transport.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import { decodePacket } from "engine.io-parser";
  2. import { Emitter } from "@socket.io/component-emitter";
  3. import { installTimerFunctions } from "./util.js";
  4. import { encode } from "./contrib/parseqs.js";
  5. class TransportError extends Error {
  6. constructor(reason, description, context) {
  7. super(reason);
  8. this.description = description;
  9. this.context = context;
  10. this.type = "TransportError";
  11. }
  12. }
  13. export class Transport extends Emitter {
  14. /**
  15. * Transport abstract constructor.
  16. *
  17. * @param {Object} opts - options
  18. * @protected
  19. */
  20. constructor(opts) {
  21. super();
  22. this.writable = false;
  23. installTimerFunctions(this, opts);
  24. this.opts = opts;
  25. this.query = opts.query;
  26. this.socket = opts.socket;
  27. }
  28. /**
  29. * Emits an error.
  30. *
  31. * @param {String} reason
  32. * @param description
  33. * @param context - the error context
  34. * @return {Transport} for chaining
  35. * @protected
  36. */
  37. onError(reason, description, context) {
  38. super.emitReserved("error", new TransportError(reason, description, context));
  39. return this;
  40. }
  41. /**
  42. * Opens the transport.
  43. */
  44. open() {
  45. this.readyState = "opening";
  46. this.doOpen();
  47. return this;
  48. }
  49. /**
  50. * Closes the transport.
  51. */
  52. close() {
  53. if (this.readyState === "opening" || this.readyState === "open") {
  54. this.doClose();
  55. this.onClose();
  56. }
  57. return this;
  58. }
  59. /**
  60. * Sends multiple packets.
  61. *
  62. * @param {Array} packets
  63. */
  64. send(packets) {
  65. if (this.readyState === "open") {
  66. this.write(packets);
  67. }
  68. else {
  69. // this might happen if the transport was silently closed in the beforeunload event handler
  70. }
  71. }
  72. /**
  73. * Called upon open
  74. *
  75. * @protected
  76. */
  77. onOpen() {
  78. this.readyState = "open";
  79. this.writable = true;
  80. super.emitReserved("open");
  81. }
  82. /**
  83. * Called with data.
  84. *
  85. * @param {String} data
  86. * @protected
  87. */
  88. onData(data) {
  89. const packet = decodePacket(data, this.socket.binaryType);
  90. this.onPacket(packet);
  91. }
  92. /**
  93. * Called with a decoded packet.
  94. *
  95. * @protected
  96. */
  97. onPacket(packet) {
  98. super.emitReserved("packet", packet);
  99. }
  100. /**
  101. * Called upon close.
  102. *
  103. * @protected
  104. */
  105. onClose(details) {
  106. this.readyState = "closed";
  107. super.emitReserved("close", details);
  108. }
  109. /**
  110. * Pauses the transport, in order not to lose packets during an upgrade.
  111. *
  112. * @param onPause
  113. */
  114. pause(onPause) { }
  115. createUri(schema, query = {}) {
  116. return (schema +
  117. "://" +
  118. this._hostname() +
  119. this._port() +
  120. this.opts.path +
  121. this._query(query));
  122. }
  123. _hostname() {
  124. const hostname = this.opts.hostname;
  125. return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]";
  126. }
  127. _port() {
  128. if (this.opts.port &&
  129. ((this.opts.secure && Number(this.opts.port !== 443)) ||
  130. (!this.opts.secure && Number(this.opts.port) !== 80))) {
  131. return ":" + this.opts.port;
  132. }
  133. else {
  134. return "";
  135. }
  136. }
  137. _query(query) {
  138. const encodedQuery = encode(query);
  139. return encodedQuery.length ? "?" + encodedQuery : "";
  140. }
  141. }