UNPKG

torrent-discovery

Version:

Discover BitTorrent and WebTorrent peers

162 lines (133 loc) 4.36 kB
module.exports = Discovery var debug = require('debug')('torrent-discovery') var DHT = require('bittorrent-dht/client') // empty object in browser var EventEmitter = require('events').EventEmitter var extend = require('xtend/mutable') var inherits = require('inherits') var parallel = require('run-parallel') var reemit = require('re-emitter') var Tracker = require('bittorrent-tracker/client') inherits(Discovery, EventEmitter) function Discovery (opts) { var self = this if (!(self instanceof Discovery)) return new Discovery(opts) EventEmitter.call(self) extend(self, { announce: [], dht: typeof DHT === 'function', rtcConfig: null, // browser only peerId: null, port: 0, // torrent port tracker: true, wrtc: null }, opts) self.infoHash = null self.infoHashBuffer = null self.torrent = null self._externalDHT = typeof self.dht === 'object' self._performedDHTLookup = false if (!self.peerId) throw new Error('peerId required') if (!process.browser && !self.port) throw new Error('port required') if (self.dht) self._createDHT(self.dhtPort) } Discovery.prototype.setTorrent = function (torrent) { var self = this if (!self.infoHash && (typeof torrent === 'string' || Buffer.isBuffer(torrent))) { self.infoHash = typeof torrent === 'string' ? torrent : torrent.toString('hex') } else if (!self.torrent && torrent && torrent.infoHash) { self.torrent = torrent self.infoHash = typeof torrent.infoHash === 'string' ? torrent.infoHash : torrent.infoHash.toString('hex') } else { return } self.infoHashBuffer = new Buffer(self.infoHash, 'hex') debug('setTorrent %s', self.infoHash) // If tracker exists, then it was created with just infoHash. Set torrent length // so client can report correct information about uploads. if (self.tracker && self.tracker !== true) { self.tracker.torrentLength = torrent.length } else { self._createTracker() } if (self.dht) { if (self.dht.ready) self._dhtLookupAndAnnounce() else self.dht.on('ready', self._dhtLookupAndAnnounce.bind(self)) } } Discovery.prototype.updatePort = function (port) { var self = this if (port === self.port) return self.port = port if (self.dht && self.infoHash) { self._performedDHTLookup = false self._dhtLookupAndAnnounce() } if (self.tracker && self.tracker !== true) { self.tracker.stop() self.tracker.destroy(function () { self._createTracker() }) } } Discovery.prototype.stop = function (cb) { var self = this var tasks = [] if (self.tracker && self.tracker !== true) { self.tracker.stop() tasks.push(function (cb) { self.tracker.destroy(cb) }) } if (!self._externalDHT && self.dht && self.dht !== true) { tasks.push(function (cb) { self.dht.destroy(cb) }) } parallel(tasks, cb) } Discovery.prototype._createDHT = function (port) { var self = this if (!self._externalDHT) self.dht = new DHT() reemit(self.dht, self, ['error', 'warning']) self.dht.on('peer', function (peer, infoHash) { if (infoHash.toString('hex') === self.infoHash) self.emit('peer', peer.host + ':' + peer.port) }) if (!self._externalDHT) self.dht.listen(port) } Discovery.prototype._createTracker = function () { var self = this if (!self.tracker) return var torrent = self.torrent ? extend({ announce: [] }, self.torrent) : { infoHash: self.infoHash, announce: [] } if (self.announce) torrent.announce = torrent.announce.concat(self.announce) var trackerOpts = { rtcConfig: self.rtcConfig, wrtc: self.wrtc } self.tracker = new Tracker(self.peerId, self.port, torrent, trackerOpts) reemit(self.tracker, self, ['peer', 'warning', 'error']) self.tracker.on('update', function (data) { self.emit('trackerAnnounce', data) }) self.tracker.start() } Discovery.prototype._dhtLookupAndAnnounce = function () { var self = this if (self._performedDHTLookup) return self._performedDHTLookup = true debug('dht lookup') self.dht.lookup(self.infoHash, function (err) { if (err || !self.port) return debug('dht announce') self.dht.announce(self.infoHash, self.port, function (err) { debug('dht announce complete') if (err) self.emit('dhtAnnounceFail') else self.emit('dhtAnnounce') }) }) }