TT#66572 Prevent uncaught rejections on websocket timeout #19

Resolves #19

Change-Id: I59dc09d6e29aca7e007b8cd6bf90e05691c6e0f0
changes/46/33846/2
Rob Gonnella 7 years ago committed by Hans-Peter Herzog
parent 9c3759214e
commit a41e866710

@ -1,6 +1,6 @@
{
"name": "janus-videoroom-client",
"version": "4.1.4",
"version": "4.1.5",
"main": "src/janus.js",
"scripts": {
"test": "mocha -b --exit -R spec --full-trace test/*-spec.js"

@ -71,6 +71,7 @@ class Client {
this.reconnect = _.isBoolean(options.reconnect)? options.reconnect : true;
this.token = _.get(options, 'token', null);
this.apiSecret = _.get(options, 'apiSecret', null);
this.handshakeTimeout = _.get(options, 'handshakeTimeout', undefined);
}
getVersion() {
@ -81,9 +82,20 @@ class Client {
return _.isObject(this.webSocket) && this.webSocket.readyState === 1;
}
isConnecting() {
return _.isObject(this.webSocket) && this.webSocket.readyState === 0;
}
isClosing() {
return _.isObject(this.webSocket) && this.webSocket.readyState === 2;
}
connect() {
if(this.webSocket === null) {
this.webSocket = new this.WebSocket(this.url, this.protocol);
var opts = this.handshakeTimeout ?
{ handshakeTimeout: this.handshakeTimeout } :
undefined;
this.webSocket = new this.WebSocket(this.url, this.protocol, opts);
this.webSocket.on(WebSocketEvent.open, ()=>{ this.open(); });
this.webSocket.on(WebSocketEvent.close, ()=>{ this.close(); });
this.webSocket.on(WebSocketEvent.message, (message)=>{ this.message(message); });
@ -109,7 +121,12 @@ class Client {
}
close(options) {
// When the connection finishes closing the onClose event handler
// will re-trigger this clean up.
if (this.isClosing()) { return; }
let connect = _.get(options, 'connect', false);
let closeHandler = ()=>{
this.stopConnectionTimeout();
if(this.webSocket !== null) {
@ -127,11 +144,10 @@ class Client {
this.connect();
}
};
if(_.isObject(this.webSocket) && this.isConnected()) {
if(this.isConnected() || this.isConnecting()) {
this.webSocket.removeAllListeners('close');
this.webSocket.on('close', ()=>{
closeHandler();
});
this.webSocket.on('close', () => closeHandler());
this.webSocket.close();
} else {
closeHandler();

@ -12,8 +12,13 @@ const logger = require('debug-logger')('mock:janus-server');
class JanusServer {
constructor(options) {
var triggerHandshakeTimeout = options.triggerHandshakeTimeout;
this.port = options.port || 9002;
this.http = http.createServer();
if (triggerHandshakeTimeout) { return; }
this.ws = new WebSocketServer({
server: this.http
});

@ -15,22 +15,34 @@ var request = {
var mockServerPort = config.janus.server.port;
var mockServerUrl = config.janus.server.url;
var brokenMockServerPort = config.janus.server.port + 1;
var brokenMockServerUrl = 'http://localhost:' + brokenMockServerPort;
var handshakeTimeoutError = 'Opening handshake has timed out';
var earlyCloseError = 'WebSocket was closed before the connection was established';
describe('Client', function() {
var janusServerMock;
var brokenJanusServerMock;
before(function(done){
janusServerMock = new JanusServerMock({
port: mockServerPort
});
janusServerMock.init().then(()=>{
done();
}).catch(()=>{
done(err);
brokenJanusServerMock = new JanusServerMock({
port: brokenMockServerPort,
triggerHandshakeTimeout: true
});
Promise.all([
janusServerMock.init(),
brokenJanusServerMock.init()
]).then(() => done()).catch((e) => done(e));
});
after(function(){
janusServerMock.close();
brokenJanusServerMock.close();
});
it('should connect to websocket endpoint', function(done) {
@ -103,6 +115,47 @@ describe('Client', function() {
client.connect();
});
[
{when: 'after', connectionTimeout: 200, handshakeTimeout: 300, expectedError: earlyCloseError},
{when: 'before', connectionTimeout: 300, handshakeTimeout: 200, expectedError: handshakeTimeoutError}
].forEach((test) => {
it(`does not throw uncaught exception if handshake timeout occurs ${test.when} connection timeout`, function(done) {
var client = new Client({
url: brokenMockServerUrl,
reconnect: true,
connectionTimeout: test.connectionTimeout,
handshakeTimeout: test.handshakeTimeout,
});
var caughtError = false
var isDone = false
function onUncaughtException(err) {
if (isDone) { return; }
isDone = true;
process.off('uncaughtException', onUncaughtException);
var msg = err.message;
done(new Error('Client should not cause uncaught exception: ' + msg));
}
client.onError((err) => {
if (isDone) { return; }
var msg = err.message;
caughtError = msg === test.expectedError;
if (caughtError) {
isDone = true;
process.off('uncaughtException', onUncaughtException);
done();
}
});
process.on('uncaughtException', onUncaughtException)
client.connect();
});
});
it('should fail sending an object, because client is disconnected', function(done){
var client = new Client({
url: mockServerUrl

Loading…
Cancel
Save