From 632436f27f1b1536fccac98b814509c4de8256a8 Mon Sep 17 00:00:00 2001 From: Gleb Arestov Date: Mon, 20 Jul 2015 21:07:44 +0300 Subject: [PATCH 1/2] should remove part of memory leaks closures for callback in event listeners in foreight objects --- lib/torrent.js | 97 +++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/lib/torrent.js b/lib/torrent.js index 2cc0800b..a61234f6 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -101,6 +101,8 @@ function Torrent (torrentId, client, opts) { this._servers = [] if (torrentId !== null) this._onTorrentId(torrentId) + + this._destroyers = [] } Object.defineProperty(Torrent.prototype, 'timeRemaining', { @@ -223,24 +225,25 @@ Torrent.prototype._onParsedTorrent = function (parsedTorrent) { }, maxConns: self.client.maxConns }) - self.swarm.on('error', function (err) { + + listen(self.swarm, 'error', function (err) { self._onError(err) - }) - self.swarm.on('wire', function (wire, addr) { + }, self) + listen(self.swarm, 'wire', function (wire, addr) { self._onWire(wire, addr) - }) + }, self) - self.swarm.on('download', function (downloaded) { + listen(self.swarm, 'download', function (downloaded) { self.client._downloadSpeed(downloaded) // update overall client stats self.client.emit('download', downloaded) self.emit('download', downloaded) - }) + }, self) - self.swarm.on('upload', function (uploaded) { + listen(self.swarm, 'upload', function (uploaded) { self.client._uploadSpeed(uploaded) // update overall client stats self.client.emit('upload', uploaded) self.emit('upload', uploaded) - }) + }, self) // listen for peers (note: in the browser, this is a no-op and callback is called on // next tick) @@ -304,17 +307,18 @@ Torrent.prototype._onSwarmListening = function () { peerId: self.client.peerId, port: self.client.torrentPort }) - self.discovery.on('error', function (err) { + + listen(self.discovery, 'error', function (err) { self._onError(err) - }) - self.discovery.on('peer', function (peer) { + }, self) + listen(self.discovery, 'peer', function (peer) { // Don't create new outgoing TCP connections when torrent is done if (typeof peer === 'string' && self.done) return self.addPeer(peer) - }) + }, self) // expose discovery events - reemit(self.discovery, self, ['trackerAnnounce', 'dhtAnnounce', 'warning']) + addDestroyer(self, reemit(self.discovery, self, ['trackerAnnounce', 'dhtAnnounce', 'warning'])) // if full metadata was included in initial torrent id, use it if (self.info) self._onMetadata(self) @@ -622,7 +626,7 @@ Torrent.prototype._onWire = function (wire, addr) { // When peer sends PORT message, add that DHT node to routing table if (self.client.dht && self.client.dht.listening) { - wire.on('port', function (port) { + listen(wire, 'port', function (port) { if (self.destroyed || self.client.dht.destroyed) { return } @@ -635,14 +639,14 @@ Torrent.prototype._onWire = function (wire, addr) { self._debug('port: %s (from %s)', port, addr) self.client.dht.addNode({ host: wire.remoteAddress, port: port }) - }) + }, self) } - wire.on('timeout', function () { + listen(wire, 'timeout', function () { self._debug('wire timeout (%s)', addr) // TODO: this might be destroying wires too eagerly wire.destroy() - }) + }, self) // Timeout for piece requests to this peer wire.setTimeout(PIECE_TIMEOUT, true) @@ -653,15 +657,15 @@ Torrent.prototype._onWire = function (wire, addr) { // use ut_metadata extension wire.use(ut_metadata(self.metadata)) - wire.ut_metadata.on('warning', function (err) { + listen(wire.ut_metadata, 'warning', function (err) { self._debug('ut_metadata warning: %s', err.message) - }) + }, self) if (!self.metadata) { - wire.ut_metadata.on('metadata', function (metadata) { + listen(wire.ut_metadata, 'metadata', function (metadata) { self._debug('got metadata via ut_metadata') self._onMetadata(metadata) - }) + }, self) wire.ut_metadata.fetch() } @@ -669,14 +673,14 @@ Torrent.prototype._onWire = function (wire, addr) { if (typeof ut_pex === 'function' && !self.private) { wire.use(ut_pex()) - wire.ut_pex.on('peer', function (peer) { + listen(wire.ut_pex, 'peer', function (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) - }) + }, self) - wire.ut_pex.on('dropped', function (peer) { + listen(wire.ut_pex, 'dropped', function (peer) { // the remote peer believes a given peer has been dropped from the swarm. // if we're not currently connected to it, then remove it from the swarm's queue. var peerObj = self.swarm._peers[peer] @@ -686,10 +690,10 @@ Torrent.prototype._onWire = function (wire, addr) { } }) - wire.once('close', function () { + listen(wire, 'close', function () { // Stop sending updates to remote peer wire.ut_pex.reset() - }) + }, self, true) } // Hook to allow user-defined `bittorrent-protocol` extensions @@ -731,43 +735,43 @@ Torrent.prototype._onWireWithMetadata = function (wire) { wire.choke() // always choke seeders } - wire.on('bitfield', function () { + listen(wire, 'bitfield', function () { updateSeedStatus() self._update() - }) + }, self) - wire.on('have', function () { + listen(wire, 'have', function () { updateSeedStatus() self._update() - }) + }, self) - wire.once('interested', function () { + listen(wire, 'interested', function () { wire.unchoke() - }) + }, self, true) - wire.once('close', function () { + listen(wire, 'close', function () { clearTimeout(timeoutId) - }) + }, self, true) - wire.on('choke', function () { + listen(wire, 'choke', function () { clearTimeout(timeoutId) timeoutId = setTimeout(onChokeTimeout, CHOKE_TIMEOUT) if (timeoutId.unref) timeoutId.unref() - }) + }, self) - wire.on('unchoke', function () { + listen(wire, 'unchoke', function () { clearTimeout(timeoutId) self._update() - }) + }, self) - wire.on('request', function (index, offset, length, cb) { + listen(wire, 'request', function (index, offset, length, cb) { if (length > MAX_BLOCK_LENGTH) { // Per spec, disconnect from peers that request >128KB return wire.destroy() } if (self.pieces[index]) return self.store.get(index, { offset: offset, length: length }, cb) - }) + }, self) wire.bitfield(self.bitfield) // always send bitfield (required) wire.interested() // always start out interested @@ -1338,3 +1342,16 @@ function randomInt (high) { } function noop () {} + +function addDestroyer (target, item) { + target._destroyers.push(item) +} + +function listen (source, eventName, cb, target, once) { + var destroyer = function () { + source.removeListener(eventName, cb) + } + addDestroyer(target, destroyer) + source[once ? 'once' : 'on'](eventName, cb) + return destroyer +} From 79e401c1047740c327ba3f969b979d4d00bcd317 Mon Sep 17 00:00:00 2001 From: Gleb Arestov Date: Sun, 22 Mar 2015 10:33:47 +0300 Subject: [PATCH 2/2] npm dep => git submodule --- node_modules/bittorrent-dht | 1 + node_modules/bittorrent-swarm | 1 + node_modules/re-emitter | 1 + node_modules/torrent-discovery | 1 + package.json | 6 ++++++ 5 files changed, 10 insertions(+) create mode 160000 node_modules/bittorrent-dht create mode 160000 node_modules/bittorrent-swarm create mode 160000 node_modules/re-emitter create mode 160000 node_modules/torrent-discovery diff --git a/node_modules/bittorrent-dht b/node_modules/bittorrent-dht new file mode 160000 index 00000000..06d4208a --- /dev/null +++ b/node_modules/bittorrent-dht @@ -0,0 +1 @@ +Subproject commit 06d4208a1267873c925c601dd080a0ad3a4bb1d0 diff --git a/node_modules/bittorrent-swarm b/node_modules/bittorrent-swarm new file mode 160000 index 00000000..7dec3eb0 --- /dev/null +++ b/node_modules/bittorrent-swarm @@ -0,0 +1 @@ +Subproject commit 7dec3eb0a1fbe20ab90fa7141d3dd12bfe80b02b diff --git a/node_modules/re-emitter b/node_modules/re-emitter new file mode 160000 index 00000000..764fee50 --- /dev/null +++ b/node_modules/re-emitter @@ -0,0 +1 @@ +Subproject commit 764fee50e0d20b53ce7ed025516aead3de6d1630 diff --git a/node_modules/torrent-discovery b/node_modules/torrent-discovery new file mode 160000 index 00000000..8de962ba --- /dev/null +++ b/node_modules/torrent-discovery @@ -0,0 +1 @@ +Subproject commit 8de962bae131cde6df28e6301f2e06ef378949be diff --git a/package.json b/package.json index 3e8e4fd7..4167721d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,10 @@ "dependencies": { "addr-to-ip-port": "^1.0.1", "bitfield": "^1.0.2", + "//": { "bittorrent-dht": "^7.0.0", + "//": "nothing" + }, "bittorrent-protocol": "^2.0.0", "chunk-store-stream": "^2.0.0", "cpus": "^1.0.0", @@ -61,7 +64,10 @@ "speedometer": "^1.0.0", "stream-to-blob-url": "^2.0.0", "stream-with-known-length-to-buffer": "^1.0.0", + "//": { "torrent-discovery": "^7.0.0", + "//": "nothing" + }, "torrent-piece": "^1.0.0", "uniq": "^1.0.1", "unordered-array-remove": "^1.0.2",