diffusion
Version:
Diffusion JavaScript client
188 lines (187 loc) • 6.84 kB
JavaScript
;
/**
* @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;