tallship-manifest
Version:
High availability service management - a list of the cargo carried by a ship, made for the use of various agents and officials at the ports of destination.
214 lines (177 loc) • 4.66 kB
JavaScript
var debug = require('debug')('hub');
var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var axon = require('axon');
var _ = require('underscore');
var HubSocket = require('./hub-socket');
var generateId = require('./id');
var Win = require('./window');
module.exports = Hub;
inherits(Hub, EventEmitter);
function Hub(opts) {
if (!(this instanceof Hub)) return new Hub(opts);
var self = this;
opts = opts || {};
self.id = generateId();
debug('set id: %s', self.id);
self._windowMax = 100000 || opts.maxWindow;
self._windowHead = 0;
this._window = new Win({
id: self.id
});
self.opts = {
server: _.extend({
port: 3100,
host: '0.0.0.0'
}, opts.server),
client: _.extend({
port: 3100,
host: '0.0.0.0'
}, opts.client)
};
self.client = new HubSocket();
self.server = new HubSocket();
self.bus = new EventEmitter();
self.client.on('close', self.emit.bind(self, 'close'));
self.server.on('close', self.emit.bind(self, 'close'));
self.client.on('message', onMessage.bind(self));
self.server.on('message', onMessage.bind(self));
self.client.on('connect', self.emit.bind(self, 'connect'));
self.server.on('connect', self.emit.bind(self, 'connection'));
}
/**
* create the server for other hubs to connect to
*/
Hub.prototype.createServer = function(opts) {
debug('creating server: %j', opts);
var self = this;
_.extend(this.opts.server, opts || {});
var s = self.server.bind(self.opts.server.port, self.opts.server.host, function() {
debug('listening');
self._listening = true;
self.emit('listening');
self.server.once('close', function() {
self._listening = false;
});
});
return s.server; // the net.Socket
}
/**
* connect to another hub
*/
Hub.prototype.connect = function(opts) {
var self = this;
debug('doing connect');
_.extend(this.opts.client, opts || {});
this.client.connect(this.opts.client.port, this.opts.client.host, function() {
debug('connected %j', self.opts.client);
// emit the clients details...
self.emit('connect', self.opts.client);
});
return this.client;
}
/**
* broadcast a new message
*/
Hub.prototype.broadcast = function() {
var args = [].slice.call(arguments);
this._windowHead = ++this._windowHead % this._windowMax;
args.unshift(this.id, this._windowHead);
debug('broadcasting NEW message %j', args);
_broadcast.apply(this, args);
return this;
}
/**
* Send `msg` to single established peer.
*
* @param {Mixed} msg
* @api public
*/
Hub.prototype.send = function(sock, msg) {
var args = [].slice.call(arguments, 1);
args.unshift(this.id, 'direct');
var buf = this.client.pack(args);
if (sock.writable) sock.write(buf);
return this;
};
/**
* Close the hub.
*
* @api public
*/
Hub.prototype.close = function() {
this.server.close();
this.client.close();
this._window.close();
return this;
};
/**
* get the server address
*/
Hub.prototype.address = function() {
return this.server.address();
}
/**
* Returns true/false if the hub is listening.
*/
Hub.prototype.listening = function() {
return !!this._listening;
}
/**
* Returns true/false if the hub is connected or has connections.
*/
Hub.prototype.isOnline = function() {
return this.client.hasSocks() || this.server.hasSocks();
}
/**
* when a message comes in strip out the history
* and unless direct broadcast it out
*/
function onMessage(from, timestamp, evt, data) {
debug('called onMessage: %j', arguments);
if (!evt) {
debug('no event name: %j', evt);
return;
}
if (!timestamp) {
debug('no timestamp: %j', timestamp);
return;
}
if (!from) {
debug('no from for event: %j', evt);
return;
}
// special case is direct messages, ie. hello
if (timestamp === 'direct') {
emitBus.apply(this, arguments);
return;
}
if (from === this.id) {
debug('got event that came from us %j', evt);
return;
}
var added = this._window.add(from, timestamp);
if (!added) {
debug('got duplicate event %j', arguments);
return;
}
_broadcast.apply(this, arguments);
emitBus.apply(this, arguments);
}
/**
* remove the from & timestamp before emitting on the bus
*/
function emitBus(evt) {
var args = [].slice.call(arguments, 2);
// args.unshift(evt);
debug('emit: %j', args);
this.bus.emit.apply(this.bus, args);
}
/**
* broadcast the message over the network
*/
function _broadcast() {
debug('broadcasting: %j', arguments);
this.client.broadcast.apply(this.client, arguments);
this.server.broadcast.apply(this.server, arguments);
}