Skip to content

Commit

Permalink
Feature/#175 max reconnection reached (#189)
Browse files Browse the repository at this point in the history
emit MAX_RECONNECTION_ATTEMPTS_REACHED
  • Loading branch information
timaschew authored and yasserf committed Jul 27, 2016
1 parent a36729d commit 8b50d6d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/constants/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ exports.TOPIC.PRIVATE = 'PRIVATE/';
exports.EVENT = {};
exports.EVENT.CONNECTION_ERROR = 'connectionError';
exports.EVENT.CONNECTION_STATE_CHANGED = 'connectionStateChanged';
exports.EVENT.MAX_RECONNECTION_ATTEMPTS_REACHED = 'MAX_RECONNECTION_ATTEMPTS_REACHED';
exports.EVENT.ACK_TIMEOUT = 'ACK_TIMEOUT';
exports.EVENT.NO_RPC_PROVIDER = 'NO_RPC_PROVIDER';
exports.EVENT.RESPONSE_TIMEOUT = 'RESPONSE_TIMEOUT';
Expand Down
37 changes: 19 additions & 18 deletions src/message/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var Connection = function( client, url, options ) {

/**
* Returns the current connection state.
* (One of constants.CONNECTION_STATE)
* (One of constants.CONNECTION_STATE)
*
* @public
* @returns {String} connectionState
Expand Down Expand Up @@ -73,7 +73,7 @@ Connection.prototype.authenticate = function( authParams, callback ) {
this._deliberateClose = false;
return;
}

if( this._state === C.CONNECTION_STATE.AWAITING_AUTHENTICATION ) {
this._sendAuthParams();
}
Expand Down Expand Up @@ -113,7 +113,7 @@ Connection.prototype.send = function( message ) {
this._currentMessageResetTimeout = utils.nextTick( this._resetCurrentMessageCount.bind( this ) );
}

if( this._state === C.CONNECTION_STATE.OPEN &&
if( this._state === C.CONNECTION_STATE.OPEN &&
this._queuedMessages.length < this._options.maxMessagesPerPacket &&
this._currentPacketMessageCount < this._options.maxMessagesPerPacket ) {
this._sendQueuedMessages();
Expand Down Expand Up @@ -233,7 +233,7 @@ Connection.prototype._sendAuthParams = function() {

/**
* Will be invoked once the connection is established. The client
* can't send messages yet, and needs to get a connection ACK or REDIRECT
* can't send messages yet, and needs to get a connection ACK or REDIRECT
* from the server before authenticating
*
* @private
Expand Down Expand Up @@ -286,7 +286,7 @@ Connection.prototype._onClose = function() {
}
else if( this._deliberateClose === true ) {
this._setState( C.CONNECTION_STATE.CLOSED );
}
}
else {
if( this._originalUrl !== this._url ) {
this._url = this._originalUrl;
Expand Down Expand Up @@ -334,7 +334,7 @@ Connection.prototype._onMessage = function( message ) {
* by the client until the authentication is successful.
*
* If a challenge is recieved, the user will send the url to the server
* in response to get the appropriate redirect. If the URL is invalid the
* in response to get the appropriate redirect. If the URL is invalid the
* server will respond with a REJECTION resulting in the client connection
* being permanently closed.
*
Expand All @@ -349,15 +349,15 @@ Connection.prototype._onMessage = function( message ) {
Connection.prototype._handleConnectionResponse = function( message ) {
var data;

if( message.action === C.ACTIONS.ACK ) {
if( message.action === C.ACTIONS.ACK ) {
this._setState( C.CONNECTION_STATE.AWAITING_AUTHENTICATION );
if( this._authParams ) {
this._sendAuthParams();
}
}
}
else if( message.action === C.ACTIONS.CHALLENGE ) {
this._setState( C.CONNECTION_STATE.CHALLENGING );
this._endpoint.send( messageBuilder.getMsg( C.TOPIC.CONNECTION, C.ACTIONS.CHALLENGE_RESPONSE, [ this._originalUrl ] ) );
this._endpoint.send( messageBuilder.getMsg( C.TOPIC.CONNECTION, C.ACTIONS.CHALLENGE_RESPONSE, [ this._originalUrl ] ) );
}
else if( message.action === C.ACTIONS.REJECTION ) {
this._challengeDenied = true;
Expand Down Expand Up @@ -385,21 +385,21 @@ Connection.prototype._handleAuthResponse = function( message ) {
var data;

if( message.action === C.ACTIONS.ERROR ) {

if( message.data[ 0 ] === C.EVENT.TOO_MANY_AUTH_ATTEMPTS ) {
this._deliberateClose = true;
this._tooManyAuthAttempts = true;
} else {
this._setState( C.CONNECTION_STATE.AWAITING_AUTHENTICATION );
}

if( this._authCallback ) {
this._authCallback( false, this._getAuthData( message.data[ 1 ] ) );
}

} else if( message.action === C.ACTIONS.ACK ) {
this._setState( C.CONNECTION_STATE.OPEN );

if( this._authCallback ) {
this._authCallback( true, this._getAuthData( message.data[ 0 ] ) );
}
Expand All @@ -426,7 +426,7 @@ Connection.prototype._getAuthData = function( data ) {
};

/**
* Updates the connection state and emits the
* Updates the connection state and emits the
* connectionStateChanged event on the client
*
* @private
Expand All @@ -443,7 +443,7 @@ Connection.prototype._setState = function( state ) {
*
* If the number of failed reconnection attempts exceeds
* options.maxReconnectAttempts the connection is closed
*
*
* @private
* @returns {void}
*/
Expand All @@ -456,18 +456,19 @@ Connection.prototype._tryReconnect = function() {
this._setState( C.CONNECTION_STATE.RECONNECTING );
this._reconnectTimeout = setTimeout(
this._tryOpen.bind( this ),
this._options.reconnectIntervalIncrement * this._reconnectionAttempt
this._options.reconnectIntervalIncrement * this._reconnectionAttempt
);
this._reconnectionAttempt++;
} else {
this._clearReconnect();
this.close();
this._client.emit( C.MAX_RECONNECTION_ATTEMPTS_REACHED, this._reconnectionAttempt );
}
};

