Skip to content

Commit

Permalink
ver. 0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
kazuyukitanimura committed Nov 12, 2012
1 parent 8bf198e commit c5ea467
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 43 deletions.
51 changes: 50 additions & 1 deletion README.md
@@ -1,3 +1,52 @@
addressbook addressbook
============ ============
TBW `addressbook` keeps tracking available node instances backed by Redis.

## Prerequisites
Redis `>=2.6.4`.

On Mac with homebrew,
```bash
$ homebrew install redis
$ redis-server
```

## Installation
```bash
$ npm install addressbook
```

## Version
0.0.1 (pre-release)

# Usage
```js
var AB = require('addressbook');
var ab = new AB();
var myServicies = [{port: 3000, protocol: 'http'}, {port: 5004, protocol: 'dnode'}];
ab.update(myServicies, function(err, addressbook) {
if (err) {
throw err;
} else {
console.log(addressbook);
}
});
ab.pick(); // => return a randomly picked remote service
```

# API
## ab.([port], [host], [options], [passowrd])

## ab.update([myServicies], [callback])

## ab.pick()

# Test
```bash
$ npm test
```

# License
MIT

Copyright (c) 2012 Kazuyuki Tanimura
12 changes: 12 additions & 0 deletions example/example.js
@@ -0,0 +1,12 @@
var AB = require('addressbook');
var ab = new AB();
var myServicies = [{port: 3000, protocol: 'http'}, {port: 5004, protocol: 'dnode'}];
ab.update(myServicies, function(err, addressbook) {
if (err) {
throw err;
} else {
console.log(addressbook);
}
});
ab.pick(); // => return randomly picked remote service

132 changes: 91 additions & 41 deletions index.js
Expand Up @@ -2,77 +2,127 @@ var os = require('os');
var redis = require("redis"); var redis = require("redis");
var dbName = 'addressbook'; var dbName = 'addressbook';


var NodeAddressbook = module.exports = function(port, host, redisOpt) { var Addressbook = module.exports = function Addressbook(port, host, options, password) {
var client = this.client = redis.createClient(port, host, redisOpt); if (! (this instanceof Addressbook)) { // enforcing new
client.on('error', function(err) { return new Addressbook(port, host, options, password);
console.error(err); }
});
this.myAddress; this.port = port;
this.protocols; this.host = host;
this.addressbook; this.options = options;
this.password = password;
var connect = function() {
var client = this.client = redis.createClient(this.port, this.host, this.options).on('error', function(err) {
console.error(err, 'reconnecting');
connect.call(this);
});
var password = this.password;
if (password) {
client.auth(password, function() {});
}
};
connect.call(this);
this.myAddress = ''; // ip address of local machine, either IPv4 or IPv6
this.myContacts = []; // local server servicies e.g., [{port:portnumber}, ...]
this.addressbook = {}; // remote server servicies e.g., {ipaddress:[{port:portnumber}, ...], ...}
}; };


var returnCallBack = function(cb, err, data) { var returnCallBack = function returnCallBack(cb, err, data) {
if (!cb) { if (! (err instanceof Error)) {
console.error('callback function is mandatory'); err = new Error(err);
process.exit(0); }
if (cb) {
// until setImmediate() is available, let's use bind for now
process.nextTick(cb.bind(null, err, data));
} else {
throw err;
} }
process.nextTick(cb.bind(err, data));
}; };


