From 8dfcea0e818dc072202ffef93731e74e16128c8b Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Fri, 29 May 2015 12:59:55 -0700 Subject: moved remote torrent handling into parse-torrent@5.1 --- index.js | 5 +- lib/torrent.js | 157 ++++++++++++++++++++++++------------------------------ package.json | 5 +- test/basic.js | 154 +++++++++++++++++++++++++++++----------------------- test/blocklist.js | 95 +++++++++++++++------------------ 5 files changed, 206 insertions(+), 210 deletions(-) diff --git a/index.js b/index.js index 62183af..f730bda 100644 --- a/index.js +++ b/index.js @@ -121,11 +121,12 @@ Object.defineProperty(WebTorrent.prototype, 'ratio', { * searching through the `client.torrents` array. Returns `null` if no matching torrent * found. * - * @param {string|Buffer|Object} torrentId + * @param {string|Buffer|Object|Torrent} torrentId * @return {Torrent|null} */ WebTorrent.prototype.get = function (torrentId) { var self = this + if (torrentId instanceof Torrent) return torrentId var parsed = parseTorrent(torrentId) if (!parsed.infoHash) throw new Error('Invalid torrent identifier') for (var i = 0, len = self.torrents.length; i < len; i++) { @@ -260,7 +261,7 @@ WebTorrent.prototype.destroy = function (cb) { var tasks = self.torrents.map(function (torrent) { return function (cb) { - self.remove(torrent.infoHash, cb) + self.remove(torrent, cb) } }) diff --git a/lib/torrent.js b/lib/torrent.js index acb4c3e..97ee244 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -5,8 +5,6 @@ var createTorrent = require('create-torrent') var debug = require('debug')('webtorrent:torrent') var Discovery = require('torrent-discovery') var EventEmitter = require('events').EventEmitter -var fs = require('fs') // browser exclude -var get = require('simple-get') // browser exclude var inherits = require('inherits') var parallel = require('run-parallel') var parseTorrent = require('parse-torrent') @@ -77,91 +75,7 @@ function Torrent (torrentId, opts) { self._storageImpl = opts.storage || Storage this._torrentFileURL = null - var parsedTorrent - try { - parsedTorrent = (torrentId && torrentId.parsedTorrent) || parseTorrent(torrentId) - } catch (err) { - // If torrent fails to parse, it could be an http/https URL or filesystem path, so - // don't consider it an error yet. - } - - if (parsedTorrent && parsedTorrent.infoHash) { - onTorrentId(parsedTorrent) - } else if (typeof get === 'function' && /^https?:/.test(torrentId)) { - // http or https url to torrent file - get.concat({ - url: torrentId, - headers: { 'user-agent': 'WebTorrent (http://webtorrent.io)' } - }, function (err, data) { - if (err) { - err = new Error('Error downloading torrent: ' + err.message) - return self._onError(err) - } - onTorrentId(data) - }) - } else if (typeof fs.readFile === 'function') { - // assume it's a filesystem path - fs.readFile(torrentId, function (err, torrent) { - if (err) return self._onError(new Error('Invalid torrent identifier')) - onTorrentId(torrent) - }) - } else throw new Error('Invalid torrent identifier') - - function onTorrentId (torrentId) { - try { - self.parsedTorrent = parseTorrent(torrentId) - } catch (err) { - return self._onError(new Error('Malformed torrent data: ' + err.message)) - } - - self.infoHash = self.parsedTorrent.infoHash - - if (!self.infoHash) { - return self._onError(new Error('Malformed torrent data: Missing info hash.')) - } - - if (self.parsedTorrent.name) self.name = self.parsedTorrent.name // preliminary name - - if (opts.announce) { - self.parsedTorrent.announce.push.apply(self.parsedTorrent.announce, opts.announce) - } - - // When no trackers specified, use some reasonable defaults - if (self.parsedTorrent.announce.length === 0) { - self.parsedTorrent.announce = createTorrent.announceList.map(function (list) { - return list[0] - }) - } - - // So `webtorrent-hybrid` can force specific trackers to be used - if (global.WEBTORRENT_ANNOUNCE) { - global.WEBTORRENT_ANNOUNCE.forEach(function (url) { - self.parsedTorrent.announce.push(url) - }) - } - - uniq(self.parsedTorrent.announce) - - // create swarm - self.swarm = new Swarm(self.infoHash, self.client.peerId, { - handshake: { dht: !!self.client.dht } - }) - self.swarm.on('error', self._onError.bind(self)) - reemit(self.swarm, self, ['warning']) - self.swarm.on('wire', self._onWire.bind(self)) - - // update overall client stats - self.swarm.on('download', self.client.downloadSpeed.bind(self.client)) - self.swarm.on('upload', self.client.uploadSpeed.bind(self.client)) - - // listen for peers (note: in the browser, this is a no-op and callback is called on - // next tick) - self.swarm.listen(self.client.torrentPort, self._onSwarmListening.bind(self)) - - process.nextTick(function () { - self.emit('infoHash') - }) - } + if (torrentId) self._onTorrentId(torrentId) } // torrent size (in bytes) @@ -230,6 +144,75 @@ Object.defineProperty(Torrent.prototype, 'torrentFileURL', { } }) +Torrent.prototype._onTorrentId = function (torrentId) { + var self = this + var parsedTorrent = torrentId && torrentId.parsedTorrent + if (parsedTorrent) { + self._onParsedTorrent(parsedTorrent) + } else { + parseTorrent.remote(torrentId, function (err, parsedTorrent) { + if (self.destroyed) return + if (err) return self._onError(err) + self._onParsedTorrent(parsedTorrent) + }) + } +} + +Torrent.prototype._onParsedTorrent = function (parsedTorrent) { + var self = this + self.parsedTorrent = parsedTorrent + self.infoHash = parsedTorrent.infoHash + + if (!self.infoHash) { + return self._onError(new Error('Malformed torrent data: Missing info hash.')) + } + + if (self.parsedTorrent.name) self.name = self.parsedTorrent.name // preliminary name + + if (self.opts.announce) { + self.parsedTorrent.announce.push.apply( + self.parsedTorrent.announce, self.opts.announce + ) + } + + // When no trackers specified, use some reasonable defaults + if (self.parsedTorrent.announce.length === 0) { + self.parsedTorrent.announce = createTorrent.announceList.map(function (list) { + return list[0] + }) + } + + // So `webtorrent-hybrid` can force specific trackers to be used + if (global.WEBTORRENT_ANNOUNCE) { + global.WEBTORRENT_ANNOUNCE.forEach(function (url) { + self.parsedTorrent.announce.push(url) + }) + } + + uniq(self.parsedTorrent.announce) + + // create swarm + self.swarm = new Swarm(self.infoHash, self.client.peerId, { + handshake: { dht: !!self.client.dht } + }) + self.swarm.on('error', self._onError.bind(self)) + reemit(self.swarm, self, ['warning']) + self.swarm.on('wire', self._onWire.bind(self)) + + // update overall client stats + self.swarm.on('download', self.client.downloadSpeed.bind(self.client)) + self.swarm.on('upload', self.client.uploadSpeed.bind(self.client)) + + // listen for peers (note: in the browser, this is a no-op and callback is called on + // next tick) + self.swarm.listen(self.client.torrentPort, self._onSwarmListening.bind(self)) + + process.nextTick(function () { + if (self.destroyed) return + self.emit('infoHash', self.infoHash) + }) +} + Torrent.prototype._onSwarmListening = function () { var self = this if (self.destroyed) return diff --git a/package.json b/package.json index 83cca71..82d7018 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "./server": false, "bittorrent-dht/client": false, "load-ip-set": false, - "simple-get": false, "ut_pex": false }, "bugs": { @@ -43,7 +42,7 @@ "multistream": "^1.4.2", "network-address": "^1.0.0", "once": "^1.3.1", - "parse-torrent": "^5.0.0", + "parse-torrent": "^5.1.0", "pretty-bytes": "^2.0.1", "pump": "^1.0.0", "random-access-file": "^0.3.1", @@ -51,7 +50,6 @@ "re-emitter": "^1.0.0", "rimraf": "^2.2.5", "run-parallel": "^1.0.0", - "simple-get": "^1.0.0", "simple-sha1": "^2.0.0", "speedometer": "^0.1.2", "thunky": "^0.1.0", @@ -68,6 +66,7 @@ "brfs": "^1.2.0", "browserify": "^10.0.0", "run-auto": "^1.0.0", + "simple-get": "^1.0.0", "standard": "^3.1.1", "tape": "^4.0.0", "uglify-js": "^2.4.15", diff --git a/test/basic.js b/test/basic.js index 9e2b9a6..4b44c46 100644 --- a/test/basic.js +++ b/test/basic.js @@ -14,65 +14,70 @@ test('client.add/remove: magnet uri, utf-8 string', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) - client.remove('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) + client.remove('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.add/remove: torrent file, buffer', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add(leaves) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - t.equal(torrent.magnetURI, leavesMagnetURI) - client.remove(leaves) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + t.equal(torrent.magnetURI, leavesMagnetURI) + client.remove(leaves) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.add/remove: info hash, hex string', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add(leavesTorrent.infoHash) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) - client.remove(leavesTorrent.infoHash) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) + client.remove(leavesTorrent.infoHash) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.add/remove: info hash, buffer', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add(new Buffer(leavesTorrent.infoHash, 'hex')) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) - client.remove(new Buffer(leavesTorrent.infoHash, 'hex')) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + t.ok(torrent.magnetURI.indexOf('magnet:?xt=urn:btih:' + leavesTorrent.infoHash) === 0) + client.remove(new Buffer(leavesTorrent.infoHash, 'hex')) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.add/remove: parsed torrent, from `parse-torrent`', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add(leavesTorrent) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - t.equal(torrent.magnetURI, leavesMagnetURI) - client.remove(leavesTorrent) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + t.equal(torrent.magnetURI, leavesMagnetURI) + client.remove(leavesTorrent) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.add/remove: parsed torrent, with string type announce property', function (t) { @@ -82,29 +87,30 @@ test('client.add/remove: parsed torrent, with string type announce property', fu }) var torrent = client.add(modifiedParsedTorrent) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - client.remove(leavesTorrent) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + client.remove(leavesTorrent) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) test('client.remove: remove by Torrent object', function (t) { var client = new WebTorrent({ dht: false, tracker: false }) var torrent = client.add(leavesTorrent.infoHash) t.equal(client.torrents.length, 1) - t.equal(torrent.infoHash, leavesTorrent.infoHash) - - client.remove(torrent) - t.equal(client.torrents.length, 0) - client.destroy() - - t.end() + torrent.on('infoHash', function () { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + client.remove(torrent) + t.equal(client.torrents.length, 0) + client.destroy() + t.end() + }) }) -test('client.seed (Buffer, Blob)', function (t) { - t.plan(global.Blob !== undefined ? 8 : 4) +test('client.seed: torrent file (Buffer)', function (t) { + t.plan(4) var opts = { name: 'Leaves of Grass by Walt Whitman.epub', @@ -118,30 +124,44 @@ test('client.seed (Buffer, Blob)', function (t) { ] } - // torrent file (Buffer) - var client1 = new WebTorrent({ dht: false, tracker: false }) - client1.seed(leavesBook, opts, function (torrent1) { - t.equal(client1.torrents.length, 1) + var client = new WebTorrent({ dht: false, tracker: false }) + client.seed(leavesBook, opts, function (torrent1) { + t.equal(client.torrents.length, 1) t.equal(torrent1.infoHash, leavesTorrent.infoHash) t.equal(torrent1.magnetURI, leavesMagnetURI) - client1.remove(torrent1) - t.equal(client1.torrents.length, 0) - client1.destroy() + client.remove(torrent1) + t.equal(client.torrents.length, 0) + client.destroy() }) +}) + +test('client.seed: torrent file (Blob)', function (t) { + var opts = { + name: 'Leaves of Grass by Walt Whitman.epub', + announce: [ + 'http://tracker.thepiratebay.org/announce', + 'udp://tracker.openbittorrent.com:80', + 'udp://tracker.ccc.de:80', + 'udp://tracker.publicbt.com:80', + 'udp://fr33domtracker.h33t.com:3310/announce', + 'http://tracker.bittorrent.am/announce' + ] + } - // Blob if (global.Blob !== undefined) { - var client2 = new WebTorrent({ dht: false, tracker: false }) - client2.seed(new global.Blob([ leavesBook ]), opts, function (torrent2) { - t.equal(client2.torrents.length, 1) + t.plan(4) + var client = new WebTorrent({ dht: false, tracker: false }) + client.seed(new global.Blob([ leavesBook ]), opts, function (torrent2) { + t.equal(client.torrents.length, 1) t.equal(torrent2.infoHash, leavesTorrent.infoHash) t.equal(torrent2.magnetURI, leavesMagnetURI) - client2.remove(torrent2) - t.equal(client2.torrents.length, 0) - client2.destroy() + client.remove(torrent2) + t.equal(client.torrents.length, 0) + client.destroy() }) } else { - console.log('Skipping Blob test because missing `Blob` constructor') + t.pass('Skipping Blob test because missing `Blob` constructor') + t.end() } }) @@ -164,10 +184,10 @@ test('after client.destroy(), no "torrent" or "ready" events emitted', function t.plan(1) var client = new WebTorrent({ dht: false, tracker: false }) - client.add(leaves, function () { + client.add(leaves, { name: 'leaves' }, function () { t.fail('unexpected "torrent" event (from add)') }) - client.seed(leavesBook, function () { + client.seed(leavesBook, { name: 'leavesBook' }, function () { t.fail('unexpected "torrent" event (from seed)') }) client.on('ready', function () { diff --git a/test/blocklist.js b/test/blocklist.js index ab36bc3..bc03432 100644 --- a/test/blocklist.js +++ b/test/blocklist.js @@ -38,14 +38,14 @@ test('blocklist (single IP)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) + client.add(leavesParsed, function (torrent) { + assertBlocked(t, torrent, '1.2.3.4:1234') + assertBlocked(t, torrent, '1.2.3.4:6969') + assertReachable(t, torrent, '1.1.1.1:1234') + assertReachable(t, torrent, '1.1.1.1:6969') - assertBlocked(t, torrent, '1.2.3.4:1234') - assertBlocked(t, torrent, '1.2.3.4:6969') - assertReachable(t, torrent, '1.1.1.1:1234') - assertReachable(t, torrent, '1.1.1.1:6969') - - client.destroy() + client.destroy() + }) }) }) @@ -59,16 +59,16 @@ test('blocklist (array of IPs)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) + client.add(leavesParsed, function (torrent) { + assertBlocked(t, torrent, '1.2.3.4:1234') + assertBlocked(t, torrent, '1.2.3.4:6969') + assertBlocked(t, torrent, '5.6.7.8:1234') + assertBlocked(t, torrent, '5.6.7.8:6969') + assertReachable(t, torrent, '1.1.1.1:1234') + assertReachable(t, torrent, '1.1.1.1:6969') - assertBlocked(t, torrent, '1.2.3.4:1234') - assertBlocked(t, torrent, '1.2.3.4:6969') - assertBlocked(t, torrent, '5.6.7.8:1234') - assertBlocked(t, torrent, '5.6.7.8:6969') - assertReachable(t, torrent, '1.1.1.1:1234') - assertReachable(t, torrent, '1.1.1.1:6969') - - client.destroy() + client.destroy() + }) }) }) @@ -123,11 +123,10 @@ test('blocklist (array of IP ranges)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + }) }) }) @@ -137,8 +136,7 @@ test('blocklist (http url)', function (t) { // Check that WebTorrent declares a user agent t.equal(req.headers['user-agent'], 'WebTorrent (http://webtorrent.io)') - fs.createReadStream(blocklistPath) - .pipe(res) + fs.createReadStream(blocklistPath).pipe(res) }) server.listen(0, function () { @@ -151,12 +149,11 @@ test('blocklist (http url)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() - server.close() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + server.close() + }) }) }) }) @@ -183,12 +180,11 @@ test('blocklist (http url with gzip encoding)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() - server.close() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + server.close() + }) }) }) }) @@ -215,12 +211,11 @@ test('blocklist (http url with deflate encoding)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() - server.close() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + server.close() + }) }) }) }) @@ -234,11 +229,10 @@ test('blocklist (fs path)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + }) }) }) @@ -251,10 +245,9 @@ test('blocklist (fs path with gzip)', function (t) { }) .on('error', function (err) { t.fail(err) }) .on('ready', function () { - var torrent = client.add(leavesParsed) - - assertList(t, torrent) - - client.destroy() + client.add(leavesParsed, function (torrent) { + assertList(t, torrent) + client.destroy() + }) }) }) -- cgit v1.2.3