From 27327915e92ee6058be6441a01cd937aa8c1bcd4 Mon Sep 17 00:00:00 2001 From: KayleePop <34007889+KayleePop@users.noreply.github.com> Date: Sun, 26 Aug 2018 14:13:13 -0500 Subject: remove `self = this` in torrent.js --- lib/torrent.js | 690 +++++++++++++++++++++++++++------------------------------ 1 file changed, 328 insertions(+), 362 deletions(-) (limited to 'lib') diff --git a/lib/torrent.js b/lib/torrent.js index a32326a..5f86228 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -179,10 +179,9 @@ class Torrent extends EventEmitter { } get _numConns () { - const self = this let numConns = 0 - for (const id in self._peers) { - if (self._peers[id].connected) numConns += 1 + for (const id in this._peers) { + if (this._peers[id].connected) numConns += 1 } return numConns } @@ -194,61 +193,59 @@ class Torrent extends EventEmitter { } _onTorrentId (torrentId) { - const self = this - if (self.destroyed) return + if (this.destroyed) return let parsedTorrent try { parsedTorrent = parseTorrent(torrentId) } catch (err) {} if (parsedTorrent) { // Attempt to set infoHash property synchronously - self.infoHash = parsedTorrent.infoHash - self._debugId = parsedTorrent.infoHash.toString('hex').substring(0, 7) + this.infoHash = parsedTorrent.infoHash + this._debugId = parsedTorrent.infoHash.toString('hex').substring(0, 7) process.nextTick(() => { - if (self.destroyed) return - self._onParsedTorrent(parsedTorrent) + if (this.destroyed) return + this._onParsedTorrent(parsedTorrent) }) } else { // If torrentId failed to parse, it could be in a form that requires an async // operation, i.e. http/https link, filesystem path, or Blob. parseTorrent.remote(torrentId, (err, parsedTorrent) => { - if (self.destroyed) return - if (err) return self._destroy(err) - self._onParsedTorrent(parsedTorrent) + if (this.destroyed) return + if (err) return this._destroy(err) + this._onParsedTorrent(parsedTorrent) }) } } _onParsedTorrent (parsedTorrent) { - const self = this - if (self.destroyed) return + if (this.destroyed) return - self._processParsedTorrent(parsedTorrent) + this._processParsedTorrent(parsedTorrent) - if (!self.infoHash) { - return self._destroy(new Error('Malformed torrent data: No info hash')) + if (!this.infoHash) { + return this._destroy(new Error('Malformed torrent data: No info hash')) } - if (!self.path) self.path = path.join(TMP, self.infoHash) + if (!this.path) this.path = path.join(TMP, this.infoHash) - self._rechokeIntervalId = setInterval(() => { - self._rechoke() + this._rechokeIntervalId = setInterval(() => { + this._rechoke() }, RECHOKE_INTERVAL) - if (self._rechokeIntervalId.unref) self._rechokeIntervalId.unref() + if (this._rechokeIntervalId.unref) this._rechokeIntervalId.unref() // Private 'infoHash' event allows client.add to check for duplicate torrents and // destroy them before the normal 'infoHash' event is emitted. Prevents user // applications from needing to deal with duplicate 'infoHash' events. - self.emit('_infoHash', self.infoHash) - if (self.destroyed) return + this.emit('_infoHash', this.infoHash) + if (this.destroyed) return - self.emit('infoHash', self.infoHash) - if (self.destroyed) return // user might destroy torrent in event handler + this.emit('infoHash', this.infoHash) + if (this.destroyed) return // user might destroy torrent in event handler - if (self.client.listening) { - self._onListening() + if (this.client.listening) { + this._onListening() } else { - self.client.once('listening', () => { - self._onListening() + this.client.once('listening', () => { + this._onListening() }) } } @@ -281,24 +278,23 @@ class Torrent extends EventEmitter { } _onListening () { - const self = this - if (self.discovery || self.destroyed) return + if (this.discovery || this.destroyed) return - let trackerOpts = self.client.tracker + let trackerOpts = this.client.tracker if (trackerOpts) { - trackerOpts = extend(self.client.tracker, { - getAnnounceOpts () { + trackerOpts = extend(this.client.tracker, { + getAnnounceOpts: () => { const opts = { - uploaded: self.uploaded, - downloaded: self.downloaded, - left: Math.max(self.length - self.downloaded, 0) + uploaded: this.uploaded, + downloaded: this.downloaded, + left: Math.max(this.length - this.downloaded, 0) } - if (self.client.tracker.getAnnounceOpts) { - extendMutable(opts, self.client.tracker.getAnnounceOpts()) + if (this.client.tracker.getAnnounceOpts) { + extendMutable(opts, this.client.tracker.getAnnounceOpts()) } - if (self._getAnnounceOpts) { + if (this._getAnnounceOpts) { // TODO: consider deprecating this, as it's redundant with the former case - extendMutable(opts, self._getAnnounceOpts()) + extendMutable(opts, this._getAnnounceOpts()) } return opts } @@ -306,58 +302,54 @@ class Torrent extends EventEmitter { } // begin discovering peers via DHT and trackers - self.discovery = new Discovery({ - infoHash: self.infoHash, - announce: self.announce, - peerId: self.client.peerId, - dht: !self.private && self.client.dht, + this.discovery = new Discovery({ + infoHash: this.infoHash, + announce: this.announce, + peerId: this.client.peerId, + dht: !this.private && this.client.dht, tracker: trackerOpts, - port: self.client.torrentPort, + port: this.client.torrentPort, userAgent: USER_AGENT }) - self.discovery.on('error', onError) - self.discovery.on('peer', onPeer) - self.discovery.on('trackerAnnounce', onTrackerAnnounce) - self.discovery.on('dhtAnnounce', onDHTAnnounce) - self.discovery.on('warning', onWarning) - - function onError (err) { - self._destroy(err) - } + this.discovery.on('error', (err) => { + this._destroy(err) + }) - function onPeer (peer) { + this.discovery.on('peer', (peer) => { // Don't create new outgoing TCP connections when torrent is done - if (typeof peer === 'string' && self.done) return - self.addPeer(peer) - } + if (typeof peer === 'string' && this.done) return + this.addPeer(peer) + }) - function onTrackerAnnounce () { - self.emit('trackerAnnounce') - if (self.numPeers === 0) self.emit('noPeers', 'tracker') - } + this.discovery.on('trackerAnnounce', () => { + this.emit('trackerAnnounce') + if (this.numPeers === 0) this.emit('noPeers', 'tracker') + }) - function onDHTAnnounce () { - self.emit('dhtAnnounce') - if (self.numPeers === 0) self.emit('noPeers', 'dht') - } + this.discovery.on('dhtAnnounce', () => { + this.emit('dhtAnnounce') + if (this.numPeers === 0) this.emit('noPeers', 'dht') + }) - function onWarning (err) { - self.emit('warning', err) - } + this.discovery.on('warning', (err) => { + this.emit('warning', err) + }) - if (self.info) { + if (this.info) { // if full metadata was included in initial torrent id, use it immediately. Otherwise, // wait for torrent-discovery to find peers and ut_metadata to get the metadata. - self._onMetadata(self) - } else if (self.xs) { - self._getMetadataFromServer() + this._onMetadata(this) + } else if (this.xs) { + this._getMetadataFromServer() } } _getMetadataFromServer () { + // to allow function hoisting const self = this - const urls = Array.isArray(self.xs) ? self.xs : [ self.xs ] + + const urls = Array.isArray(this.xs) ? this.xs : [ this.xs ] const tasks = urls.map(url => cb => { getMetadataFromURL(url, cb) @@ -425,14 +417,13 @@ class Torrent extends EventEmitter { * Called when the full torrent metadata is received. */ _onMetadata (metadata) { - const self = this - if (self.metadata || self.destroyed) return - self._debug('got metadata') + if (this.metadata || this.destroyed) return + this._debug('got metadata') - self._xsRequests.forEach(req => { + this._xsRequests.forEach(req => { req.abort() }) - self._xsRequests = [] + this._xsRequests = [] let parsedTorrent if (metadata && metadata.infoHash) { @@ -442,99 +433,99 @@ class Torrent extends EventEmitter { try { parsedTorrent = parseTorrent(metadata) } catch (err) { - return self._destroy(err) + return this._destroy(err) } } - self._processParsedTorrent(parsedTorrent) - self.metadata = self.torrentFile + this._processParsedTorrent(parsedTorrent) + this.metadata = this.torrentFile // add web seed urls (BEP19) - if (self.client.enableWebSeeds) { - self.urlList.forEach(url => { - self.addWebSeed(url) + if (this.client.enableWebSeeds) { + this.urlList.forEach(url => { + this.addWebSeed(url) }) } - self._rarityMap = new RarityMap(self) + this._rarityMap = new RarityMap(this) - self.store = new ImmediateChunkStore( - new self._store(self.pieceLength, { + this.store = new ImmediateChunkStore( + new this._store(this.pieceLength, { torrent: { - infoHash: self.infoHash + infoHash: this.infoHash }, - files: self.files.map(file => ({ - path: path.join(self.path, file.path), + files: this.files.map(file => ({ + path: path.join(this.path, file.path), length: file.length, offset: file.offset })), - length: self.length + length: this.length }) ) - self.files = self.files.map(file => new File(self, file)) + this.files = this.files.map(file => new File(this, file)) // Select only specified files (BEP53) http://www.bittorrent.org/beps/bep_0053.html - if (self.so) { - const selectOnlyFiles = parseRange.parse(self.so) + if (this.so) { + const selectOnlyFiles = parseRange.parse(this.so) - self.files.forEach((v, i) => { - if (selectOnlyFiles.includes(i)) self.files[i].select(true) + this.files.forEach((v, i) => { + if (selectOnlyFiles.includes(i)) this.files[i].select(true) }) } else { // start off selecting the entire torrent with low priority - if (self.pieces.length !== 0) { - self.select(0, self.pieces.length - 1, false) + if (this.pieces.length !== 0) { + this.select(0, this.pieces.length - 1, false) } } - self._hashes = self.pieces + this._hashes = this.pieces - self.pieces = self.pieces.map((hash, i) => { - const pieceLength = (i === self.pieces.length - 1) - ? self.lastPieceLength - : self.pieceLength + this.pieces = this.pieces.map((hash, i) => { + const pieceLength = (i === this.pieces.length - 1) + ? this.lastPieceLength + : this.pieceLength return new Piece(pieceLength) }) - self._reservations = self.pieces.map(() => []) + this._reservations = this.pieces.map(() => []) - self.bitfield = new BitField(self.pieces.length) + this.bitfield = new BitField(this.pieces.length) - self.wires.forEach(wire => { + this.wires.forEach(wire => { // If we didn't have the metadata at the time ut_metadata was initialized for this // wire, we still want to make it available to the peer in case they request it. - if (wire.ut_metadata) wire.ut_metadata.setMetadata(self.metadata) + if (wire.ut_metadata) wire.ut_metadata.setMetadata(this.metadata) - self._onWireWithMetadata(wire) + this._onWireWithMetadata(wire) }) - if (self.skipVerify) { + if (this.skipVerify) { // Skip verifying exisitng data and just assume it's correct - self._markAllVerified() - self._onStore() + this._markAllVerified() + this._onStore() } else { - self._debug('verifying existing torrent data') - if (self._fileModtimes && self._store === FSChunkStore) { + this._debug('verifying existing torrent data') + if (this._fileModtimes && this._store === FSChunkStore) { // don't verify if the files haven't been modified since we last checked - self.getFileModtimes((err, fileModtimes) => { - if (err) return self._destroy(err) + this.getFileModtimes((err, fileModtimes) => { + if (err) return this._destroy(err) - const unchanged = self.files.map((_, index) => fileModtimes[index] === self._fileModtimes[index]).every(x => x) + const unchanged = this.files.map((_, index) => fileModtimes[index] === this._fileModtimes[index]).every(x => x) if (unchanged) { - self._markAllVerified() - self._onStore() + this._markAllVerified() + this._onStore() } else { - self._verifyPieces() + this._verifyPieces() } }) } else { - self._verifyPieces() + this._verifyPieces() } } - self.emit('metadata') + this.emit('metadata') } /* @@ -543,46 +534,44 @@ class Torrent extends EventEmitter { * Only valid in Node, not in the browser. */ getFileModtimes (cb) { - const self = this const ret = [] - parallelLimit(self.files.map((file, index) => cb => { - fs.stat(path.join(self.path, file.path), (err, stat) => { + parallelLimit(this.files.map((file, index) => cb => { + fs.stat(path.join(this.path, file.path), (err, stat) => { if (err && err.code !== 'ENOENT') return cb(err) ret[index] = stat && stat.mtime.getTime() cb(null) }) }), FILESYSTEM_CONCURRENCY, err => { - self._debug('done getting file modtimes') + this._debug('done getting file modtimes') cb(err, ret) }) } _verifyPieces () { - const self = this - parallelLimit(self.pieces.map((_, index) => cb => { - if (self.destroyed) return cb(new Error('torrent is destroyed')) + parallelLimit(this.pieces.map((_, index) => cb => { + if (this.destroyed) return cb(new Error('torrent is destroyed')) - self.store.get(index, (err, buf) => { - if (self.destroyed) return cb(new Error('torrent is destroyed')) + this.store.get(index, (err, buf) => { + if (this.destroyed) return cb(new Error('torrent is destroyed')) if (err) return process.nextTick(cb, null) // ignore error sha1(buf, hash => { - if (self.destroyed) return cb(new Error('torrent is destroyed')) + if (this.destroyed) return cb(new Error('torrent is destroyed')) - if (hash === self._hashes[index]) { - if (!self.pieces[index]) return - self._debug('piece verified %s', index) - self._markVerified(index) + if (hash === this._hashes[index]) { + if (!this.pieces[index]) return + this._debug('piece verified %s', index) + this._markVerified(index) } else { - self._debug('piece invalid %s', index) + this._debug('piece invalid %s', index) } cb(null) }) }) }), FILESYSTEM_CONCURRENCY, err => { - if (err) return self._destroy(err) - self._debug('done verifying') - self._onStore() + if (err) return this._destroy(err) + this._debug('done verifying') + this._onStore() }) } @@ -602,64 +591,61 @@ class Torrent extends EventEmitter { * Called when the metadata, listening server, and underlying chunk store is initialized. */ _onStore () { - const self = this - if (self.destroyed) return - self._debug('on store') + if (this.destroyed) return + this._debug('on store') - self.ready = true - self.emit('ready') + this.ready = true + this.emit('ready') // Files may start out done if the file was already in the store - self._checkDone() + this._checkDone() // In case any selections were made before torrent was ready - self._updateSelections() + this._updateSelections() } destroy (cb) { - const self = this - self._destroy(null, cb) + this._destroy(null, cb) } _destroy (err, cb) { - const self = this - if (self.destroyed) return - self.destroyed = true - self._debug('destroy') + if (this.destroyed) return + this.destroyed = true + this._debug('destroy') - self.client._remove(self) + this.client._remove(this) - clearInterval(self._rechokeIntervalId) + clearInterval(this._rechokeIntervalId) - self._xsRequests.forEach(req => { + this._xsRequests.forEach(req => { req.abort() }) - if (self._rarityMap) { - self._rarityMap.destroy() + if (this._rarityMap) { + this._rarityMap.destroy() } - for (const id in self._peers) { - self.removePeer(id) + for (const id in this._peers) { + this.removePeer(id) } - self.files.forEach(file => { + this.files.forEach(file => { if (file instanceof File) file._destroy() }) - const tasks = self._servers.map(server => cb => { + const tasks = this._servers.map(server => cb => { server.destroy(cb) }) - if (self.discovery) { + if (this.discovery) { tasks.push(cb => { - self.discovery.destroy(cb) + this.discovery.destroy(cb) }) } - if (self.store) { + if (this.store) { tasks.push(cb => { - self.store.close(cb) + this.store.close(cb) }) } @@ -673,39 +659,38 @@ class Torrent extends EventEmitter { // errors versus torrent errors. Torrent errors are not fatal, and the client // is still usable afterwards. Therefore, always listen for errors in both // places (`client.on('error')` and `torrent.on('error')`). - if (self.listenerCount('error') === 0) { - self.client.emit('error', err) + if (this.listenerCount('error') === 0) { + this.client.emit('error', err) } else { - self.emit('error', err) + this.emit('error', err) } } - self.emit('close') + this.emit('close') - self.client = null - self.files = [] - self.discovery = null - self.store = null - self._rarityMap = null - self._peers = null - self._servers = null - self._xsRequests = null + this.client = null + this.files = [] + this.discovery = null + this.store = null + this._rarityMap = null + this._peers = null + this._servers = null + this._xsRequests = null } addPeer (peer) { - const self = this - if (self.destroyed) throw new Error('torrent is destroyed') - if (!self.infoHash) throw new Error('addPeer() must not be called before the `infoHash` event') + if (this.destroyed) throw new Error('torrent is destroyed') + if (!this.infoHash) throw new Error('addPeer() must not be called before the `infoHash` event') - if (self.client.blocked) { + if (this.client.blocked) { let host if (typeof peer === 'string') { let parts try { parts = addrToIPPort(peer) } catch (e) { - self._debug('ignoring peer: invalid %s', peer) - self.emit('invalidPeer', peer) + this._debug('ignoring peer: invalid %s', peer) + this.emit('invalidPeer', peer) return false } host = parts[0] @@ -713,65 +698,64 @@ class Torrent extends EventEmitter { host = peer.remoteAddress } - if (host && self.client.blocked.contains(host)) { - self._debug('ignoring peer: blocked %s', peer) + if (host && this.client.blocked.contains(host)) { + this._debug('ignoring peer: blocked %s', peer) if (typeof peer !== 'string') peer.destroy() - self.emit('blockedPeer', peer) + this.emit('blockedPeer', peer) return false } } - const wasAdded = !!self._addPeer(peer) + const wasAdded = !!this._addPeer(peer) if (wasAdded) { - self.emit('peer', peer) + this.emit('peer', peer) } else { - self.emit('invalidPeer', peer) + this.emit('invalidPeer', peer) } return wasAdded } _addPeer (peer) { - const self = this - if (self.destroyed) { + if (this.destroyed) { if (typeof peer !== 'string') peer.destroy() return null } - if (typeof peer === 'string' && !self._validAddr(peer)) { - self._debug('ignoring peer: invalid %s', peer) + if (typeof peer === 'string' && !this._validAddr(peer)) { + this._debug('ignoring peer: invalid %s', peer) return null } const id = (peer && peer.id) || peer - if (self._peers[id]) { - self._debug('ignoring peer: duplicate (%s)', id) + if (this._peers[id]) { + this._debug('ignoring peer: duplicate (%s)', id) if (typeof peer !== 'string') peer.destroy() return null } - if (self.paused) { - self._debug('ignoring peer: torrent is paused') + if (this.paused) { + this._debug('ignoring peer: torrent is paused') if (typeof peer !== 'string') peer.destroy() return null } - self._debug('add peer %s', id) + this._debug('add peer %s', id) let newPeer if (typeof peer === 'string') { // `peer` is an addr ("ip:port" string) - newPeer = Peer.createTCPOutgoingPeer(peer, self) + newPeer = Peer.createTCPOutgoingPeer(peer, this) } else { // `peer` is a WebRTC connection (simple-peer) - newPeer = Peer.createWebRTCPeer(peer, self) + newPeer = Peer.createWebRTCPeer(peer, this) } - self._peers[newPeer.id] = newPeer - self._peersLength += 1 + this._peers[newPeer.id] = newPeer + this._peersLength += 1 if (typeof peer === 'string') { // `peer` is an addr ("ip:port" string) - self._queue.push(newPeer) - self._drain() + this._queue.push(newPeer) + this._drain() } return newPeer @@ -806,46 +790,43 @@ class Torrent extends EventEmitter { * peer that has already sent a handshake. */ _addIncomingPeer (peer) { - const self = this - if (self.destroyed) return peer.destroy(new Error('torrent is destroyed')) - if (self.paused) return peer.destroy(new Error('torrent is paused')) + if (this.destroyed) return peer.destroy(new Error('torrent is destroyed')) + if (this.paused) return peer.destroy(new Error('torrent is paused')) this._debug('add incoming peer %s', peer.id) - self._peers[peer.id] = peer - self._peersLength += 1 + this._peers[peer.id] = peer + this._peersLength += 1 } removePeer (peer) { - const self = this const id = (peer && peer.id) || peer - peer = self._peers[id] + peer = this._peers[id] if (!peer) return this._debug('removePeer %s', id) - delete self._peers[id] - self._peersLength -= 1 + delete this._peers[id] + this._peersLength -= 1 peer.destroy() // If torrent swarm was at capacity before, try to open a new connection now - self._drain() + this._drain() } select (start, end, priority, notify) { - const self = this - if (self.destroyed) throw new Error('torrent is destroyed') + if (this.destroyed) throw new Error('torrent is destroyed') - if (start < 0 || end < start || self.pieces.length <= end) { + if (start < 0 || end < start || this.pieces.length <= end) { throw new Error('invalid selection ', start, ':', end) } priority = Number(priority) || 0 - self._debug('select %s-%s (priority %s)', start, end, priority) + this._debug('select %s-%s (priority %s)', start, end, priority) - self._selections.push({ + this._selections.push({ from: start, to: end, offset: 0, @@ -853,65 +834,62 @@ class Torrent extends EventEmitter { notify: notify || noop }) - self._selections.sort((a, b) => b.priority - a.priority) + this._selections.sort((a, b) => b.priority - a.priority) - self._updateSelections() + this._updateSelections() } deselect (start, end, priority) { - const self = this - if (self.destroyed) throw new Error('torrent is destroyed') + if (this.destroyed) throw new Error('torrent is destroyed') priority = Number(priority) || 0 - self._debug('deselect %s-%s (priority %s)', start, end, priority) + this._debug('deselect %s-%s (priority %s)', start, end, priority) - for (let i = 0; i < self._selections.length; ++i) { - const s = self._selections[i] + for (let i = 0; i < this._selections.length; ++i) { + const s = this._selections[i] if (s.from === start && s.to === end && s.priority === priority) { - self._selections.splice(i, 1) + this._selections.splice(i, 1) break } } - self._updateSelections() + this._updateSelections() } critical (start, end) { - const self = this - if (self.destroyed) throw new Error('torrent is destroyed') + if (this.destroyed) throw new Error('torrent is destroyed') - self._debug('critical %s-%s', start, end) + this._debug('critical %s-%s', start, end) for (let i = start; i <= end; ++i) { - self._critical[i] = true + this._critical[i] = true } - self._updateSelections() + this._updateSelections() } _onWire (wire, addr) { - const self = this - self._debug('got wire %s (%s)', wire._debugId, addr || 'Unknown') + this._debug('got wire %s (%s)', wire._debugId, addr || 'Unknown') wire.on('download', downloaded => { - if (self.destroyed) return - self.received += downloaded - self._downloadSpeed(downloaded) - self.client._downloadSpeed(downloaded) - self.emit('download', downloaded) - self.client.emit('download', downloaded) + if (this.destroyed) return + this.received += downloaded + this._downloadSpeed(downloaded) + this.client._downloadSpeed(downloaded) + this.emit('download', downloaded) + this.client.emit('download', downloaded) }) wire.on('upload', uploaded => { - if (self.destroyed) return - self.uploaded += uploaded - self._uploadSpeed(uploaded) - self.client._uploadSpeed(uploaded) - self.emit('upload', uploaded) - self.client.emit('upload', uploaded) + if (this.destroyed) return + this.uploaded += uploaded + this._uploadSpeed(uploaded) + this.client._uploadSpeed(uploaded) + this.emit('upload', uploaded) + this.client.emit('upload', uploaded) }) - self.wires.push(wire) + this.wires.push(wire) if (addr) { // Sometimes RTCPeerConnection.getStats() doesn't return an ip:port for peers @@ -921,25 +899,25 @@ class Torrent extends EventEmitter { } // When peer sends PORT message, add that DHT node to routing table - if (self.client.dht && self.client.dht.listening) { + if (this.client.dht && this.client.dht.listening) { wire.on('port', port => { - if (self.destroyed || self.client.dht.destroyed) { + if (this.destroyed || this.client.dht.destroyed) { return } if (!wire.remoteAddress) { - return self._debug('ignoring PORT from peer with no address') + return this._debug('ignoring PORT from peer with no address') } if (port === 0 || port > 65536) { - return self._debug('ignoring invalid PORT from peer') + return this._debug('ignoring invalid PORT from peer') } - self._debug('port: %s (from %s)', port, addr) - self.client.dht.addNode({ host: wire.remoteAddress, port }) + this._debug('port: %s (from %s)', port, addr) + this.client.dht.addNode({ host: wire.remoteAddress, port }) }) } wire.on('timeout', () => { - self._debug('wire timeout (%s)', addr) + this._debug('wire timeout (%s)', addr) // TODO: this might be destroying wires too eagerly wire.destroy() }) @@ -951,38 +929,38 @@ class Torrent extends EventEmitter { wire.setKeepAlive(true) // use ut_metadata extension - wire.use(utMetadata(self.metadata)) + wire.use(utMetadata(this.metadata)) wire.ut_metadata.on('warning', err => { - self._debug('ut_metadata warning: %s', err.message) + this._debug('ut_metadata warning: %s', err.message) }) - if (!self.metadata) { + if (!this.metadata) { wire.ut_metadata.on('metadata', metadata => { - self._debug('got metadata via ut_metadata') - self._onMetadata(metadata) + this._debug('got metadata via ut_metadata') + this._onMetadata(metadata) }) wire.ut_metadata.fetch() } // use ut_pex extension if the torrent is not flagged as private - if (typeof utPex === 'function' && !self.private) { + if (typeof utPex === 'function' && !this.private) { wire.use(utPex()) wire.ut_pex.on('peer', peer => { // Only add potential new peers when we're not seeding - if (self.done) return - self._debug('ut_pex: got peer: %s (from %s)', peer, addr) - self.addPeer(peer) + if (this.done) return + this._debug('ut_pex: got peer: %s (from %s)', peer, addr) + this.addPeer(peer) }) wire.ut_pex.on('dropped', peer => { // the remote peer believes a given peer has been dropped from the torrent swarm. // if we're not currently connected to it, then remove it from the queue. - const peerObj = self._peers[peer] + const peerObj = this._peers[peer] if (peerObj && !peerObj.connected) { - self._debug('ut_pex: dropped peer: %s (from %s)', peer, addr) - self.removePeer(peer) + this._debug('ut_pex: dropped peer: %s (from %s)', peer, addr) + this.removePeer(peer) } }) @@ -994,25 +972,24 @@ class Torrent extends EventEmitter { // Hook to allow user-defined `bittorrent-protocol` extensions // More info: https://github.com/webtorrent/bittorrent-protocol#extension-api - self.emit('wire', wire, addr) + this.emit('wire', wire, addr) - if (self.metadata) { + if (this.metadata) { process.nextTick(() => { // This allows wire.handshake() to be called (by Peer.onHandshake) before any // messages get sent on the wire - self._onWireWithMetadata(wire) + this._onWireWithMetadata(wire) }) } } _onWireWithMetadata (wire) { - const self = this let timeoutId = null - function onChokeTimeout () { - if (self.destroyed || wire.destroyed) return + const onChokeTimeout = () => { + if (this.destroyed || wire.destroyed) return - if (self._numQueued > 2 * (self._numConns - self.numPeers) && + if (this._numQueued > 2 * (this._numConns - this.numPeers) && wire.amInterested) { wire.destroy() } else { @@ -1022,9 +999,9 @@ class Torrent extends EventEmitter { } let i - function updateSeedStatus () { - if (wire.peerPieces.buffer.length !== self.bitfield.buffer.length) return - for (i = 0; i < self.pieces.length; ++i) { + const updateSeedStatus = () => { + if (wire.peerPieces.buffer.length !== this.bitfield.buffer.length) return + for (i = 0; i < this.pieces.length; ++i) { if (!wire.peerPieces.get(i)) return } wire.isSeeder = true @@ -1033,12 +1010,12 @@ class Torrent extends EventEmitter { wire.on('bitfield', () => { updateSeedStatus() - self._update() + this._update() }) wire.on('have', () => { updateSeedStatus() - self._update() + this._update() }) wire.once('interested', () => { @@ -1057,7 +1034,7 @@ class Torrent extends EventEmitter { wire.on('unchoke', () => { clearTimeout(timeoutId) - self._update() + this._update() }) wire.on('request', (index, offset, length, cb) => { @@ -1065,16 +1042,16 @@ class Torrent extends EventEmitter { // Per spec, disconnect from peers that request >128KB return wire.destroy() } - if (self.pieces[index]) return - self.store.get(index, { offset, length }, cb) + if (this.pieces[index]) return + this.store.get(index, { offset, length }, cb) }) - wire.bitfield(self.bitfield) // always send bitfield (required) + wire.bitfield(this.bitfield) // always send bitfield (required) wire.uninterested() // always start out uninterested (as per protocol) // Send PORT message to peers that support DHT - if (wire.peerExtensions.dht && self.client.dht && self.client.dht.listening) { - wire.port(self.client.dht.address().port) + if (wire.peerExtensions.dht && this.client.dht && this.client.dht.listening) { + wire.port(this.client.dht.address().port) } if (wire.type !== 'webSeed') { // do not choke on webseeds @@ -1090,58 +1067,53 @@ class Torrent extends EventEmitter { * Called on selection changes. */ _updateSelections () { - const self = this - if (!self.ready || self.destroyed) return + if (!this.ready || this.destroyed) return process.nextTick(() => { - self._gcSelections() + this._gcSelections() }) - self._updateInterest() - self._update() + this._updateInterest() + this._update() } /** * Garbage collect selections with respect to the store's current state. */ _gcSelections () { - const self = this - - for (let i = 0; i < self._selections.length; ++i) { - const s = self._selections[i] + for (let i = 0; i < this._selections.length; ++i) { + const s = this._selections[i] const oldOffset = s.offset // check for newly downloaded pieces in selection - while (self.bitfield.get(s.from + s.offset) && s.from + s.offset < s.to) { + while (this.bitfield.get(s.from + s.offset) && s.from + s.offset < s.to) { s.offset += 1 } if (oldOffset !== s.offset) s.notify() if (s.to !== s.from + s.offset) continue - if (!self.bitfield.get(s.from + s.offset)) continue + if (!this.bitfield.get(s.from + s.offset)) continue - self._selections.splice(i, 1) // remove fully downloaded selection + this._selections.splice(i, 1) // remove fully downloaded selection i -= 1 // decrement i to offset splice s.notify() - self._updateInterest() + this._updateInterest() } - if (!self._selections.length) self.emit('idle') + if (!this._selections.length) this.emit('idle') } /** * Update interested status for all peers. */ _updateInterest () { - const self = this + const prev = this._amInterested + this._amInterested = !!this._selections.length - const prev = self._amInterested - self._amInterested = !!self._selections.length - - self.wires.forEach(wire => { + this.wires.forEach(wire => { let interested = false - for (let index = 0; index < self.pieces.length; ++index) { - if (self.pieces[index] && wire.peerPieces.get(index)) { + for (let index = 0; index < this.pieces.length; ++index) { + if (this.pieces[index] && wire.peerPieces.get(index)) { interested = true break } @@ -1151,23 +1123,22 @@ class Torrent extends EventEmitter { else wire.uninterested() }) - if (prev === self._amInterested) return - if (self._amInterested) self.emit('interested') - else self.emit('uninterested') + if (prev === this._amInterested) return + if (this._amInterested) this.emit('interested') + else this.emit('uninterested') } /** * Heartbeat to update all peers and their requests. */ _update () { - const self = this - if (self.destroyed) return + if (this.destroyed) return // update wires in random order for better request distribution - const ite = randomIterate(self.wires) + const ite = randomIterate(this.wires) let wire while ((wire = ite())) { - self._updateWire(wire) + this._updateWire(wire) } } @@ -1175,6 +1146,7 @@ class Torrent extends EventEmitter { * Attempts to update a peer's requests */ _updateWire (wire) { + // to allow function hoisting const self = this if (wire.peerChoking) return @@ -1321,16 +1293,15 @@ class Torrent extends EventEmitter { * unchoking as described in BEP3. */ _rechoke () { - const self = this - if (!self.ready) return + if (!this.ready) return - if (self._rechokeOptimisticTime > 0) self._rechokeOptimisticTime -= 1 - else self._rechokeOptimisticWire = null + if (this._rechokeOptimisticTime > 0) this._rechokeOptimisticTime -= 1 + else this._rechokeOptimisticWire = null const peers = [] - self.wires.forEach(wire => { - if (!wire.isSeeder && wire !== self._rechokeOptimisticWire) { + this.wires.forEach(wire => { + if (!wire.isSeeder && wire !== this._rechokeOptimisticWire) { peers.push({ wire, downloadSpeed: wire.downloadSpeed(), @@ -1345,20 +1316,20 @@ class Torrent extends EventEmitter { let unchokeInterested = 0 let i = 0 - for (; i < peers.length && unchokeInterested < self._rechokeNumSlots; ++i) { + for (; i < peers.length && unchokeInterested < this._rechokeNumSlots; ++i) { peers[i].isChoked = false if (peers[i].wire.peerInterested) unchokeInterested += 1 } // Optimistically unchoke a peer - if (!self._rechokeOptimisticWire && i < peers.length && self._rechokeNumSlots) { + if (!this._rechokeOptimisticWire && i < peers.length && this._rechokeNumSlots) { const candidates = peers.slice(i).filter(peer => peer.wire.peerInterested) const optimistic = candidates[randomInt(candidates.length)] if (optimistic) { optimistic.isChoked = false - self._rechokeOptimisticWire = optimistic.wire - self._rechokeOptimisticTime = RECHOKE_OPTIMISTIC_DURATION + this._rechokeOptimisticWire = optimistic.wire + this._rechokeOptimisticTime = RECHOKE_OPTIMISTIC_DURATION } } @@ -1396,13 +1367,11 @@ class Torrent extends EventEmitter { * given wire may effectively swap out the request for one of its own. */ _hotswap (wire, index) { - const self = this - const speed = wire.downloadSpeed() if (speed < Piece.BLOCK_LENGTH) return false - if (!self._reservations[index]) return false + if (!this._reservations[index]) return false - const r = self._reservations[index] + const r = this._reservations[index] if (!r) { return false } @@ -1433,10 +1402,10 @@ class Torrent extends EventEmitter { const req = minWire.requests[i] if (req.piece !== index) continue - self.pieces[index].cancel((req.offset / Piece.BLOCK_LENGTH) | 0) + this.pieces[index].cancel((req.offset / Piece.BLOCK_LENGTH) | 0) } - self.emit('hotswap', minWire, wire, index) + this.emit('hotswap', minWire, wire, index) return true } @@ -1545,58 +1514,56 @@ class Torrent extends EventEmitter { } _checkDone () { - const self = this - if (self.destroyed) return + if (this.destroyed) return // are any new files done? - self.files.forEach(file => { + this.files.forEach(file => { if (file.done) return for (let i = file._startPiece; i <= file._endPiece; ++i) { - if (!self.bitfield.get(i)) return + if (!this.bitfield.get(i)) return } file.done = true file.emit('done') - self._debug(`file done: ${file.name}`) + this._debug(`file done: ${file.name}`) }) // is the torrent done? (if all current selections are satisfied, or there are // no selections, then torrent is done) let done = true - for (let i = 0; i < self._selections.length; i++) { - const selection = self._selections[i] + for (let i = 0; i < this._selections.length; i++) { + const selection = this._selections[i] for (let piece = selection.from; piece <= selection.to; piece++) { - if (!self.bitfield.get(piece)) { + if (!this.bitfield.get(piece)) { done = false break } } if (!done) break } - if (!self.done && done) { - self.done = true - self._debug(`torrent done: ${self.infoHash}`) - self.emit('done') + if (!this.done && done) { + this.done = true + this._debug(`torrent done: ${this.infoHash}`) + this.emit('done') } - self._gcSelections() + this._gcSelections() return done } load (streams, cb) { - const self = this - if (self.destroyed) throw new Error('torrent is destroyed') - if (!self.ready) return self.once('ready', () => { self.load(streams, cb) }) + if (this.destroyed) throw new Error('torrent is destroyed') + if (!this.ready) return this.once('ready', () => { this.load(streams, cb) }) if (!Array.isArray(streams)) streams = [ streams ] if (!cb) cb = noop const readable = new MultiStream(streams) - const writable = new ChunkStoreWriteStream(self.store, self.pieceLength) + const writable = new ChunkStoreWriteStream(this.store, this.pieceLength) pump(readable, writable, err => { if (err) return cb(err) - self._markAllVerified() - self._checkDone() + this._markAllVerified() + this._checkDone() cb(null) }) } @@ -1635,15 +1602,14 @@ class Torrent extends EventEmitter { * queue until another connection closes. */ _drain () { - const self = this - this._debug('_drain numConns %s maxConns %s', self._numConns, self.client.maxConns) - if (typeof net.connect !== 'function' || self.destroyed || self.paused || - self._numConns >= self.client.maxConns) { + this._debug('_drain numConns %s maxConns %s', this._numConns, this.client.maxConns) + if (typeof net.connect !== 'function' || this.destroyed || this.paused || + this._numConns >= this.client.maxConns) { return } - this._debug('drain (%s queued, %s/%s peers)', self._numQueued, self.numPeers, self.client.maxConns) + this._debug('drain (%s queued, %s/%s peers)', this._numQueued, this.numPeers, this.client.maxConns) - const peer = self._queue.shift() + const peer = this._queue.shift() if (!peer) return // queue could be empty this._debug('tcp connect attempt to %s', peer.addr) @@ -1662,12 +1628,12 @@ class Torrent extends EventEmitter { // When connection closes, attempt reconnect after timeout (with exponential backoff) conn.on('close', () => { - if (self.destroyed) return + if (this.destroyed) return // TODO: If torrent is done, do not try to reconnect after a timeout if (peer.retries >= RECONNECT_WAIT.length) { - self._debug( + this._debug( 'conn %s closed: will not re-add (max %s attempts)', peer.addr, RECONNECT_WAIT.length ) @@ -1675,13 +1641,13 @@ class Torrent extends EventEmitter { } const ms = RECONNECT_WAIT[peer.retries] - self._debug( + this._debug( 'conn %s closed: will re-add to queue in %sms (attempt %s)', peer.addr, ms, peer.retries + 1 ) - const reconnectTimeout = setTimeout(function reconnectTimeout () { - const newPeer = self._addPeer(peer.addr) + const reconnectTimeout = setTimeout(() => { + const newPeer = this._addPeer(peer.addr) if (newPeer) newPeer.retries = peer.retries + 1 }, ms) if (reconnectTimeout.unref) reconnectTimeout.unref() -- cgit v1.2.3