Showing with 56 additions and 40 deletions.
  1. +48 −30 lib/godot/net/client.js
  2. +3 −3 package.json
  3. +5 −7 test/net/client-reconnect-test.js
@@ -7,9 +7,11 @@

var dgram = require('dgram'),
net = require('net'),
util = require('util'),
backoff = require('backoff'),
EventEmitter = require('events').EventEmitter;
utile = require('utile'),
clone = utile.clone,
back = require('back'),
EventEmitter = require('events').EventEmitter,
noop = function () {};

//
// ### function Server (options)
@@ -29,13 +31,19 @@ var Client = module.exports = function Client(options) {
throw new Error('Cannot create client without type: udp, tcp, unix');
}

if(typeof options.reconnect !== 'undefined'
&& typeof options.reconnect!== 'object') {
throw new Error('Reconnect must be a defined object if used')
}

var self = this;

this.type = options.type;
this.host = options.host;
this.port = options.port;
this.path = options.path;
this.reconnect = options.reconnect;
this.attempt = null;
this.producers = {};
this.handlers = {
data: {},
@@ -52,7 +60,7 @@ var Client = module.exports = function Client(options) {
//
// Inherit from EventEmitter
//
util.inherits(Client, EventEmitter);
utile.inherits(Client, EventEmitter);

//
// ### function add (producer)
@@ -126,28 +134,7 @@ Client.prototype.write = function (data) {
// Opens the underlying network connection for this client.
//
Client.prototype.connect = function (port, host, callback) {
var self = this,
connectBackoff, backoffType;

if (this.reconnect) {
if (typeof this.reconnect === 'object') {
backoffType = this.reconnect.type || 'exponential';
connectBackoff = backoff[backoffType](this.reconnect);
connectBackoff.failAfter(this.reconnect.maxTries || 10);
}
else {
connectBackoff = backoff.exponential();
connectBackoff.failAfter(10);
}

connectBackoff.on('fail', function (err) {
self.emit('error', err);
});

connectBackoff.on('ready', function () {
connect();
});
}
var self = this;

//
// Do some fancy arguments parsing to support everything
@@ -173,8 +160,38 @@ Client.prototype.connect = function (port, host, callback) {
: self.emit('error', err) ;
}

function reconnect(err) {
self.attempt = self.attempt || clone(self.reconnect);
//
// Remark: Terminate the backoff when we have hit our fail condition with
// a noop to avoid an if statement
//
// TODO: Make this less coupled (I feel like i want this contained in
// `back` but eh)
//
return self.terminate
? noop()
: back(function (fail, backoff) {
self.attempt = backoff;
//
// Remark: We are done here, emit error and set termination
//
if (fail) {
self.terminate = true;
self.attempt = null;
return self.emit('error', err);
}
//
// Attempt a CONNECT!
//
return connect();
}, self.attempt);
}

function onError(err) {
return connectBackoff ? connectBackoff.backoff(err) : self.emit('error', err);
return self.reconnect
? reconnect(err)
: self.emit('error', err);
}

function connect() {
@@ -193,9 +210,10 @@ Client.prototype.connect = function (port, host, callback) {

self.socket.on('error', onError);
self.socket.on('connect', function () {
if (connectBackoff) {
connectBackoff.reset();
}
//
// Remark: We have successfully connected so reset the terminate variable
//
self.terminate = false;
self.emit('connect');
});
}
@@ -26,8 +26,8 @@
"telenode": "0.0.3",
"utile": "0.2.x",
"window-stream": "~0.4.0",
"backoff": "2.1.x",
"json-stream": "0.1.x"
"json-stream": "0.1.x",
"back": "0.1.x"
},
"devDependencies": {
"optimist": "0.3.4",
@@ -36,7 +36,7 @@
},
"main": "./lib/godot",
"engines": {
"node": "0.8.x"
"node": "0.10.x || 0.8.x"
},
"scripts": {
"test": "vows --spec -i"
@@ -49,9 +49,8 @@ vows.describe('godot/net/client-reconnect').addBatch({
godot.producer(helpers.fixtures['producer-test'])
],
reconnect: {
type: 'exponential',
maxTries: 2,
initialDelay: 100,
retries: 2,
minDelay: 100,
maxDelay: 300
}
});
@@ -66,7 +65,7 @@ vows.describe('godot/net/client-reconnect').addBatch({
assert.instanceOf(err, Error);
},
"should take appropiate amount of time": function (_, err, t) {
assert(t >= 300);
assert(t >= 200);
}
},
"with backoff and server eventually coming up": {
@@ -81,9 +80,8 @@ vows.describe('godot/net/client-reconnect').addBatch({
godot.producer(helpers.fixtures['producer-test'])
],
reconnect: {
type: 'exponential',
maxTries: 2,
initialDelay: 100,
retries: 2,
minDelay: 100,
maxDelay: 300
}
});