diff options
author | Diego RodrÃguez Baquero <diegorbaquero@gmail.com> | 2016-04-03 02:02:00 +0300 |
---|---|---|
committer | Diego RodrÃguez Baquero <diegorbaquero@gmail.com> | 2016-04-03 02:02:00 +0300 |
commit | 7205c151a044d121f529cac653bcf52a0a222a7a (patch) | |
tree | 3ef0d3675003ca6deb3dbae1311ceb0f34b2be39 /lib | |
parent | b1fec4de2da98e418efa9cac32f65e141c5decd6 (diff) | |
parent | 00da34d0b80fd0a2b5ad9c07e334fb52de6a8e7b (diff) |
Merge branch 'master' into max-web-conns-default
Diffstat (limited to 'lib')
-rw-r--r-- | lib/peer.js | 4 | ||||
-rw-r--r-- | lib/torrent.js | 94 |
2 files changed, 79 insertions, 19 deletions
diff --git a/lib/peer.js b/lib/peer.js index aafbabe..06786c5 100644 --- a/lib/peer.js +++ b/lib/peer.js @@ -4,8 +4,8 @@ var Wire = require('bittorrent-protocol') var WebConn = require('./webconn') -var CONNECT_TIMEOUT_TCP = 25000 -var CONNECT_TIMEOUT_WEBRTC = 5000 +var CONNECT_TIMEOUT_TCP = 5000 +var CONNECT_TIMEOUT_WEBRTC = 25000 var HANDSHAKE_TIMEOUT = 25000 /** diff --git a/lib/torrent.js b/lib/torrent.js index 2bff2e1..622b58f 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -5,12 +5,12 @@ module.exports = Torrent var addrToIPPort = require('addr-to-ip-port') var BitField = require('bitfield') var ChunkStoreWriteStream = require('chunk-store-stream/write') -var cpus = require('cpus') var debug = require('debug')('webtorrent:torrent') var Discovery = require('torrent-discovery') var EventEmitter = require('events').EventEmitter var extend = require('xtend') var extendMutable = require('xtend/mutable') +var fs = require('fs') var FSChunkStore = require('fs-chunk-store') // browser: `memory-chunk-store` var ImmediateChunkStore = require('immediate-chunk-store') var inherits = require('inherits') @@ -24,7 +24,6 @@ var pathExists = require('path-exists') // browser exclude var Piece = require('torrent-piece') var pump = require('pump') var randomIterate = require('random-iterate') -var reemit = require('re-emitter') var sha1 = require('simple-sha1') var uniq = require('uniq') var ut_metadata = require('ut_metadata') @@ -46,6 +45,8 @@ var PIPELINE_MAX_DURATION = 1 var RECHOKE_INTERVAL = 10000 // 10 seconds var RECHOKE_OPTIMISTIC_DURATION = 2 // 30 seconds +var FILESYSTEM_CONCURRENCY = 2 + var TMP = typeof pathExists.sync === 'function' ? path.join(pathExists.sync('/tmp') ? '/tmp' : os.tmpDir(), 'webtorrent') : '/tmp/webtorrent' @@ -59,7 +60,6 @@ inherits(Torrent, EventEmitter) */ function Torrent (torrentId, client, opts) { EventEmitter.call(this) - if (!debug.enabled) this.setMaxListeners(0) this.client = client this._debugId = this.client.peerId.slice(32) @@ -100,6 +100,9 @@ function Torrent (torrentId, client, opts) { // for cleanup this._servers = [] + // optimization: don't recheck every file if it hasn't changed + this._fileModtimes = opts.fileModtimes + if (torrentId !== null) this._onTorrentId(torrentId) } @@ -298,10 +301,11 @@ Torrent.prototype._onSwarmListening = function () { // 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, tracker: self.client.tracker && trackerOpts, - peerId: self.client.peerId, port: self.client.torrentPort }) self.discovery.on('error', function (err) { @@ -314,11 +318,19 @@ Torrent.prototype._onSwarmListening = function () { }) // expose discovery events - reemit(self.discovery, self, ['trackerAnnounce', 'dhtAnnounce', 'warning']) + self.discovery.on('trackerAnnounce', function () { + self.emit('trackerAnnounce') + }) + self.discovery.on('dhtAnnounce', function () { + self.emit('dhtAnnounce') + }) + self.discovery.on('warning', function (err) { + self.emit('warning', err) + }) - // if full metadata was included in initial torrent id, use it + // 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. if (self.info) self._onMetadata(self) - else self.discovery.setTorrent(self.infoHash) self.emit('listening', self.client.torrentPort) } @@ -346,9 +358,6 @@ Torrent.prototype._onMetadata = function (metadata) { self._processParsedTorrent(parsedTorrent) self.metadata = self.torrentFile - // pass full torrent metadata to discovery module - self.discovery.setTorrent(self) - // add web seed urls (BEP19) self.urlList.forEach(function (url) { self.addWebSeed(url) @@ -398,7 +407,56 @@ Torrent.prototype._onMetadata = function (metadata) { }) self._debug('verifying existing torrent data') - parallelLimit(self.pieces.map(function (piece, index) { + if (self._fileModtimes && self._store === FSChunkStore) { + // don't verify if the files haven't been modified since we last checked + self.getFileModtimes(function (err, fileModtimes) { + if (err) return self._onError(err) + + var unchanged = self.files.map(function (_, index) { + return fileModtimes[index] === self._fileModtimes[index] + }).every(function (x) { + return x + }) + + if (unchanged) { + for (var index = 0; index < self.pieces.length; index++) { + self._markVerified(index) + } + self._onStore() + } else { + self._verifyPieces() + } + }) + } else { + self._verifyPieces() + } + + self.emit('metadata') +} + +/* + * Gets the last modified time of every file on disk for this torrent. + * Only valid in Node, not in the browser. + */ +Torrent.prototype.getFileModtimes = function (cb) { + var self = this + var ret = [] + parallelLimit(self.files.map(function (file, index) { + return function (cb) { + fs.stat(path.join(self.path, file.path), function (err, stat) { + ret[index] = stat && stat.mtime.getTime() + cb(err) + }) + } + }), FILESYSTEM_CONCURRENCY, function (err) { + self._debug('done getting file modtimes') + cb(err, ret) + }) +} + +Torrent.prototype._verifyPieces = function () { + var self = this + parallelLimit(self.pieces.map(function (_, index) { return function (cb) { self.store.get(index, function (err, buf) { if (err) return cb(null) // ignore error @@ -406,9 +464,7 @@ Torrent.prototype._onMetadata = function (metadata) { if (hash === self._hashes[index]) { if (!self.pieces[index]) return self._debug('piece verified %s', index) - self.pieces[index] = null - self._reservations[index] = null - self.bitfield.set(index, true) + self._markVerified(index) } else { self._debug('piece invalid %s', index) } @@ -416,13 +472,17 @@ Torrent.prototype._onMetadata = function (metadata) { }) }) } - }), cpus().length, function (err) { + }), FILESYSTEM_CONCURRENCY, function (err) { if (err) return self._onError(err) self._debug('done verifying') self._onStore() }) +} - self.emit('metadata') +Torrent.prototype._markVerified = function (index) { + this.pieces[index] = null + this._reservations[index] = null + this.bitfield.set(index, true) } /** @@ -470,7 +530,7 @@ Torrent.prototype.destroy = function (cb) { }) if (self.swarm) tasks.push(function (cb) { self.swarm.destroy(cb) }) - if (self.discovery) tasks.push(function (cb) { self.discovery.stop(cb) }) + if (self.discovery) tasks.push(function (cb) { self.discovery.destroy(cb) }) if (self.store) tasks.push(function (cb) { self.store.close(cb) }) parallel(tasks, cb) |