diff options
author | Feross Aboukhadijeh <feross@feross.org> | 2016-04-21 11:10:30 +0300 |
---|---|---|
committer | Feross Aboukhadijeh <feross@feross.org> | 2016-04-21 11:10:30 +0300 |
commit | 63e4aee7bd016f258d81708af9c03cf608968816 (patch) | |
tree | 9b28e5e486c8a0bcd53d18a1eed2eb57a879f2b0 /lib/torrent.js | |
parent | a47d2ce4b27896a4c2e2e3820f69c712c2a0de3e (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/torrent.js')
-rw-r--r-- | lib/torrent.js | 33 |
1 files changed, 27 insertions, 6 deletions
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) { |