/**
* Attempts to open a errourosly closed connection
*
*
* @private
* @returns {void}
*/
Expand All @@ -491,4 +492,4 @@ Connection.prototype._clearReconnect = function() {
this._reconnectionAttempt = 0;
};

module.exports = Connection;
module.exports = Connection;
47 changes: 45 additions & 2 deletions test-unit/unit/message/connectionSpec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* global describe, it, expect, jasmine */

var proxyquire = require( 'proxyquire' ).noCallThru(),
C = require( '../../../src/constants/constants' ),
TcpConnectionMock = require( '../../mocks/tcp/tcp-connection-mock' ),
Connection = proxyquire( '../../../src/message/connection', { '../tcp/tcp-connection': TcpConnectionMock } ),
clientMock = new (require( '../../mocks/client-mock' ))(),
Expand Down Expand Up @@ -289,7 +290,7 @@ describe( 'connection handles auth rejections', function(){

connection._endpoint.simulateOpen();
connection._endpoint.emit( 'message', msg( 'C|A+' ) );

expect( connection._endpoint.lastSendMessage ).toBe( msg( 'A|REQ|{"user":"John"}+' ) );
expect( connection.getState() ).toBe( 'AUTHENTICATING' );
done();
Expand Down Expand Up @@ -336,6 +337,48 @@ describe( 'connection handles data associated with login', function(){
/*****************************************
* RECONNECTING
*****************************************/
describe( 'reach the max reconnect attempts', function(){
var connection,
authCallback = jasmine.createSpy( 'invalid auth callback' ),
options = {reconnectIntervalIncrement: 10, maxReconnectAttempts: 1 };

it( 'creates the connection', function(){
connection = new Connection( clientMock, url, options );
expect( connection._endpoint.url ).toBe( 'somehost:4444' );
expect( connection.getState() ).toBe( 'CLOSED' );
expect( connection._endpoint.lastSendMessage ).toBe( null );
});

it( 'opens the connection', function(){
connection._endpoint.simulateOpen();
expect( connection.getState() ).toBe( 'AWAITING_CONNECTION' );
});

it( 'recieves connection ack', function(){
connection._endpoint.emit( 'message', msg( 'C|A+' ) );
expect( connection.getState() ).toBe( 'AWAITING_AUTHENTICATION' );
});

it( 'loses the connection', function( done ){
expect( connection._endpoint.callsToOpen ).toBe( 0 );
connection._endpoint.close();
expect( connection.getState() ).toBe( 'RECONNECTING' );
expect( connection._endpoint.callsToOpen ).toBe( 0 );

clientMock.on( C.MAX_RECONNECTION_ATTEMPTS_REACHED, done )

setTimeout(function(){
expect( connection._endpoint.callsToOpen ).toBe( 1 );
}, 1 );

setTimeout(function(){
connection._endpoint.close();
expect( connection._endpoint.callsToOpen ).toBe( 1 );
}, 50 );

});
});

describe( 'tries to reconnect if the connection drops unexpectedly', function(){
var connection,
authCallback = jasmine.createSpy( 'invalid auth callback' ),
Expand Down Expand Up @@ -369,7 +412,7 @@ describe( 'tries to reconnect if the connection drops unexpectedly', function(){
}, 1 );

setTimeout(function(){
connection._endpoint.close();
connection._endpoint.close();
expect( connection._endpoint.callsToOpen ).toBe( 1 );
}, 50 );

Expand Down

0 comments on commit 8b50d6d

Please sign in to comment.