From c430d6a98c2ffb0914d0152c662b7cb843fe2d8f Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:20:35 -0800 Subject: [PATCH 1/6] only support latest version of chrome/firefox --- .zuul.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.zuul.yml b/.zuul.yml index 6f21af41..2972d391 100644 --- a/.zuul.yml +++ b/.zuul.yml @@ -1,6 +1,6 @@ ui: tape browsers: - name: chrome - version: 35..latest + version: 39..latest - name: firefox - version: 30..latest + version: 34..latest From 8e6503ab5dcbc698c02de88b5e0f65e015269591 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:24:48 -0800 Subject: [PATCH 2/6] readme --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1a585b8a..cb4c136d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ # ![WebTorrent](img/wordmark.png) + +### Streaming torrent client for node & the browser + [![Build Status][webtorrent-ti]][webtorrent-tu] [![NPM Version][webtorrent-ni]][webtorrent-nu] [![NPM Downloads][webtorrent-downloads-image]][webtorrent-downloads-url] [![Gratipay][webtorrent-gratipay-image]][webtorrent-gratipay-url] -### WebTorrent – Streaming torrent client for node & the browser +[![Sauce Test Status][webtorrent-sauce-image]][webtorrent-sauce-url] -WebTorrent is a streaming torrent client that works in node.js and the browser. **YEP, -THAT'S RIGHT. The browser.** It's written completely in JavaScript – the language of the -web – so the same code works in both runtimes. +**WebTorrent** is a streaming torrent client for **node.js** and the **browser**. YEP, +THAT'S RIGHT. THE BROWSER. It's written completely in JavaScript – the language of the web +– so the same code works in both runtimes. In the browser, WebTorrent uses **WebRTC** (data channels) for peer-to-peer transport. It can be used **without** browser plugins, extensions, or installations. It's Just @@ -33,8 +36,6 @@ it the first "hybrid" client. > Warning: This is pre-alpha software. **Watch/star to follow along with progress.** -[![Sauce Test Status][webtorrent-sauce-image]][webtorrent-sauce-url] - ### Features - **Torrent client for node.js & the browser** (same npm module!) From 9e55cc7eec04e07060f32d1695b44f30a7c25187 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:27:00 -0800 Subject: [PATCH 3/6] add client.seed tests (buffer, blob, path to file) --- test/basic-node.js | 30 +++++++++++------- test/basic.js | 24 ++++++++++++++ .../Leaves of Grass by Walt Whitman.epub | Bin test/download.js | 2 +- test/server.js | 2 +- 5 files changed, 45 insertions(+), 13 deletions(-) rename test/{torrents => content}/Leaves of Grass by Walt Whitman.epub (100%) diff --git a/test/basic-node.js b/test/basic-node.js index 9d18928f..950ba843 100644 --- a/test/basic-node.js +++ b/test/basic-node.js @@ -8,11 +8,7 @@ var test = require('tape') var leavesPath = __dirname + '/torrents/leaves.torrent' var leaves = fs.readFileSync(leavesPath) var leavesTorrent = parseTorrent(leaves) - -function verify (t, client, torrent) { - t.equal(torrent.infoHash, leavesTorrent.infoHash) - client.destroy() -} +var leavesBookPath = __dirname + '/content/Leaves of Grass by Walt Whitman.epub' test('client.add (http url to a torrent file (string))', function (t) { t.plan(1) @@ -25,9 +21,10 @@ test('client.add (http url to a torrent file (string))', function (t) { if (err) throw err server.listen(port, function () { var url = 'http://127.0.0.1:' + port - var client1 = new WebTorrent({ dht: false, trackers: false }) - client1.add(url, function (torrent) { - verify(t, client1, torrent) + var client = new WebTorrent({ dht: false, trackers: false }) + client.add(url, function (torrent) { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + client.destroy() server.close() }) }) @@ -37,8 +34,19 @@ test('client.add (http url to a torrent file (string))', function (t) { test('client.add (filesystem path to a torrent file (string))', function (t) { t.plan(1) - var client1 = new WebTorrent({ dht: false, trackers: false }) - client1.add(leavesPath, function (torrent) { - verify(t, client1, torrent) + var client = new WebTorrent({ dht: false, trackers: false }) + client.add(leavesPath, function (torrent) { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + client.destroy() + }) +}) + +test('client.seed (filesystem path to file (string))', function (t) { + t.plan(1) + + var client = new WebTorrent({ dht: false, trackers: false }) + client.seed(leavesBookPath, function (torrent) { + t.equal(torrent.infoHash, leavesTorrent.infoHash) + client.destroy() }) }) diff --git a/test/basic.js b/test/basic.js index a413e94d..2211593c 100644 --- a/test/basic.js +++ b/test/basic.js @@ -5,6 +5,7 @@ var test = require('tape') var leaves = fs.readFileSync(__dirname + '/torrents/leaves.torrent') var leavesTorrent = parseTorrent(leaves) +var leavesBook = fs.readFileSync(__dirname + '/content/Leaves of Grass by Walt Whitman.epub') function verify (t, client, torrent) { t.equal(torrent.infoHash, leavesTorrent.infoHash) @@ -33,5 +34,28 @@ test('client.add (magnet uri, torrent file, info hash, and parsed torrent)', fun // parsed torrent (from parse-torrent) var client5 = new WebTorrent({ dht: false, trackers: false }) verify(t, client5, client5.add(leavesTorrent)) +}) + +test('client.seed (Buffer, Blob)', function (t) { + t.plan(2) + var opts = { + name: 'Leaves of Grass by Walt Whitman.epub' + } + + // torrent file (Buffer) + var client1 = new WebTorrent({ dht: false, trackers: false }) + client1.seed(leavesBook, opts, function (torrent) { + verify(t, client1, torrent) + }) + + // Blob + if (typeof Blob !== 'undefined') { + var client2 = new WebTorrent({ dht: false, trackers: false }) + client2.seed(new Blob([ leavesBook ]), opts, function (torrent) { + verify(t, client2, torrent) + }) + } else { + t.pass('Skipping Blob test because missing `Blob` constructor') + } }) diff --git a/test/torrents/Leaves of Grass by Walt Whitman.epub b/test/content/Leaves of Grass by Walt Whitman.epub similarity index 100% rename from test/torrents/Leaves of Grass by Walt Whitman.epub rename to test/content/Leaves of Grass by Walt Whitman.epub diff --git a/test/download.js b/test/download.js index 9ec7e03f..e5dfe4bb 100644 --- a/test/download.js +++ b/test/download.js @@ -7,7 +7,7 @@ var parseTorrent = require('parse-torrent') var test = require('tape') var TrackerServer = require('bittorrent-tracker/server') -var leavesFile = __dirname + '/torrents/Leaves of Grass by Walt Whitman.epub' +var leavesFile = __dirname + '/content/Leaves of Grass by Walt Whitman.epub' var leavesTorrent = fs.readFileSync(__dirname + '/torrents/leaves.torrent') var leavesParsed = parseTorrent(leavesTorrent) diff --git a/test/server.js b/test/server.js index 27239d56..f00c22bd 100644 --- a/test/server.js +++ b/test/server.js @@ -5,7 +5,7 @@ var portfinder = require('portfinder') var test = require('tape') var WebTorrent = require('../') -var leavesFile = __dirname + '/torrents/Leaves of Grass by Walt Whitman.epub' +var leavesFile = __dirname + '/content/Leaves of Grass by Walt Whitman.epub' var leavesTorrent = fs.readFileSync(__dirname + '/torrents/leaves.torrent') test('start http server programmatically', function (t) { From 58c1f4cb260c6d163e368a157e1a675a43cd38d4 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:30:39 -0800 Subject: [PATCH 4/6] support seeding by string path to file For #197 --- index.js | 66 ++++++++++++++++++++++++++--------------------- lib/fs-storage.js | 1 + 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index 406d65ab..a76ab976 100644 --- a/index.js +++ b/index.js @@ -9,15 +9,17 @@ var DHT = require('bittorrent-dht/client') // browser exclude var EventEmitter = require('events').EventEmitter var extend = require('extend.js') var FileReadStream = require('filestream/read') -var FSStorage = require('./lib/fs-storage') // browser exclude +var fs = require('fs') var hat = require('hat') var inherits = require('inherits') var loadIPSet = require('load-ip-set') // browser exclude var parallel = require('run-parallel') var parseTorrent = require('parse-torrent') var speedometer = require('speedometer') -var Storage = require('./lib/storage') var stream = require('stream') + +var FSStorage = require('./lib/fs-storage') // browser exclude +var Storage = require('./lib/storage') var Torrent = require('./lib/torrent') inherits(WebTorrent, EventEmitter) @@ -196,45 +198,49 @@ WebTorrent.prototype.seed = function (input, opts, onseed) { } if (!opts) opts = {} - // TODO: support `input` as string, or array of strings + // TODO: support an array of paths + // TODO: support path to folder (currently, only path to file supported) if (typeof FileList !== 'undefined' && input instanceof FileList) input = Array.prototype.slice.call(input) - if (isBlob(input) || Buffer.isBuffer(input)) { + if (isBlob(input) || Buffer.isBuffer(input)) input = [ input ] - } - var streams = input.map(function (item) { - if (isBlob(item)) return new FileReadStream(item) - else if (Buffer.isBuffer(item)) { - var s = new stream.PassThrough() - s.end(item) - return s - } else throw new Error('unsupported input type to `seed`') - }) + var streams + if (Array.isArray(input) && input.length > 0) { + streams = input.map(function (item) { + if (isBlob(item)) return new FileReadStream(item) + else if (Buffer.isBuffer(item)) { + var s = new stream.PassThrough() + s.end(item) + return s + } else { + throw new Error('Array must contain only File|Blob|Buffer objects') + } + }) + } else if (typeof input === 'string') { + streams = [ fs.createReadStream(input) ] + } else { + throw new Error('invalid input type') + } - var torrent createTorrent(input, opts, function (err, torrentBuf) { if (err) return self.emit('error', err) - self.add(torrentBuf, opts, function (_torrent) { - torrent = _torrent - torrent.storage.load( - streams, - function (err) { - if (err) return self.emit('error', err) - self.emit('seed', torrent) - }) + self.add(torrentBuf, opts, function (torrent) { + var tasks = [function (cb) { + torrent.storage.load(streams, cb) + }] + if (self.dht) tasks.push(function (cb) { + torrent.on('dhtAnnounce', cb) + }) + parallel(tasks, function (err) { + if (err) return self.emit('error', err) + if (onseed) onseed(torrent) + self.emit('seed', torrent) + }) }) }) - - function clientOnSeed (_torrent) { - if (torrent.infoHash === _torrent.infoHash) { - onseed(torrent) - self.removeListener('seed', clientOnSeed) - } - } - if (onseed) self.on('seed', clientOnSeed) } /** diff --git a/lib/fs-storage.js b/lib/fs-storage.js index 7afe92e8..cd32d4e5 100644 --- a/lib/fs-storage.js +++ b/lib/fs-storage.js @@ -165,6 +165,7 @@ FSStorage.prototype._onPieceDone = function (piece) { var target = targets[i++] target.openWrite(function (err, file) { + if (self.closed) return if (err) return self.emit('error', err) file.write(target.offset, piece.buffer.slice(target.from, target.to), writeToNextFile) }) From 455e2bdffb40331c4b12cd0a872b4e88b03bc1b8 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:41:06 -0800 Subject: [PATCH 5/6] use correct tracker option `tracker`; not `trackers` --- index.js | 2 +- test/basic-node.js | 6 +++--- test/basic.js | 14 +++++++------- test/download.js | 5 ++--- test/metadata.js | 4 ++-- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index a76ab976..d3424559 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,7 @@ function WebTorrent (opts) { if (!debug.enabled) self.setMaxListeners(0) self.torrentPort = opts.torrentPort || 0 - self.tracker = (opts.tracker !== undefined) ? opts.tracker : true + self.tracker = opts.tracker !== undefined ? opts.tracker : true self.torrents = [] self.downloadSpeed = speedometer() diff --git a/test/basic-node.js b/test/basic-node.js index 950ba843..caf69b6c 100644 --- a/test/basic-node.js +++ b/test/basic-node.js @@ -21,7 +21,7 @@ test('client.add (http url to a torrent file (string))', function (t) { if (err) throw err server.listen(port, function () { var url = 'http://127.0.0.1:' + port - var client = new WebTorrent({ dht: false, trackers: false }) + var client = new WebTorrent({ dht: false, tracker: false }) client.add(url, function (torrent) { t.equal(torrent.infoHash, leavesTorrent.infoHash) client.destroy() @@ -34,7 +34,7 @@ test('client.add (http url to a torrent file (string))', function (t) { test('client.add (filesystem path to a torrent file (string))', function (t) { t.plan(1) - var client = new WebTorrent({ dht: false, trackers: false }) + var client = new WebTorrent({ dht: false, tracker: false }) client.add(leavesPath, function (torrent) { t.equal(torrent.infoHash, leavesTorrent.infoHash) client.destroy() @@ -44,7 +44,7 @@ test('client.add (filesystem path to a torrent file (string))', function (t) { test('client.seed (filesystem path to file (string))', function (t) { t.plan(1) - var client = new WebTorrent({ dht: false, trackers: false }) + var client = new WebTorrent({ dht: false, tracker: false }) client.seed(leavesBookPath, function (torrent) { t.equal(torrent.infoHash, leavesTorrent.infoHash) client.destroy() diff --git a/test/basic.js b/test/basic.js index 2211593c..6928f221 100644 --- a/test/basic.js +++ b/test/basic.js @@ -16,23 +16,23 @@ test('client.add (magnet uri, torrent file, info hash, and parsed torrent)', fun t.plan(5) // magnet uri (utf8 string) - var client1 = new WebTorrent({ dht: false, trackers: false }) + var client1 = new WebTorrent({ dht: false, tracker: false }) verify(t, client1, client1.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)) // torrent file (buffer) - var client2 = new WebTorrent({ dht: false, trackers: false }) + var client2 = new WebTorrent({ dht: false, tracker: false }) verify(t, client2, client2.add(leaves)) // info hash (hex string) - var client3 = new WebTorrent({ dht: false, trackers: false }) + var client3 = new WebTorrent({ dht: false, tracker: false }) verify(t, client3, client3.add(leavesTorrent.infoHash)) // info hash (buffer) - var client4 = new WebTorrent({ dht: false, trackers: false }) + var client4 = new WebTorrent({ dht: false, tracker: false }) verify(t, client4, client4.add(new Buffer(leavesTorrent.infoHash, 'hex'))) // parsed torrent (from parse-torrent) - var client5 = new WebTorrent({ dht: false, trackers: false }) + var client5 = new WebTorrent({ dht: false, tracker: false }) verify(t, client5, client5.add(leavesTorrent)) }) @@ -44,15 +44,15 @@ test('client.seed (Buffer, Blob)', function (t) { } // torrent file (Buffer) - var client1 = new WebTorrent({ dht: false, trackers: false }) + var client1 = new WebTorrent({ dht: false, tracker: false }) client1.seed(leavesBook, opts, function (torrent) { verify(t, client1, torrent) }) // Blob if (typeof Blob !== 'undefined') { - var client2 = new WebTorrent({ dht: false, trackers: false }) client2.seed(new Blob([ leavesBook ]), opts, function (torrent) { + var client2 = new WebTorrent({ dht: false, tracker: false }) verify(t, client2, torrent) }) } else { diff --git a/test/download.js b/test/download.js index e5dfe4bb..3e895e44 100644 --- a/test/download.js +++ b/test/download.js @@ -1,6 +1,5 @@ var auto = require('run-auto') var WebTorrent = require('../') -var BlockStream = require('block-stream') var DHT = require('bittorrent-dht/client') var fs = require('fs') var parseTorrent = require('parse-torrent') @@ -212,7 +211,7 @@ test('Simple download using DHT', function (t) { }, client1: ['dhtPort', function (cb, r) { var client1 = new WebTorrent({ - trackers: false, + tracker: false, dht: { bootstrap: '127.0.0.1:' + r.dhtPort } }) client1.on('error', function (err) { t.fail(err) }) @@ -245,7 +244,7 @@ test('Simple download using DHT', function (t) { client2: ['client1', function (cb, r) { var client2 = new WebTorrent({ - trackers: false, + tracker: false, dht: { bootstrap: '127.0.0.1:' + r.dhtPort } }) client2.on('error', function (err) { t.fail(err) }) diff --git a/test/metadata.js b/test/metadata.js index 27ab496d..c01182ae 100644 --- a/test/metadata.js +++ b/test/metadata.js @@ -9,8 +9,8 @@ var leavesTorrent = parseTorrent(leaves) test('ut_metadata transfer', function (t) { t.plan(5) - var client1 = new WebTorrent({ dht: false, trackers: false }) - var client2 = new WebTorrent({ dht: false, trackers: false }) + var client1 = new WebTorrent({ dht: false, tracker: false }) + var client2 = new WebTorrent({ dht: false, tracker: false }) client1.on('torrent', function (torrent) { t.pass('client1 emits torrent event') // even though it started with metadata From b8cfe8ea3cde0f0e18d9facc1c3924e783d7f2d0 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Tue, 16 Dec 2014 15:42:53 -0800 Subject: [PATCH 6/6] hack: set name on blob to fix test exception --- test/basic.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/basic.js b/test/basic.js index 6928f221..912c4b03 100644 --- a/test/basic.js +++ b/test/basic.js @@ -51,8 +51,14 @@ test('client.seed (Buffer, Blob)', function (t) { // Blob if (typeof Blob !== 'undefined') { - client2.seed(new Blob([ leavesBook ]), opts, function (torrent) { var client2 = new WebTorrent({ dht: false, tracker: false }) + var blob = new Blob([ leavesBook ]) + + // TODO: just pass name in the opts object – this should work + // Doing it this way until we use the create-torrent code to process inputs + // in client.seed + blob.name = opts.name + client2.seed(blob, function (torrent) { verify(t, client2, torrent) }) } else {