123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- "use strict";
- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.WS = void 0;
- const transport_js_1 = require("../transport.js");
- const yeast_js_1 = require("../contrib/yeast.js");
- const util_js_1 = require("../util.js");
- const websocket_constructor_js_1 = require("./websocket-constructor.js");
- const debug_1 = __importDefault(require("debug")); // debug()
- const engine_io_parser_1 = require("engine.io-parser");
- const debug = (0, debug_1.default)("engine.io-client:websocket"); // debug()
- // detect ReactNative environment
- const isReactNative = typeof navigator !== "undefined" &&
- typeof navigator.product === "string" &&
- navigator.product.toLowerCase() === "reactnative";
- class WS extends transport_js_1.Transport {
- /**
- * WebSocket transport constructor.
- *
- * @param {Object} opts - connection options
- * @protected
- */
- constructor(opts) {
- super(opts);
- this.supportsBinary = !opts.forceBase64;
- }
- get name() {
- return "websocket";
- }
- doOpen() {
- if (!this.check()) {
- // let probe timeout
- return;
- }
- const uri = this.uri();
- const protocols = this.opts.protocols;
- // React Native only supports the 'headers' option, and will print a warning if anything else is passed
- const opts = isReactNative
- ? {}
- : (0, util_js_1.pick)(this.opts, "agent", "perMessageDeflate", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "localAddress", "protocolVersion", "origin", "maxPayload", "family", "checkServerIdentity");
- if (this.opts.extraHeaders) {
- opts.headers = this.opts.extraHeaders;
- }
- try {
- this.ws =
- websocket_constructor_js_1.usingBrowserWebSocket && !isReactNative
- ? protocols
- ? new websocket_constructor_js_1.WebSocket(uri, protocols)
- : new websocket_constructor_js_1.WebSocket(uri)
- : new websocket_constructor_js_1.WebSocket(uri, protocols, opts);
- }
- catch (err) {
- return this.emitReserved("error", err);
- }
- this.ws.binaryType = this.socket.binaryType;
- this.addEventListeners();
- }
- /**
- * Adds event listeners to the socket
- *
- * @private
- */
- addEventListeners() {
- this.ws.onopen = () => {
- if (this.opts.autoUnref) {
- this.ws._socket.unref();
- }
- this.onOpen();
- };
- this.ws.onclose = (closeEvent) => this.onClose({
- description: "websocket connection closed",
- context: closeEvent,
- });
- this.ws.onmessage = (ev) => this.onData(ev.data);
- this.ws.onerror = (e) => this.onError("websocket error", e);
- }
- write(packets) {
- this.writable = false;
- // encodePacket efficient as it uses WS framing
- // no need for encodePayload
- for (let i = 0; i < packets.length; i++) {
- const packet = packets[i];
- const lastPacket = i === packets.length - 1;
- (0, engine_io_parser_1.encodePacket)(packet, this.supportsBinary, (data) => {
- // always create a new object (GH-437)
- const opts = {};
- if (!websocket_constructor_js_1.usingBrowserWebSocket) {
- if (packet.options) {
- opts.compress = packet.options.compress;
- }
- if (this.opts.perMessageDeflate) {
- const len =
- // @ts-ignore
- "string" === typeof data ? Buffer.byteLength(data) : data.length;
- if (len < this.opts.perMessageDeflate.threshold) {
- opts.compress = false;
- }
- }
- }
- // Sometimes the websocket has already been closed but the browser didn't
- // have a chance of informing us about it yet, in that case send will
- // throw an error
- try {
- if (websocket_constructor_js_1.usingBrowserWebSocket) {
- // TypeError is thrown when passing the second argument on Safari
- this.ws.send(data);
- }
- else {
- this.ws.send(data, opts);
- }
- }
- catch (e) {
- debug("websocket closed before onclose event");
- }
- if (lastPacket) {
- // fake drain
- // defer to next tick to allow Socket to clear writeBuffer
- (0, websocket_constructor_js_1.nextTick)(() => {
- this.writable = true;
- this.emitReserved("drain");
- }, this.setTimeoutFn);
- }
- });
- }
- }
- doClose() {
- if (typeof this.ws !== "undefined") {
- this.ws.close();
- this.ws = null;
- }
- }
- /**
- * Generates uri for connection.
- *
- * @private
- */
- uri() {
- const schema = this.opts.secure ? "wss" : "ws";
- const query = this.query || {};
- // append timestamp to URI
- if (this.opts.timestampRequests) {
- query[this.opts.timestampParam] = (0, yeast_js_1.yeast)();
- }
- // communicate binary support capabilities
- if (!this.supportsBinary) {
- query.b64 = 1;
- }
- return this.createUri(schema, query);
- }
- /**
- * Feature detection for WebSocket.
- *
- * @return {Boolean} whether this transport is available.
- * @private
- */
- check() {
- return !!websocket_constructor_js_1.WebSocket;
- }
- }
- exports.WS = WS;
|