Skip to content
Browse files

ver. 0.0.1

  • Loading branch information...
1 parent 8bf198e commit c5ea467248dd52d700d391b137ab44645e687327 @kazuyukitanimura committed
Showing with 213 additions and 43 deletions.
  1. +50 −1 README.md
  2. +12 −0 example/example.js
  3. +91 −41 index.js
  4. +14 −1 package.json
  5. +46 −0 test/test.js
View
51 README.md
@@ -1,3 +1,52 @@
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
View
12 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
+
View
132 index.js
@@ -2,41 +2,64 @@ var os = require('os');
var redis = require("redis");
var dbName = 'addressbook';
-var NodeAddressbook = module.exports = function(port, host, redisOpt) {
- var client = this.client = redis.createClient(port, host, redisOpt);
- client.on('error', function(err) {
- console.error(err);
- });
- this.myAddress;
- this.protocols;
- this.addressbook;
+var Addressbook = module.exports = function Addressbook(port, host, options, password) {
+ if (! (this instanceof Addressbook)) { // enforcing new
+ return new Addressbook(port, host, options, password);
+ }
+
+ this.port = port;
+ this.host = host;
+ 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) {
- if (!cb) {
- console.error('callback function is mandatory');
- process.exit(0);
+var returnCallBack = function returnCallBack(cb, err, data) {
+ if (! (err instanceof Error)) {
+ err = new Error(err);
+ }
+ 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) {
- //protocols = [{
- // protocol: 'tcp',
- // port: '6789'
- //}];
- if (typeof protocols === 'function') {
- cb = protocols;
- protocols = undefined;
- }
- if (protocols && ! Array.isArray(protocols)) {
- returnCallBack(cb, 'protocols has to be an Array');
+Addressbook.prototype.update = function update(myContacts, cb) {
+ var i;
+ var self = this;
+ if (typeof myContacts === 'function') {
+ cb = myContacts;
+ myContacts = undefined;
}
- if (!protocols) {
- protocols = this.protocols;
- if (!protocols) {
- returnCallBack(cb, 'protocols has to be provided at least once');
+ if (myContacts) {
+ if (!Array.isArray(myContacts)) {
+ returnCallBack(cb, 'myContacts has to be an Array');
+ 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
@@ -44,35 +67,62 @@ NodeAddressbook.prototype.update = function(protocols, cb) {
var ifaces = os.networkInterfaces();
var en0;
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 (dev === 'en0' && !en0) {
+ if (dev === 'en0' && ! en0) {
en0 = details.address;
}
}
- });
+ }
}
if (!en0) {
returnCallBack(cb, 'No network IP found');
+ return;
} else {
var client = this.client;
- if (en0 !== this.myAddress || protocols !== this.protocols) {
+ if (en0 !== this.myAddress || myContacts !== this.myContacts) {
this.myAddress = en0;
- this.protocols = protocols;
- client.hset(dbName, en0, JSON.stringify(protocols), function(err, res) {
- if (err) {
- returnCallBack(cb, err);
- } else if (res !== 0) {
- returnCallBack(cb, 'Redis did not return 0');
- }
- });
+ this.myContacts = myContacts;
+ if (myContacts) {
+ client.hset(dbName, en0, JSON.stringify(myContacts), function(err, res) {
+ if (err) {
+ returnCallBack(cb, err);
+ return;
+ } else if (res !== 0) {
+ returnCallBack(cb, 'Redis did not return 0, but returned', res);
+ return;
+ }
+ });
+ }
}
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;
+};
+
View
15 package.json
@@ -1,10 +1,23 @@
{
"name": "addressbook"
, "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": {
"redis" : ">= 0.8.2"
}
+ , "devDependencies": {
+ "mocha" : ">= 1.7.0"
+ }
+ , "scripts" : {
+ "test" : "mocha"
+ }
, "engine": "node >= 0.8.14"
, "license": "MIT"
+ , "author": "kazuyukitanimura <kazuyukitanimura@gmail.com>"
}
View
46 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.
Something went wrong with that request. Please try again.