diff options
author | Feross Aboukhadijeh <feross@feross.org> | 2016-04-21 09:10:32 +0300 |
---|---|---|
committer | Feross Aboukhadijeh <feross@feross.org> | 2016-04-21 09:10:32 +0300 |
commit | 3daee2c66cbf752b9e6e49b99492b8c1914a4a58 (patch) | |
tree | fbdd6c10f6a64674268dc77d1b3ccb4a37c44a65 /index.js | |
parent | 7a7c4a8b8c49f5c92b7c20ff439bc8614f7d607e (diff) |
BREAKING: Major cleanup
### Added
- `client.listening` property to signal whether TCP server is listening
for incoming
connections.
### Changed
- Merged `Swarm` class into `Torrent` object. Properties on
`torrent.swarm` (like
`torrent.swarm.wires`) now exist on `torrent` (e.g. `torrent.wires`).
- `torrent.addPeer` can no longer be called before the `infoHash` event
has been
emitted.
- Remove `torrent.on('listening')` event. Use `client.on('listening')`
instead.
- Remove support from `TCPPool` for listening on multiple ports. This
was not used by
WebTorrent and just added complexity. There is now a single `TCPPool`
instance for the
whole WebTorrent client.
- Deprecate: Do not use `client.download()` anymore. Use `client.add()`
instead.
- Deprecate: Do not use `torrent.swarm` anymore. Use `torrent` instead.
### Fixed
- When there is a `torrent.on('error')` listener, don't also emit
`client.on('error')`.
- Do not return existing torrent object when duplicate torrent is
added. Fire an
`'error'` event instead.
- Memory leak of `Torrent` object caused by `RarityMap`
- Memory leak of `Torrent` object caused by `TCPPool`
- `client.ratio` and `torrent.ratio` are now calculated as `uploaded /
received` instead
of `uploaded / downloaded`.
Diffstat (limited to 'index.js')
-rw-r--r-- | index.js | 130 |
1 files changed, 80 insertions, 50 deletions
@@ -1,3 +1,6 @@ +// TODO: cleanup event listeners +// TODO: set dhtPort to correct port + module.exports = WebTorrent var createTorrent = require('create-torrent') @@ -16,10 +19,9 @@ var speedometer = require('speedometer') var zeroFill = require('zero-fill') var concatStream = require('./lib/concat-stream') +var TCPPool = require('./lib/tcp-pool') // browser exclude var Torrent = require('./lib/torrent') -module.exports.WEBRTC_SUPPORT = Peer.WEBRTC_SUPPORT - /** * WebTorrent version. */ @@ -55,36 +57,44 @@ function WebTorrent (opts) { if (!opts) opts = {} + self.peerId = typeof opts.peerId === 'string' + ? opts.peerId + : (opts.peerId || new Buffer(VERSION_PREFIX + hat(48))).toString('hex') + self.peerIdBuffer = new Buffer(self.peerId, 'hex') + + self.nodeId = typeof opts.nodeId === 'string' + ? opts.nodeId + : (opts.nodeId && opts.nodeId.toString('hex')) || hat(160) + self.nodeIdBuffer = new Buffer(self.nodeId, 'hex') + self.destroyed = false + self.listening = false self.torrentPort = opts.torrentPort || 0 self.tracker = opts.tracker !== undefined ? opts.tracker : true + self.torrents = [] + self.maxConns = Number(opts.maxConns) || 55 self._rtcConfig = opts.rtcConfig self._wrtc = opts.wrtc || global.WRTC // to support `webtorrent-hybrid` package - self.torrents = [] + if (typeof TCPPool === 'function') { + self._tcpPool = new TCPPool(self) + } else { + process.nextTick(function () { + self._onListening() + }) + } + // stats self._downloadSpeed = speedometer() self._uploadSpeed = speedometer() - self.maxConns = opts.maxConns - - self.peerId = typeof opts.peerId === 'string' - ? opts.peerId - : (opts.peerId || new Buffer(VERSION_PREFIX + hat(48))).toString('hex') - self.peerIdBuffer = new Buffer(self.peerId, 'hex') - - self.nodeId = typeof opts.nodeId === 'string' - ? opts.nodeId - : (opts.nodeId && opts.nodeId.toString('hex')) || hat(160) - self.nodeIdBuffer = new Buffer(self.nodeId, 'hex') - if (opts.dht !== false && typeof DHT === 'function' /* browser exclude */) { // use a single DHT instance for all torrents, so the routing table can be reused self.dht = new DHT(extend({ nodeId: self.nodeId }, opts.dht)) self.dht.once('error', function (err) { self.emit('error', err) - self.destroy() + self._destroy() }) // Ignore warning when there are > 10 torrents in the client @@ -114,6 +124,8 @@ function WebTorrent (opts) { } } +WebTorrent.WEBRTC_SUPPORT = Peer.WEBRTC_SUPPORT + Object.defineProperty(WebTorrent.prototype, 'downloadSpeed', { get: function () { return this._downloadSpeed() } }) @@ -142,10 +154,10 @@ Object.defineProperty(WebTorrent.prototype, 'ratio', { var uploaded = this.torrents.reduce(function (total, torrent) { return total + torrent.uploaded }, 0) - var downloaded = this.torrents.reduce(function (total, torrent) { - return total + torrent.downloaded + var received = this.torrents.reduce(function (total, torrent) { + return total + torrent.received }, 0) || 1 - return uploaded / downloaded + return uploaded / received } }) @@ -174,14 +186,18 @@ WebTorrent.prototype.get = function (torrentId) { return null } +WebTorrent.prototype.download = function (torrentId, opts, ontorrent) { + console.warn('WebTorrent: client.download() is deprecated. Use client.add() instead') + return this.add(torrentId, opts, ontorrent) +} + /** * Start downloading a new torrent. Aliased as `client.download`. * @param {string|Buffer|Object} torrentId * @param {Object} opts torrent-specific options * @param {function=} ontorrent called when the torrent is ready (has metadata) */ -WebTorrent.prototype.add = -WebTorrent.prototype.download = function (torrentId, opts, ontorrent) { +WebTorrent.prototype.add = function (torrentId, opts, ontorrent) { var self = this if (self.destroyed) throw new Error('client is destroyed') if (typeof opts === 'function') return self.add(torrentId, null, opts) @@ -189,29 +205,12 @@ WebTorrent.prototype.download = function (torrentId, opts, ontorrent) { debug('add') opts = opts ? extend(opts) : {} - var torrent = self.get(torrentId) - - if (torrent) { - if (torrent.ready) process.nextTick(onReady) - else torrent.once('ready', onReady) - } else { - torrent = new Torrent(torrentId, self, opts) - self.torrents.push(torrent) + var torrent = new Torrent(torrentId, self, opts) + self.torrents.push(torrent) - torrent.once('error', function (err) { - self.emit('error', err, torrent) - self.remove(torrent) - }) - - torrent.once('listening', function (port) { - self.emit('listening', port, torrent) - }) - - torrent.once('ready', onReady) - } + torrent.once('ready', onReady) function onReady () { - debug('on torrent') if (typeof ontorrent === 'function') ontorrent(torrent) self.emit('torrent', torrent) } @@ -303,19 +302,20 @@ WebTorrent.prototype.seed = function (input, opts, onseed) { * @param {function} cb */ WebTorrent.prototype.remove = function (torrentId, cb) { - var self = this debug('remove') - var torrent = self.get(torrentId) + var torrent = this.get(torrentId) if (!torrent) throw new Error('No torrent with id ' + torrentId) - self.torrents.splice(self.torrents.indexOf(torrent), 1) + this.torrents.splice(this.torrents.indexOf(torrent), 1) torrent.destroy(cb) } WebTorrent.prototype.address = function () { - var self = this - return { address: '0.0.0.0', family: 'IPv4', port: self.torrentPort } + if (!this.listening) return null + return this._tcpPool + ? this._tcpPool.server.address() + : { address: '0.0.0.0', family: 'IPv4', port: 0 } } /** @@ -323,18 +323,48 @@ WebTorrent.prototype.address = function () { * @param {function} cb */ WebTorrent.prototype.destroy = function (cb) { + if (this.destroyed) throw new Error('client already destroyed') + this._destroy(null, cb) +} + +WebTorrent.prototype._destroy = function (err, cb) { var self = this - if (self.destroyed) throw new Error('client already destroyed') + debug('client destroy') self.destroyed = true - debug('destroy') var tasks = self.torrents.map(function (torrent) { - return function (cb) { self.remove(torrent, cb) } + return function (cb) { + torrent.destroy(cb) + } }) - if (self.dht) tasks.push(function (cb) { self.dht.destroy(cb) }) + if (self._tcpPool) { + tasks.push(function (cb) { + self._tcpPool.destroy(cb) + }) + } + + if (self.dht) { + tasks.push(function (cb) { + self.dht.destroy(cb) + }) + } parallel(tasks, cb) + + if (err) self.emit('error', err) +} + +WebTorrent.prototype._onListening = function () { + this.listening = true + + if (this._tcpPool) { + // Sometimes server.address() returns `null` in Docker. + // WebTorrent issue: https://github.com/feross/bittorrent-swarm/pull/18 + this.torrentPort = (this._tcpPool.server.address() || { port: 0 }).port + } + + this.emit('listening') } /** |