NodeAddressbook.prototype.update = function(protocols, cb) { Addressbook.prototype.update = function update(myContacts, cb) {
//protocols = [{ var i;
// protocol: 'tcp', var self = this;
// port: '6789' if (typeof myContacts === 'function') {
//}]; cb = myContacts;
if (typeof protocols === 'function') { myContacts = undefined;
cb = protocols;
protocols = undefined;
}
if (protocols && ! Array.isArray(protocols)) {
returnCallBack(cb, 'protocols has to be an Array');
} }
if (!protocols) { if (myContacts) {
protocols = this.protocols; if (!Array.isArray(myContacts)) {
if (!protocols) { returnCallBack(cb, 'myContacts has to be an Array');
returnCallBack(cb, 'protocols has to be provided at least once'); return;
} else {
for (i = myContacts.length; i--;) {
if (! (myContacts[i].port && myContacts[i].protocol)) {
returnCallBack(cb, 'each contact in myContacts has to have a port number');
return;
}
}
} }
} else {
myContacts = this.myContacts;
} }


// get the network IP // get the network IP
// http://stackoverflow.com/questions/3653065/get-local-ip-address-in-node-js // http://stackoverflow.com/questions/3653065/get-local-ip-address-in-node-js
var ifaces = os.networkInterfaces(); var ifaces = os.networkInterfaces();
var en0; var en0;
for (var dev in ifaces) { for (var dev in ifaces) {
ifaces[dev].forEach(function(details) { var ifacesDev = ifaces[dev];
for (i = ifacesDev.length; i--;) {
var details = ifacesDev[i];
if (details.family === 'IPv4' || details.family === 'IPv6') { if (details.family === 'IPv4' || details.family === 'IPv6') {
if (dev === 'en0' && !en0) { if (dev === 'en0' && ! en0) {
en0 = details.address; en0 = details.address;
} }
} }
}); }
} }


if (!en0) { if (!en0) {
returnCallBack(cb, 'No network IP found'); returnCallBack(cb, 'No network IP found');
return;
} else { } else {
var client = this.client; var client = this.client;


if (en0 !== this.myAddress || protocols !== this.protocols) { if (en0 !== this.myAddress || myContacts !== this.myContacts) {
this.myAddress = en0; this.myAddress = en0;
this.protocols = protocols; this.myContacts = myContacts;
client.hset(dbName, en0, JSON.stringify(protocols), function(err, res) { if (myContacts) {
if (err) { client.hset(dbName, en0, JSON.stringify(myContacts), function(err, res) {
returnCallBack(cb, err); if (err) {
} else if (res !== 0) { returnCallBack(cb, err);
returnCallBack(cb, 'Redis did not return 0'); return;
} } else if (res !== 0) {
}); returnCallBack(cb, 'Redis did not return 0, but returned', res);
return;
}
});
}
} }


client.hgetall(dbName, function(err, data) { client.hgetall(dbName, function(err, data) {
returnCallBack(cb, err, JSON.parse(data)); var addressbook = {};
self.addressbook = addressbook;
for (var key in data) {
addressbook[key] = JSON.parse(data[key]);
}
returnCallBack(cb, err, addressbook);
return;
}); });
} }
}; };


Addressbook.prototype.pick = function pick(n) {
var addressbook = this.addressbook;
var host;
var c = 0;
for (var key in addressbook) {
if (Math.random() * ++c < 1) {
host = key;
}
}
var ret = addressbook[host];
ret.host = host;
return ret;
};

15 changes: 14 additions & 1 deletion package.json
@@ -1,10 +1,23 @@
{ {
"name": "addressbook" "name": "addressbook"
, "version": "0.0.1" , "version": "0.0.1"
, "private": true , "description": "Addressbook keeps tracking available node instances backed by Redis."
, "repository": {
"type": "git",
"url": "git://github.com/kazuyukitanimura/addressbook.git"
}
, "main" : "./index.js"
, "keywords" : ["redis", "mdns"]
, "dependencies": { , "dependencies": {
"redis" : ">= 0.8.2" "redis" : ">= 0.8.2"
} }
, "devDependencies": {
"mocha" : ">= 1.7.0"
}
, "scripts" : {
"test" : "mocha"
}
, "engine": "node >= 0.8.14" , "engine": "node >= 0.8.14"
, "license": "MIT" , "license": "MIT"
, "author": "kazuyukitanimura <kazuyukitanimura@gmail.com>"
} }
46 changes: 46 additions & 0 deletions test/test.js
@@ -0,0 +1,46 @@
var assert = require("assert");
var Addressbook = require('../index');
var myServicies = [{
port: 3000,
protocol: 'http'
},
{
port: 5004,
protocol: 'dnode'
}];

describe('Addressbook', function() {
describe('#update()', function() {
it('should return {ipaddress:[{port:portnumber}, ...], ...}', function(done) {
var ab = Addressbook();
ab.update(function(err, addressbook) {
assert(err instanceof Error);
});
ab.update(myServicies, function(err, addressbook) {
for (var key in addressbook) {
var contacts = addressbook[key];
assert(Array.isArray(contacts));
for (var i = contacts.length; i--;) {
var contact = contacts[i];
assert(contact.port);
assert.deepEqual(typeof contact.port, 'number');
assert(contact.protocol);
assert.deepEqual(typeof contact.protocol, 'string');
}
}
assert.deepEqual(ab.addressbook, addressbook);
done();
});
});
});
describe('#pick(n)', function() {
it('should return [{port:portnumber}, ...]', function(done) {
var ab = Addressbook();
ab.update(function(err, addressbook) {
assert(ab.pick().port);
});
done();
});
});
});

0 comments on commit c5ea467

Please sign in to comment.