src/server.js

Summary

Maintainability
A
0 mins
Test Coverage
var propagate = require('propagate'),
    interpolate = require('util').format,
    request = require('request'),
    jsonmw = require('json-body'),
    utils = require('./utils'),
    dns = require('dns'),
    os = require('os')


/**
 * http.Server handler
 *
 * @param {http.Server} node
 * @param {object} peers
 * @param {fn} callback
 */
var server = module.exports = function (srv, peers, callback) {
  if(!(this instanceof server)) return new server(srv, peers, callback)
  
  this.peers = peers
  this.server = srv

  // propagate close event
  propagate(['close', 'error'], srv, this)
    
  // add request handler
  srv.on('request', function (req, res) {
    if(req.method.toUpperCase() !== 'POST') return
    if(req.url.toLowerCase() !== '/identifications') return
    this.identifications(req, res)
  }.bind(this))
  
  // find the hostname
  dns.lookup(os.hostname(), 4, function (e, hostname) {
    if(e) return callback(e)
    // Create Server
    this.port = srv.address().port
    this.hostname = hostname
    callback(e)
  }.bind(this))
}

require('util').inherits(server, require('events').EventEmitter)

/**
 * Propagate the peers we know
 *
 * @param {peer} to the peer we want to propagate to
 * @param {array} identifications the peers we know aout
 * @param {boolean} ig ignore error
 */
server.prototype.propagate = function (to, identifications) {
  var url = interpolate('http://%s:%s/identifications', to.hostname, to.port)
  // POST http://hostname:port/identifications
  request.post(url, {json: {
    // send all known peers
    identifications: identifications,
    // send its own name
    from: this.peers.state.name()
  }}, function (e, req, body) {
    // we should ignore the error because if it failed, then it's because we're propagating to a dead
    // peer and/or the network is partitioned. afd handles that
    if(e) return //console.log('failed to propagate to peer %s', to.name())
    // identify the peers replied
    this.peers.identify(body)
    // signal that the peer we just connected with is alive
    to.beat()
  }.bind(this))
}

/**
 * handle `propagate` requests
 *
 * @param {http.IncomingMessage}
 * @param {http.ServerResponse}
 */
server.prototype.identifications = function (req, res) {
  // parse the connection body
  jsonmw(req, function (e, body, stream) {
    if(e) return utils.send(res, 500)
    // identify the peers we received
    this.peers.identify(body.identifications)
    // send the peers that the peer that is contacting us doesn't know
    res.end(JSON.stringify(this.peers.deltas(body.identifications)))
    // signal that the peer that is contactng us is alive
    this.peers.find(body.from).beat()
  }.bind(this))
}

/**
 * close the http.Server
 */
server.prototype.close = function () {
  // make sure the server is running
  if(this.server._handle) this.server.close()
}