UNPKG

irrelon-reactor-autonet

Version:

A module for automatically creating groups of self-networking services.

210 lines (163 loc) 4.27 kB
import request from 'request'; import async from 'async'; import ForerunnerDB from 'forerunnerdb'; import polo from 'polo'; import Server from './Server'; class AutoNet extends Server { constructor (name) { super(name); this.fdb = new ForerunnerDB(); this.db = this.fdb.db('broadcast'); this.peer = this.db.collection('peer', { primaryKey: 'name' }); this.client = this.db.collection('client', { primaryKey: 'name' }); this._started = false; this._lastAdvert = 0; this._discover = []; this._zeroConfig = polo(); } discover (arr) { if (arr !== undefined) { if (arr instanceof Array) { this._discover = this._discover.concat(arr); } else { this._discover.push(arr); } return this; } return this._discover; } advertise (data, callback) { var self = this, packet, doAdvert; doAdvert = function () { packet = self.encodePacket(data); if (!self.checkForPeer(packet)) { self.peer.insert(packet); } self._advertise(packet, callback); }; if (self._started === true) { doAdvert(); } else { self.on('started', function () { doAdvert(); }); } } encodePacket (data) { var packet = { "name": data._id, "data": data, "port": this._port, "endPoints": this._routes }; return packet; } decodePacket (packet) { return packet.data; } _advertise (packet, callback) { var self = this; self.__advertise = function () { //self.log('Advertising existence...'); self._zeroConfig.put(packet); }; self.__advertise(); if (callback) { callback(false); } } start (host, port, callback) { var self = this; if (!host) { // No host specified, use all available IPs host = '0.0.0.0'; } if (port === undefined) { // Find the next available port port = 0; } super.start(host, port, function (err, serverAddress) { if (!err) { self._port = serverAddress.port; self._started = true; self._zeroConfig.on('up', function (name, packet) { //self.log('Found autonet peer:', packet); if (!self.checkForPeer(packet)) { self.emit('peerFound', self.decodePacket(packet)); self.addPeer(packet); } // Check if this peer is in our discovery query array if (self.peer._match(self.decodePacket(packet), {$or: self._discover}) === true) { //self.log('Accepting autonet peer:', packet); self.addClient(packet); } }); self.emit('started'); } callback(err, serverAddress); }); } checkForPeer (peer) { //console.log('Peer found:', !!this.peer.count(peer)); return !!this.peer.count({name: peer.name}); } addPeer (peer) { if (!this.checkForPeer(peer)) { this.peer.insert(peer); this.emit('peerAdded', this.decodePacket(peer)); if (this.__advertise) { // Advertise ourselves since this peer is new this.__advertise(); } } } removePeer (peer) { this.peer.remove(peer); this.emit('peerRemoved', peer); } checkForClient (peer) { return !!this.client.count({name: peer.name}); } addClient (peer) { var exists = this.checkForClient(peer); if (!exists) { this.client.insert(peer); this.emit('clientAdded', this.decodePacket(peer)); } } removeClient (peer) { this.client.remove(peer); this.emit('clientRemoved', this.decodePacket(peer)); } broadcast (method, path, data, finished) { var self = this, peerArr, requestQueue = [], generateRequest, i; peerArr = this.client.find(); generateRequest = function (peer, data) { requestQueue.push(function (cb) { self.sendTo(peer, method, path, data, cb); }); }; for (i = 0; i < peerArr.length; i++) { generateRequest(peerArr[i], data); } if (requestQueue.length) { async.parallel(requestQueue, finished); } } sendTo (peer, method, path, data, finished) { request({ url: 'http://' + peer.address + path, method: method, json: data }, finished); } } export default AutoNet;