wikimedia-kad-fork
Version:
implementation of the kademlia dht for node
116 lines (92 loc) • 2.46 kB
JavaScript
;
var AddressPortContact = require('../contacts/address-port-contact');
var Message = require('../message');
var assert = require('assert');
var inherits = require('util').inherits;
var http = require('http');
var RPC = require('../rpc');
/**
* Represents an HTTP transport for RPC
* @constructor
* @extends {RPC}
* @param {AddressPortContact} contact - Your node's contact instance
* @param {Object} options
*/
function HTTPTransport(contact, options) {
if (!(this instanceof HTTPTransport)) {
return new HTTPTransport(contact, options);
}
this._queuedResponses = {};
assert(contact instanceof AddressPortContact, 'Invalid contact supplied');
RPC.call(this, contact, options);
}
inherits(HTTPTransport, RPC);
/**
* Create a HTTP server
* @private
* @param {Function} done
*/
HTTPTransport.prototype._open = function(done) {
var self = this;
this._server = http.createServer(function(req, res) {
var payload = '';
var message = null;
req.on('data', function(chunk) {
payload += chunk.toString();
});
req.on('end', function() {
var buffer = new Buffer(payload);
try {
message = Message.fromBuffer(buffer);
} catch(err) {
return self.receive(null);
}
if (Message.isRequest(message)) {
self._queuedResponses[message.id] = res;
}
self.receive(buffer, {});
});
});
this._server.listen(this._contact.port, this._contact.address, done);
};
/**
* Send a RPC to the given contact
* @private
* @param {Buffer} data
* @param {Contact} contact
*/
HTTPTransport.prototype._send = function(data, contact) {
var self = this;
var parsed = JSON.parse(data.toString());
function handleResponse(res) {
var payload = '';
res.on('data', function(chunk) {
payload += chunk.toString();
});
res.on('end', function() {
self.receive(new Buffer(payload), {});
});
}
if (this._queuedResponses[parsed.id]) {
this._queuedResponses[parsed.id].end(data);
delete this._queuedResponses[parsed.id];
return;
}
var req = http.request({
hostname: contact.address,
port: contact.port,
method: 'POST'
}, handleResponse);
req.on('error', function() {
self.receive(null);
});
req.end(data);
};
/**
* Close the underlying socket
* @private
*/
HTTPTransport.prototype._close = function() {
this._server.close();
};
module.exports = HTTPTransport;