UNPKG

diffusion

Version:

Diffusion JavaScript client

188 lines (187 loc) 6.84 kB
"use strict"; /** * @module Transport */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WSTransport = void 0; var errors_1 = require("./../../errors/errors"); var emitter_1 = require("./../events/emitter"); var stream_1 = require("./../events/stream"); var logger_1 = require("./../util/logger"); var credential_tunnel_1 = require("./../v4-stack/credential-tunnel"); var log = logger_1.create('Websocket transport'); /** * Construct a valid websocket URI from the given options. * * @param req the connection request. * @param opts the connection options. * @returns the connection URI */ function constructURI(req, opts) { var scheme = opts.secure ? 'wss' : 'ws'; var uri = scheme + "://" + opts.host + ":" + opts.port + opts.path; uri += '?ty=' + req.type; uri += '&v=' + req.version; uri += '&ca=' + req.capabilities; uri += '&r=' + opts.reconnect.timeout; if (req.token) { uri += '&c=' + encodeURIComponent(req.token); uri += '&cs=' + req.availableClientSequence; uri += '&ss=' + req.lastServerSequence; } if (opts.properties) { uri += '&sp=' + encodeURIComponent(JSON.stringify(opts.properties)); } if (opts.principal !== undefined) { uri += '&username=' + encodeURIComponent(opts.principal); uri += '&password=' + encodeURIComponent(credential_tunnel_1.encodeAsString(opts.credentials)); } return uri; } /** * The implementation of the {@link Transport} interface using Web Sockets */ var WSTransport = /** @class */ (function (_super) { __extends(WSTransport, _super); /** * Construct a new WSTransport instance * * @param opts the connection options * @param ws the transport constructor function */ function WSTransport(opts, ws, allowsOptions) { var _this = this; var factory = emitter_1.Emitter.create(); _this = _super.call(this, factory) || this; _this.emitter = factory.emitter(_this); _this.opts = opts; _this.ws = ws; _this.allowsOptions = allowsOptions; return _this; } /** * Handler function for the WebSocket's `onmessage` event. * * @param message the message that was received */ WSTransport.prototype.handler = function (message) { if (message.data.length > this.opts.maxMessageSize) { this.emitter.error(new Error("Received message of size: " + message.data.length + ", " + ("exceeding max message size: " + this.opts.maxMessageSize))); } else { this.emitter.immediate('data', new Uint8Array(message.data)); } }; /** * Establish a websocket connection, with provided connection options and * callback functions. * * @param req the connection request * @param handshake a handshake deserialiser */ WSTransport.prototype.connect = function (req, handshake) { var _this = this; var extraOptions = {}; if (this.opts.httpProxyAgent !== undefined) { if (!this.allowsOptions) { throw new errors_1.IllegalArgumentError('httpProxyAgent option is not allowed'); } extraOptions.agent = this.opts.httpProxyAgent; } if (this.opts.tlsOptions !== undefined) { if (!this.allowsOptions) { throw new errors_1.IllegalArgumentError('tlsOptions option are not allowed'); } extraOptions = __assign(__assign({}, extraOptions), this.opts.tlsOptions); } try { var uri = constructURI(req, this.opts); this.socket = (Object.keys(extraOptions).length === 0) ? new this.ws(uri) : new this.ws(uri, extraOptions); log.debug('Created websocket', uri); } catch (error) { throw new errors_1.RuntimeError("Unable to construct WebSocket " + error); } this.socket.binaryType = 'arraybuffer'; this.socket.onmessage = function (msg) { _this.socket.onmessage = _this.handler.bind(_this); _this.socket.onerror = function (err) { _this.emitter.error(err); }; handshake(new Uint8Array(msg.data)); }; this.socket.onclose = function (reason) { _this.emitter.close(reason); }; this.socket.onerror = function (err) { _this.emitter.close(err); }; }; /** * Send a binary message to the server. * * @param message the message to send * @return `true` if the message was sent successfully */ WSTransport.prototype.dispatch = function (message) { log.debug('Sending websocket message', message); try { this.socket.send(message); return true; } catch (err) { log.error('Websocket send error', err); return false; } }; /** * Directly close the websocket connection. */ WSTransport.prototype.close = function () { var _this = this; log.debug('Closing websocket'); if (this.socket !== undefined) { try { this.socket.onerror = function (err) { _this.emitter.close(err); }; this.socket.close(1000); } catch (err) { // if socket.close throws an error we must assume it is already closed } } return this; }; return WSTransport; }(stream_1.StreamImpl)); exports.WSTransport = WSTransport;