Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/webtorrent/webtorrent.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFeross Aboukhadijeh <feross@feross.org>2016-04-21 11:10:30 +0300
committerFeross Aboukhadijeh <feross@feross.org>2016-04-21 11:10:30 +0300
commit63e4aee7bd016f258d81708af9c03cf608968816 (patch)
tree9b28e5e486c8a0bcd53d18a1eed2eb57a879f2b0 /lib
parenta47d2ce4b27896a4c2e2e3820f69c712c2a0de3e (diff)
More thorough object cleanup
- Only pass `torrent.infoHash` to the Chunk Store constructor, instead of the `Torrent` instance itself, to prevent accidental memory leaks of the `Torrent` object by the store. (Open an issue if you were using other properties. They can be re-added.) - Non-fatal errors with a single torrent will be emitted at `torrent.on('error')`. You should listen to this event. Previously, all torrent errors were also emitted on `client.on('error')` and handling `torrent.on('error')` was optional. This design is better since now it is possible to distinguish between fatal client errors (`client.on('error')`) when the whole client becomes unusable versus recoverable errors where only a single torrent fails (`torrent.on('error')`) but the client can continue to be used. However, if there is no `torrent.on('error')` event, then the error will be forwarded to `client.on('error')`. This prevents crashing the client when the user only has a listener on the client, but it makes it impossible for them to determine a client error versus a torrent error. - Errors creating a torrent with `client.seed` are now emitted on the returned `torrent` object instead of the client (unless there is no event listeners on `torrent.on('error')` as previously discussed). The torrent object is now also destroyed automatically for the user, as was probably expected. - If `client.get` is passed a `Torrent` instance, it now only returns it if it is present in the client.
Diffstat (limited to 'lib')
-rw-r--r--lib/file.js6
-rw-r--r--lib/rarity-map.js2
-rw-r--r--lib/torrent.js33
3 files changed, 31 insertions, 10 deletions
diff --git a/lib/file.js b/lib/file.js
index bfa032e..c73fc38 100644
--- a/lib/file.js
+++ b/lib/file.js
@@ -1,5 +1,3 @@
-// TODO: cleanup reference to torrent (i.e. Torrent object)
-
module.exports = File
var eos = require('end-of-stream')
@@ -89,3 +87,7 @@ File.prototype.renderTo = function (elem, cb) {
if (typeof window === 'undefined') throw new Error('browser-only method')
render.render(this, elem, cb)
}
+
+File.prototype._destroy = function () {
+ this._torrent = null
+}
diff --git a/lib/rarity-map.js b/lib/rarity-map.js
index c362077..430f62f 100644
--- a/lib/rarity-map.js
+++ b/lib/rarity-map.js
@@ -3,8 +3,6 @@ module.exports = RarityMap
/**
* Mapping of torrent pieces to their respective availability in the torrent swarm. Used
* by the torrent manager for implementing the rarest piece first selection strategy.
- *
- * @param {Torrent} torrent
*/
function RarityMap (torrent) {
var self = this
diff --git a/lib/torrent.js b/lib/torrent.js
index fc5f495..296f579 100644
--- a/lib/torrent.js
+++ b/lib/torrent.js
@@ -92,10 +92,10 @@ function Torrent (torrentId, client, opts) {
this.metadata = null
this.store = null
- this.files = null
+ this.files = []
+ this.pieces = []
this._amInterested = false
- this.pieces = []
this._selections = []
this._critical = []
@@ -253,6 +253,7 @@ Torrent.prototype._onParsedTorrent = function (parsedTorrent) {
if (self._rechokeIntervalId.unref) self._rechokeIntervalId.unref()
self.emit('infoHash', self.infoHash)
+ if (self.destroyed) return // user might destroy torrent in `infoHash` event handler
if (self.client.listening) {
self._onListening()
@@ -371,7 +372,9 @@ Torrent.prototype._onMetadata = function (metadata) {
self.store = new ImmediateChunkStore(
new self._store(self.pieceLength, {
- torrent: self,
+ torrent: {
+ infoHash: self.infoHash
+ },
files: self.files.map(function (file) {
return {
path: path.join(self.path, file.path),
@@ -464,6 +467,7 @@ Torrent.prototype._verifyPieces = function () {
var self = this
parallelLimit(self.pieces.map(function (_, index) {
return function (cb) {
+ if (self.destroyed) return cb(new Error('torrent is destroyed'))
self.store.get(index, function (err, buf) {
if (err) return cb(null) // ignore error
sha1(buf, function (hash) {
@@ -523,7 +527,7 @@ Torrent.prototype._destroy = function (err, cb) {
self.destroyed = true
self._debug('destroy')
- self.client.remove(self)
+ self.client._remove(self)
clearInterval(self._rechokeIntervalId)
@@ -535,6 +539,10 @@ Torrent.prototype._destroy = function (err, cb) {
self.removePeer(id)
}
+ self.files.forEach(function (file) {
+ if (file instanceof File) file._destroy()
+ })
+
var tasks = self._servers.map(function (server) {
return function (cb) {
server.destroy(cb)
@@ -546,6 +554,7 @@ Torrent.prototype._destroy = function (err, cb) {
self.discovery.destroy(cb)
})
}
+
if (self.store) {
tasks.push(function (cb) {
self.store.close(cb)
@@ -555,14 +564,26 @@ Torrent.prototype._destroy = function (err, cb) {
parallel(tasks, cb)
if (err) {
- // When there is no `torrent.on('error')` listener, emit `client.on('error')` instead.
- // The more-specific, torrent error handler is preferred.
+ // Torrent errors are emitted at `torrent.on('error')`. If there are no 'error' event
+ // handlers on the torrent instance, the error will be emitted at
+ // `client.on('error')`. This prevents crashing the user's program, but it makes it
+ // impossible to determine a client error versus a torrent error (where the client
+ // is still usable afterwards). Users are recommended for errors in both places
+ // to distinguish between the error types.
if (self.listenerCount('error') === 0) {
self.client.emit('error', err)
} else {
self.emit('error', err)
}
}
+
+ self.client = null
+ self.files = []
+ self.discovery = null
+ self.store = null
+ self._rarityMap = null
+ self._peers = null
+ self._servers = null
}
Torrent.prototype.addPeer = function (peer) {