From 9d072d494d1de71a877dcac3ba3ad5e110f63b7d Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 16:47:31 -0600 Subject: [PATCH 1/7] Make cmd.js pass lint. --- bin/cmd.js | 121 ++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/bin/cmd.js b/bin/cmd.js index bb381fe0..d637fcb6 100755 --- a/bin/cmd.js +++ b/bin/cmd.js @@ -2,93 +2,90 @@ // TODO: add terminal UI -var chalk = require('chalk') -var clivas = require('clivas') -var concat = require('concat-stream') -var cp = require('child_process') -var fs = require('fs') -var http = require('http') -var minimist = require('minimist') -var os = require('os') -var path = require('path') -var WebTorrent = require('../') - -var TMP = os.tmp +var chalk = require('chalk'), + clivas = require('clivas'), + concat = require('concat-stream'), + cp = require('child_process'), + fs = require('fs'), + http = require('http'), + minimist = require('minimist'), + os = require('os'), + path = require('path'), + WebTorrent = require('../'), + TMP = os.tmp; function usage () { - var logo = fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8') - logo.split('\n').forEach(function (line) { - console.log(chalk.bold(line.substring(0, 20) + chalk.red(line.substring(20)))) - }) - console.log('Usage: webtorrent [torrentId] {OPTIONS}') - console.log('') - console.log(chalk.bold('torrentId') + ' can be any of the following:') - console.log(' * magnet uri') - console.log(' * path to .torrent file (filesystem path or http url)') - console.log(' * info hash (as hex string)') - console.log('') - console.log(chalk.bold('OPTIONS:')) - console.log(' --vlc autoplay in vlc') - console.log(' --mplayer autoplay in mplayer') - console.log(' --omx [jack] autoplay in omx (jack=local|hdmi)') - console.log('') - console.log(' -p, --port change the http port [default: 9000]') - console.log(' -l, --list list available files in torrent') - console.log(' -t, --subtitles load subtitles file') - console.log(' -h, --help display this help message') - console.log(' -v, --version print the current version') - console.log('') + var logo = fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8'); + logo.split('\n').forEach(function (line){ + console.log(chalk.bold(line.substring(0, 20) + chalk.red(line.substring(20)))); + }); + console.log('Usage: webtorrent [torrentId] {OPTIONS}'); + console.log(''); + console.log(chalk.bold('torrentId') + ' can be any of the following:'); + console.log(' * magnet uri'); + console.log(' * path to .torrent file (filesystem path or http url)'); + console.log(' * info hash (as hex string)'); + console.log(''); + console.log(chalk.bold('OPTIONS:')); + console.log(' --vlc autoplay in vlc'); + console.log(' --mplayer autoplay in mplayer'); + console.log(' --omx [jack] autoplay in omx (jack=local|hdmi)'); + console.log(''); + console.log(' -p, --port change the http port [default: 9000]'); + console.log(' -l, --list list available files in torrent'); + console.log(' -t, --subtitles load subtitles file'); + console.log(' -h, --help display this help message'); + console.log(' -v, --version print the current version'); + console.log(''); } -var argv = minimist(process.argv.slice(2)) - -var torrentId = argv._[0] - -var port = Number(argv.port || argv.p) || 9000 -var list = argv.list || argv.l -var subtitles = argv.subtitles || argv.t +var argv = minimist(process.argv.slice(2)), + torrentId = argv._[0], + port = Number(argv.port || argv.p) || 9000, + list = argv.list || argv.l, + subtitles = argv.subtitles || argv.t; if (argv.help || argv.h) { - usage() - process.exit(0) + usage(); + process.exit(0); } if (argv.version || argv.v) { - console.log(require('../package.json').version) - process.exit(0) + console.log(require('../package.json').version); + process.exit(0); } if (!torrentId) { - usage() - process.exit(0) + usage(); + process.exit(0); } -var VLC_ARGS = '-q --video-on-top --play-and-exit' -var OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string') - ? argv.omx + ' ' - : 'hdmi ' -var MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0 ' +var VLC_ARGS = '-q --video-on-top --play-and-exit', + OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string') + ? argv.omx + ' ' + : 'hdmi ', + MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0 '; if (subtitles) { - VLC_ARGS += ' --sub-file=' + subtitles - OMX_EXEC += ' --subtitles ' + subtitles - MPLAYER_EXEC += ' -sub ' + subtitles + VLC_ARGS += ' --sub-file=' + subtitles; + OMX_EXEC += ' --subtitles ' + subtitles; + MPLAYER_EXEC += ' -sub ' + subtitles; } var client = new WebTorrent({ list: list -}) -client.add(torrentId) +}); +client.add(torrentId); if (list) { // TODO client.on('torrent', function (torrent) { torrent.files.forEach(function (file, i) { - console.log(i, file.name) - }) - process.exit(0) - }) - return + console.log(i, file.name); + }); + process.exit(0); + }); + return; } From 2d896ae5e5e0138922242834b71ed7fb0f9c9917 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 16:48:07 -0600 Subject: [PATCH 2/7] make basic.js pass lint --- test/basic.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/basic.js b/test/basic.js index cf79627a..dce12954 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,6 +1,6 @@ -var test = require('tape') +var test = require('tape'); test('TODO', function (t) { - t.ok(true) - t.end() -}) \ No newline at end of file + t.ok(true); + t.end(); +}); \ No newline at end of file From 8719bc5f0ef74b10c2dbfb0d14deaf0432234213 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 16:54:45 -0600 Subject: [PATCH 3/7] make index.js pass lint --- index.js | 141 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/index.js b/index.js index 71a143f8..8cfdf310 100644 --- a/index.js +++ b/index.js @@ -1,152 +1,155 @@ // TODO: support blocklists -module.exports = WebTorrent +module.exports = WebTorrent; -var Client = require('bittorrent-client') -var fs = require('fs') -var http = require('http') -var inherits = require('inherits') -var mime = require('mime') -var rangeParser = require('range-parser') +var Client = require('bittorrent-client'), + fs = require('fs'), + http = require('http'), + inherits = require('inherits'), + mime = require('mime'), + rangeParser = require('range-parser'); -inherits(WebTorrent, Client) +inherits(WebTorrent, Client); function WebTorrent (opts) { - var self = this - Client.call(self, opts) - if (!opts) opts = {} - + var self = this; + Client.call(self, opts); + if (!opts){ + opts = {}; + } if (opts.list) { - return + return; } - self._startServer() + self._startServer(); self.on('torrent', function (torrent) { - self._onTorrent(torrent) - }) + self._onTorrent(torrent); + }); // TODO: add event that signals that all files that are "interesting" to the user have // completed and handle it by stopping fetching additional data from the network } WebTorrent.prototype.add = function (torrentId, cb) { - var self = this - if (typeof cb !== 'function') cb = function () {} + var self = this; + if (typeof cb !== 'function'){ + cb = function () {}; + } // TODO: support passing in an index to file to download // self.index = opts.index if (!self.ready) { - return self.once('ready', self.add.bind(self, torrentId, cb)) + return self.once('ready', self.add.bind(self, torrentId, cb)); } // Called once we have a torrentId that bittorrent-client can handle function onTorrentId (torrentId) { - var torrent = Client.prototype.add.call(self, torrentId, cb) // will emit 'torrent' event - cb(null, torrent) + var torrent = Client.prototype.add.call(self, torrentId, cb); // will emit 'torrent' event + cb(null, torrent); } if (Client.toInfoHash(torrentId)) { // magnet uri, info hash, or torrent file can be handled by bittorrent-client process.nextTick(function () { - onTorrentId(torrentId) - }) + onTorrentId(torrentId); + }); } else if (/^https?:/.test(torrentId)) { // http or https url to torrent file http.get(torrentId, function (res) { res.pipe(concat(function (torrent) { - onTorrentId(torrent) - })) + onTorrentId(torrent); + })); }).on('error', function (err) { - cb(new Error('Error downloading torrent from ' + torrentId + '\n' + err.message)) - }) + cb(new Error('Error downloading torrent from ' + torrentId + '\n' + err.message)); + }); } else { // assume it's a filesystem path fs.readFile(torrentId, function (err, torrent) { if (err) { return cb(new Error('Cannot add torrent. Require one of: magnet uri, ' + - 'info hash, torrent file, http url, or filesystem path')) + 'info hash, torrent file, http url, or filesystem path')); } - onTorrentId(torrent) - }) + onTorrentId(torrent); + }); } - return self -} + return self; +}; WebTorrent.prototype._onTorrent = function (torrent) { - var self = this - console.log('got metadata') - console.log('files:\n', torrent.files.map(function (f) { return f.name }).join('\n')) + var self = this; + console.log('got metadata'); + console.log('files:\n', torrent.files.map(function (f) { return f.name; }).join('\n')); // if no index specified, use largest file // TODO: support torrent index selection correctly -- this doesn't work yet if (typeof torrent.index !== 'number') { var largestFile = torrent.files.reduce(function (a, b) { - return a.length > b.length ? a : b - }) - torrent.index = torrent.files.indexOf(largestFile) + return a.length > b.length ? a : b; + }); + torrent.index = torrent.files.indexOf(largestFile); } // TODO - torrent.files[torrent.index].select() -} + torrent.files[torrent.index].select(); +}; WebTorrent.prototype._startServer = function () { - var self = this - self.server = http.createServer() - self.server.on('request', self._onRequest.bind(self)) -} + var self = this; + self.server = http.createServer(); + self.server.on('request', self._onRequest.bind(self)); +}; WebTorrent.prototype._onRequest = function (req, res) { - var self = this + var self = this; if (!self.ready) { - return self.once('ready', self._onRequest.bind(self, req, res)) + return self.once('ready', self._onRequest.bind(self, req, res)); } - var u = url.parse(req.url) + var u = url.parse(req.url); if (u.pathname === '/favicon.ico') { - return res.end() + return res.end(); } if (u.pathname === '/') { - u.pathname = '/' + self.index + u.pathname = '/' + self.index; } - var i = Number(u.pathname.slice(1)) + var i = Number(u.pathname.slice(1)); if (isNaN(i) || i >= e.files.length) { - res.statusCode = 404 - return res.end() + res.statusCode = 404; + return res.end(); } - res.setHeader('Accept-Ranges', 'bytes') - res.setHeader('Content-Type', mime.lookup(file.name)) + res.setHeader('Accept-Ranges', 'bytes'); + res.setHeader('Content-Type', mime.lookup(file.name)); - var file = e.files[i] - var range = req.headers.range + var file = e.files[i], + range = req.headers.range; if (!range) { - res.statusCode = 206 - res.setHeader('Content-Length', file.length) + res.statusCode = 206; + res.setHeader('Content-Length', file.length); if (req.method === 'HEAD') { - return res.end() + return res.end(); } - pump(file.createReadStream(), res) - return + pump(file.createReadStream(), res); + return; } - range = rangeParser(file.length, range)[0] // don't support multi-range reqs - res.statusCode = 206 + range = rangeParser(file.length, range)[0]; // don't support multi-range reqs + res.statusCode = 206; - var rangeStr = 'bytes ' + range.start + '-' + range.end + '/' + file.length - res.setHeader('Content-Range', rangeStr) - res.setHeader('Content-Length', range.end - range.start + 1) + var rangeStr = 'bytes ' + range.start + '-' + range.end + '/' + file.length; + res.setHeader('Content-Range', rangeStr); + res.setHeader('Content-Length', range.end - range.start + 1); if (req.method === 'HEAD') { - return res.end() + return res.end(); } - pump(file.createReadStream(range), res) -} + pump(file.createReadStream(range), res); +}; From 6d88f76b17a7a123cd2c8b7a5a883f814d00cb37 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 17:25:32 -0600 Subject: [PATCH 4/7] make torrent-manager.js pass lint --- lib/torrent-manager.js | 161 +++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/lib/torrent-manager.js b/lib/torrent-manager.js index de0730da..d42cd96a 100644 --- a/lib/torrent-manager.js +++ b/lib/torrent-manager.js @@ -1,137 +1,142 @@ -module.exports = TorrentManager +module.exports = TorrentManager; -var $ = require('jquery') -var async = require('async') -var DHT = require('bittorrent-dht') -var EventEmitter = require('events').EventEmitter -var hat = require('hat') -var inherits = require('inherits') -var portfinder = require('chrome-portfinder') -var speedometer = require('speedometer') -var Torrent = require('./torrent') +var $ = require('jquery'), + async = require('async'), + DHT = require('bittorrent-dht'), + EventEmitter = require('events').EventEmitter, + hat = require('hat'), + inherits = require('inherits'), + portfinder = require('chrome-portfinder'), + speedometer = require('speedometer'), + Torrent = require('./torrent'), + MAX_PEERS = 200; -var MAX_PEERS = 200 -portfinder.basePort = Math.floor(Math.random() * 60000) + 1025 // >1024 +portfinder.basePort = Math.floor(Math.random() * 60000) + 1025; // >1024 -inherits(TorrentManager, EventEmitter) +inherits(TorrentManager, EventEmitter); function TorrentManager () { - var self = this - if (!(self instanceof TorrentManager)) return new TorrentManager() - EventEmitter.call(self) + var self = this; + if (!(self instanceof TorrentManager)){ + return new TorrentManager(); + } + EventEmitter.call(self); // TODO: should these ids be consistent between restarts? - self.peerId = new Buffer('-WW0001-' + hat(48), 'utf8') - self.nodeId = new Buffer(hat(160), 'hex') + self.peerId = new Buffer('-WW0001-' + hat(48), 'utf8'); + self.nodeId = new Buffer(hat(160), 'hex'); - self.torrents = [] - self.ready = false - this.downloadSpeed = speedometer() - this.uploadSpeed = speedometer() + self.torrents = []; + self.ready = false; + this.downloadSpeed = speedometer(); + this.uploadSpeed = speedometer(); - self.dht = new DHT({ nodeId: self.nodeId }) + self.dht = new DHT({ nodeId: self.nodeId }); // self._reemitEvents(self.dht, 'dht', ['node', 'peer']) self.dht.on('peer', function (addr, infoHash) { - var torrent = self.getTorrent(infoHash) - torrent.addPeer(addr) - }) + var torrent = self.getTorrent(infoHash); + torrent.addPeer(addr); + }); - self._installWindowEvents() + self._installWindowEvents(); async.auto({ dhtPort: function (cb) { - portfinder.getPort(cb) + portfinder.getPort(cb); }, torrentPort: function (cb) { - portfinder.getPort(cb) + portfinder.getPort(cb); } }, function (err, r) { - self.dhtPort = r.dhtPort - self.torrentPort = r.torrentPort + self.dhtPort = r.dhtPort; + self.torrentPort = r.torrentPort; self.dht.listen(self.dhtPort, function () { - self.ready = true - self.emit('ready') - }) - }) + self.ready = true; + self.emit('ready'); + }); + }); } Object.defineProperty(TorrentManager.prototype, 'ratio', { get: function () { - var self = this - - var uploaded = self.torrents.reduce(function (total, torrent) { - return total + torrent.uploaded - }, 0) - var downloaded = self.torrents.reduce(function (total, torrent) { - return total + torrent.downloaded - }, 0) - - if (downloaded === 0) return 0 - return uploaded / downloaded + var self = this, + uploaded = self.torrents.reduce(function (total, torrent) { + return total + torrent.uploaded; + }, 0), + downloaded = self.torrents.reduce(function (total, torrent) { + return total + torrent.downloaded; + }, 0); + + if (downloaded === 0){ + return 0; + } + return uploaded / downloaded; } -}) +}); TorrentManager.prototype.getTorrent = function (infoHash) { - var self = this - var index - for (var i = 0, len = self.torrents.length; i < len; i += 1) { - var torrent = self.torrents[i] + var self = this, + index, + i; + for (i = 0, len = self.torrents.length; i < len; i += 1) { + var torrent = self.torrents[i]; if (torrent.infoHash === infoHash) - return torrent + return torrent; } - return null -} + return null; +}; /** * Add a torrent via magnet uri or torrent file * @param {string|Buffer} uri magnet uri or torrent file */ TorrentManager.prototype.addTorrent = function (uri) { - var self = this - if (!self.ready) - return self.once('ready', self.addTorrent.bind(self, uri)) + var self = this; + if (!self.ready){ + return self.once('ready', self.addTorrent.bind(self, uri)); + } var torrent = new Torrent(uri, { peerId: self.peerId, torrentPort: self.torrentPort, dhtPort: self.dhtPort - }) - self.torrents.push(torrent) + }); + self.torrents.push(torrent); torrent.swarm.on('download', function (downloaded) { - self.downloadSpeed(downloaded) - }) + self.downloadSpeed(downloaded); + }); torrent.swarm.on('upload', function (uploaded) { - self.uploadSpeed(uploaded) - }) + self.uploadSpeed(uploaded); + }); // self._reemitEvents(torrent, 'torrent', ['listening']) - self.emit('addTorrent', torrent) + self.emit('addTorrent', torrent); torrent.on('listening', function (port) { - console.log('Swarm listening on port ' + port) + console.log('Swarm listening on port ' + port); // TODO: Add the torrent to the public DHT so peers know to find up - }) + }); torrent.on('error', function (err) { - self.emit('error', err) - }) + self.emit('error', err); + }); - self.dht.setInfoHash(torrent.infoHash) - self.dht.findPeers(MAX_PEERS) // TODO: should the DHT be concerned with max peers? -} + self.dht.setInfoHash(torrent.infoHash); + self.dht.findPeers(MAX_PEERS); // TODO: should the DHT be concerned with max peers? +}; TorrentManager.prototype._reemitEvents = function (obj, eventPrefix, events) { - var self = this + var self = this; events.forEach(function (event) { obj.on(event, function () { - var args = Array.prototype.slice.call(arguments) - args.unshift(eventPrefix + ':' + event, obj) - self.emit.apply(self, args) - }) - }) -} + var args = Array.prototype.slice.call(arguments); + args.unshift(eventPrefix + ':' + event, obj); + self.emit.apply(self, args); + }); + }); +}; From bf1799b982a9d8b26c33890355fc8bee14dc2a8f Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 17:48:49 -0600 Subject: [PATCH 5/7] make storage.js pass lint --- lib/storage.js | 340 ++++++++++++++++++++++++++----------------------- 1 file changed, 178 insertions(+), 162 deletions(-) diff --git a/lib/storage.js b/lib/storage.js index a29bd285..38ec40d7 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -1,16 +1,16 @@ -module.exports = Storage +module.exports = Storage; -var BitField = require('bitfield') -var EventEmitter = require('events').EventEmitter -var inherits = require('inherits') -var Rusha = require('rusha-browserify') // Fast SHA1 (works in browser) +var BitField = require('bitfield'), + EventEmitter = require('events').EventEmitter, + inherits = require('inherits'), + Rusha = require('rusha-browserify'), // Fast SHA1 (works in browser) -var BLOCK_LENGTH = 16 * 1024 -var BLOCK_BLANK = 0 -var BLOCK_RESERVED = 1 -var BLOCK_WRITTEN = 2 + BLOCK_LENGTH = 16 * 1024, + BLOCK_BLANK = 0, + BLOCK_RESERVED = 1, + BLOCK_WRITTEN = 2; -inherits(Piece, EventEmitter) +inherits(Piece, EventEmitter); /** * Piece @@ -22,105 +22,115 @@ inherits(Piece, EventEmitter) * @param {Buffer} buffer backing buffer for this piece */ function Piece (index, hash, buffer) { - var self = this - if (!(self instanceof Piece)) return new Piece(index, hash, buffer) - EventEmitter.call(self) + var self = this; + if (!(self instanceof Piece)){ + return new Piece(index, hash, buffer); + } + EventEmitter.call(self); - self.index = index - self.hash = hash - self.buffer = buffer + self.index = index; + self.hash = hash; + self.buffer = buffer; - self.length = buffer.length - self._reset() + self.length = buffer.length; + self._reset(); } Piece.prototype.readBlock = function (offset, length) { - var self = this - if (!self._verifyOffset(offset)) return - return self.buffer.slice(offset, offset + length) -} + var self = this; + return self._verifyOffset(offset)?self.buffer.slice(offset, offset + length):undefined; +}; Piece.prototype.writeBlock = function (offset, buffer) { - var self = this - if (!self._verifyOffset(offset)) return - if (!self._verifyBlock(offset, buffer)) return + var self = this; + if (!self._verifyOffset(offset) || !self._verifyBlock(offset, buffer)){ + return; + } - var i = offset / BLOCK_LENGTH - if (self.blocks[i] === BLOCK_WRITTEN) return + var i = offset / BLOCK_LENGTH; + if (self.blocks[i] === BLOCK_WRITTEN){ + return; + } - buffer.copy(self.buffer, offset) - self.blocks[i] = BLOCK_WRITTEN - self.blocksWritten += 1 + buffer.copy(self.buffer, offset); + self.blocks[i] = BLOCK_WRITTEN; + self.blocksWritten += 1; - if (self.blocksWritten === self.blocks.length) - self._verify() -} + if (self.blocksWritten === self.blocks.length){ + self._verify(); + } +}; Piece.prototype.selectBlock = function (endGame) { - var self = this - var len = self.blocks.length + var self = this, + len = self.blocks.length; for (var i = 0; i < len; i++) { - if ((self.blocks[i] && !endGame) || self.blocks[i] === BLOCK_WRITTEN) continue - self.blocks[i] = BLOCK_RESERVED + if ((self.blocks[i] && !endGame) || self.blocks[i] === BLOCK_WRITTEN){ + continue; + } + self.blocks[i] = BLOCK_RESERVED; return { offset: i * BLOCK_LENGTH, - length: (i === len - 1) - ? self.length - (i * BLOCK_LENGTH) - : BLOCK_LENGTH - } + length: (i === len - 1) ? self.length - (i * BLOCK_LENGTH) : BLOCK_LENGTH + }; } - return null -} + return null; +}; Piece.prototype.deselectBlock = function (offset) { - var self = this - if (!self._verifyOffset(offset)) return + var self = this; + if (!self._verifyOffset(offset)){ + return; + } - var i = offset / BLOCK_LENGTH - if (self.blocks[i] === BLOCK_RESERVED) - self.blocks[i] = BLOCK_BLANK -} + var i = offset / BLOCK_LENGTH; + if (self.blocks[i] === BLOCK_RESERVED){ + self.blocks[i] = BLOCK_BLANK; + } +}; Piece.prototype._reset = function () { - var self = this - self.verified = false - self.blocks = new Buffer(Math.ceil(self.length / BLOCK_LENGTH)) - self.blocksWritten = 0 -} + var self = this; + self.verified = false; + self.blocks = new Buffer(Math.ceil(self.length / BLOCK_LENGTH)); + self.blocksWritten = 0; +}; Piece.prototype._verify = function () { - var self = this - if (self.verified) return - - self.verified = (sha1(self.buffer) === self.hash) - if (self.verified) - self.emit('done') - else { - console.error('piece', self.index, 'failed verification', sha1(self.buffer), 'expected', self.hash) - self._reset() + var self = this; + if (self.verified){ + return; } -} + + self.verified = (sha1(self.buffer) === self.hash); + if (self.verified){ + self.emit('done'); + } else { + console.error('piece', self.index, 'failed verification', sha1(self.buffer), 'expected', self.hash); + self._reset(); + } +}; Piece.prototype._verifyOffset = function (offset) { if (offset % BLOCK_LENGTH === 0) { - return true + return true; } else { - console.error('invalid offset', offset, 'not multiple of', BLOCK_LENGTH, 'bytes') - return false + console.error('invalid offset', offset, 'not multiple of', BLOCK_LENGTH, 'bytes'); + return false; } -} +}; Piece.prototype._verifyBlock = function (offset, buffer) { - var self = this + var self = this; if ((self.length - offset) < BLOCK_LENGTH || buffer.length === BLOCK_LENGTH) { - return true + return true; } else { - console.error('invalid block of size', buffer.length, 'bytes') - return false + console.error('invalid block of size', buffer.length, 'bytes'); + return false; } -} +}; -inherits(File, EventEmitter) +inherits(File, EventEmitter); /** * File @@ -132,36 +142,39 @@ inherits(File, EventEmitter) * @param {Array.} pieces backing pieces for this file */ function File (file, buffer, pieces) { - var self = this - if (!(self instanceof File)) return new File(file, buffer, pieces) - EventEmitter.call(self) + var self = this; + if (!(self instanceof File)){ + return new File(file, buffer, pieces); + } + EventEmitter.call(self); - self.name = file.name - self.path = file.path - self.length = file.length - self.offset = file.offset - self.buffer = buffer - self.pieces = pieces + self.name = file.name; + self.path = file.path; + self.length = file.length; + self.offset = file.offset; + self.buffer = buffer; + self.pieces = pieces; - self.done = false + self.done = false; self.pieces.forEach(function (piece) { piece.on('done', function () { - self._checkDone() - }) - }) + self._checkDone(); + }); + }); } File.prototype._checkDone = function () { - var self = this + var self = this; self.done = self.pieces.every(function (piece) { - return piece.verified - }) - if (self.done) - self.emit('done') -} + return piece.verified; + }); + if (self.done){ + self.emit('done'); + } +}; -inherits(Storage, EventEmitter) +inherits(Storage, EventEmitter); /** * Storage @@ -171,113 +184,116 @@ inherits(Storage, EventEmitter) * @param {[type]} parsedTorrent [description] */ function Storage (parsedTorrent) { - var self = this - if (!(self instanceof Storage)) return new Storage(parsedTorrent) - EventEmitter.call(self) + var self = this; + if (!(self instanceof Storage)){ + return new Storage(parsedTorrent); + } + EventEmitter.call(self); - self.parsedTorrent = parsedTorrent - self.pieceLength = parsedTorrent.pieceLength + self.parsedTorrent = parsedTorrent; + self.pieceLength = parsedTorrent.pieceLength; - self.buffer = new Buffer(self.parsedTorrent.length) - self.bitfield = new BitField(self.parsedTorrent.pieces.length) + self.buffer = new Buffer(self.parsedTorrent.length); + self.bitfield = new BitField(self.parsedTorrent.pieces.length); self.pieces = self.parsedTorrent.pieces.map(function (hash, index) { - var start = index * self.pieceLength - var end = start + self.pieceLength - var buffer = self.buffer.slice(start, end) // references same memory - - var piece = new Piece(index, hash, buffer) - piece.on('done', self._onPieceDone.bind(self, piece)) - return piece - }) + var start = index * self.pieceLength, + end = start + self.pieceLength, + buffer = self.buffer.slice(start, end), // references same memory + piece = new Piece(index, hash, buffer); + piece.on('done', self._onPieceDone.bind(self, piece)); + return piece; + }); self.files = self.parsedTorrent.files.map(function (fileObj) { - var start = fileObj.offset - var end = start + fileObj.length - var buffer = self.buffer.slice(start, end) // references same memory - - var startPiece = start / self.pieceLength | 0 - var endPiece = (end - 1) / self.pieceLength | 0 - var pieces = self.pieces.slice(startPiece, endPiece + 1) - - var file = new File(fileObj, buffer, pieces) - file.on('done', self._onFileDone.bind(self, file)) - return file - }) + var start = fileObj.offset; + var end = start + fileObj.length; + var buffer = self.buffer.slice(start, end); // references same memory + + var startPiece = start / self.pieceLength | 0; + var endPiece = (end - 1) / self.pieceLength | 0; + var pieces = self.pieces.slice(startPiece, endPiece + 1); + + var file = new File(fileObj, buffer, pieces); + file.on('done', self._onFileDone.bind(self, file)); + return file; + }); } Object.defineProperty(Storage.prototype, 'downloaded', { get: function () { - var self = this - var downloaded = 0 + var self = this; + var downloaded = 0; return self.pieces.reduce(function (total, piece) { - return total + (piece.verified ? piece.length : 0) - }, 0) + return total + (piece.verified ? piece.length : 0); + }, 0); } -}) +}); /** * The number of missing pieces. Used to implement "end game" mode. */ Object.defineProperty(Storage.prototype, 'numMissing', { get: function () { - var self = this - var numMissing = self.pieces.length - for (var index = 0, len = self.pieces.length; index < len; index++) { - numMissing -= self.bitfield.get(index) + var self = this, + numMissing = self.pieces.length, + index; + for (index = 0, len = self.pieces.length; index < len; index++) { + numMissing -= self.bitfield.get(index); } - return numMissing + return numMissing; } -}) +}); Storage.prototype.readBlock = function (index, offset, length) { - var self = this - var piece = self.pieces[index] - if (!piece) return null - return piece.readBlock(offset, length) -} + var self = this, + piece = self.pieces[index]; + + return !piece ? null : piece.readBlock(offset, length); +}; Storage.prototype.writeBlock = function (index, offset, buffer) { - var self = this - var piece = self.pieces[index] - if (!piece) return - piece.writeBlock(offset, buffer) -} + var self = this, + piece = self.pieces[index]; + if (piece){ + piece.writeBlock(offset, buffer); + } +}; Storage.prototype.selectBlock = function (index, endGame) { - var self = this - var piece = self.pieces[index] - if (!piece) return null - return piece.selectBlock(endGame) -} + var self = this, + piece = self.pieces[index]; + return !piece ? null : piece.selectBlock(endGame); +}; Storage.prototype.deselectBlock = function (index, offset) { - var self = this - var piece = self.pieces[index] - if (!piece) return - piece.deselectBlock(offset) -} + var self = this, + piece = self.pieces[index]; + if (piece){ + piece.deselectBlock(offset); + } +}; // // HELPER METHODS // Storage.prototype._onPieceDone = function (piece) { - var self = this - console.log('PIECE DONE', self.progress, self.numMissing) - self.bitfield.set(piece.index) - self.emit('piece', piece) -} + var self = this; + console.log('PIECE DONE', self.progress, self.numMissing); + self.bitfield.set(piece.index); + self.emit('piece', piece); +}; Storage.prototype._onFileDone = function (file) { - var self = this - self.emit('file', file) + var self = this; + self.emit('file', file); // TODO - self.emit('done') -} + self.emit('done'); +}; function sha1 (buf) { - return (new Rusha()).digestFromBuffer(buf) + return (new Rusha()).digestFromBuffer(buf); } From ca04f5c55bbe01baf4907ec5ea3030f9570475af Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 18:22:42 -0600 Subject: [PATCH 6/7] make torrent.js pass lint --- lib/torrent.js | 271 +++++++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 133 deletions(-) diff --git a/lib/torrent.js b/lib/torrent.js index 8d2f0e0d..e771aa98 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -1,21 +1,21 @@ -module.exports = Torrent +module.exports = Torrent; -var bncode = require('bncode') -var EventEmitter = require('events').EventEmitter -var inherits = require('inherits') -var magnet = require('magnet-uri') -var parseTorrent = require('parse-torrent') -var Storage = require('./storage') -var Swarm = require('bittorrent-swarm') -var ut_metadata = require('ut_metadata') +var bncode = require('bncode'), + EventEmitter = require('events').EventEmitter, + inherits = require('inherits'), + magnet = require('magnet-uri'), + parseTorrent = require('parse-torrent'), + Storage = require('./storage'), + Swarm = require('bittorrent-swarm'), + ut_metadata = require('ut_metadata'), -var BLOCK_LENGTH = 16 * 1024 -var MAX_BLOCK_LENGTH = 128 * 1024 -var MAX_OUTSTANDING_REQUESTS = 5 -var METADATA_BLOCK_LENGTH = 16 * 1024 -var PIECE_TIMEOUT = 10000 + BLOCK_LENGTH = 16 * 1024, + MAX_BLOCK_LENGTH = 128 * 1024, + MAX_OUTSTANDING_REQUESTS = 5, + METADATA_BLOCK_LENGTH = 16 * 1024, + PIECE_TIMEOUT = 10000; -inherits(Torrent, EventEmitter) +inherits(Torrent, EventEmitter); /** * Torrent @@ -26,45 +26,48 @@ inherits(Torrent, EventEmitter) * @param {Object} opts options object */ function Torrent (uri, opts) { - var self = this - if (!(self instanceof Torrent)) return new Torrent(uri, opts) - EventEmitter.call(self) + var self = this; + if (!(self instanceof Torrent)) { + return new Torrent(uri, opts); + } + EventEmitter.call(self); if (typeof uri === 'string') { // magnet uri - var info = parseMagnetUri(uri) - if (!info.infoHash) - throw new Error('invalid torrent uri') - self.infoHash = info.infoHash - self.name = info.name + var info = parseMagnetUri(uri); + if (!info.infoHash){ + throw new Error('invalid torrent uri'); + } + self.infoHash = info.infoHash; + self.name = info.name; } else if (Buffer.isBuffer(uri)) { // torrent file - self._onMetadata(uri) + self._onMetadata(uri); } - self.peerId = opts.peerId - self.torrentPort = opts.torrentPort - self.dhtPort = opts.dhtPort + self.peerId = opts.peerId; + self.torrentPort = opts.torrentPort; + self.dhtPort = opts.dhtPort; - self.metadata = null - self.parsedTorrent = null + self.metadata = null; + self.parsedTorrent = null; self.swarm = new Swarm(self.infoHash, self.peerId, { handshake: { dht: true } - }) - self.storage = null + }); + self.storage = null; if (self.torrentPort) { self.swarm.listen(self.torrentPort, function (port) { - self.emit('listening', port) - }) + self.emit('listening', port); + }); } self.swarm.on('error', function (err) { - self.emit('error', err) - }) + self.emit('error', err); + }); - self.swarm.on('wire', self._onWire.bind(self)) + self.swarm.on('wire', self._onWire.bind(self)); } /** @@ -72,221 +75,223 @@ function Torrent (uri, opts) { */ Object.defineProperty(Torrent.prototype, 'length', { get: function () { - var self = this - if (!self.parsedTorrent) return 0 - return self.parsedTorrent.length + var self = this; + return !self.parsedTorrent ? 0 : self.parsedTorrent.length; } -}) +}); /** * Time remaining (in milliseconds) */ Object.defineProperty(Torrent.prototype, 'timeRemaining', { get: function () { - var self = this - var remainingBytes = self.length - self.downloaded - if (self.swarm.downloadSpeed() === 0) return Infinity - return (remainingBytes / self.swarm.downloadSpeed()) * 1000 + var self = this, + remainingBytes = self.length - self.downloaded; + return self.swarm.downloadSpeed() === 0 ? Infinity : (remainingBytes / self.swarm.downloadSpeed()) * 1000; } -}) +}); /** * Percentage complete, represented as a number between 0 and 1 */ Object.defineProperty(Torrent.prototype, 'progress', { get: function () { - var self = this - if (!self.parsedTorrent) return 0 - return self.downloaded / self.parsedTorrent.length + var self = this; + return !self.parsedTorrent ? 0 : self.downloaded / self.parsedTorrent.length; } -}) +}); /** * Bytes downloaded (and verified) */ Object.defineProperty(Torrent.prototype, 'downloaded', { get: function () { - var self = this - return (self.storage && self.storage.downloaded) || 0 + var self = this; + return (self.storage && self.storage.downloaded) || 0; } -}) +}); /** * Bytes uploaded */ Object.defineProperty(Torrent.prototype, 'uploaded', { get: function () { - var self = this - return self.swarm.uploaded + var self = this; + return self.swarm.uploaded; } -}) +}); /** * Ratio of bytes downloaded to uploaded */ Object.defineProperty(Torrent.prototype, 'ratio', { get: function () { - var self = this - if (self.uploaded === 0) return 0 - return self.downloaded / self.uploaded + var self = this; + return self.uploaded === 0 ? 0 : self.downloaded / self.uploaded; } -}) +}); /** * Add a peer to the swarm * @param {string} addr */ Torrent.prototype.addPeer = function (addr) { - var self = this - self.swarm.add(addr) -} + var self = this; + self.swarm.add(addr); +}; Torrent.prototype._onWire = function (wire) { - var self = this + var self = this; - wire.use(ut_metadata(self.metadata)) + wire.use(ut_metadata(self.metadata)); wire.ut_metadata.on('metadata', function (metadata) { - self._onMetadata(metadata) - }) + self._onMetadata(metadata); + }); - wire.ut_metadata.fetch(metadata) + wire.ut_metadata.fetch(metadata); // Send KEEP-ALIVE (every 60s) so peers will not disconnect the wire - wire.setKeepAlive(true) + wire.setKeepAlive(true); // If peer supports DHT, send PORT message to report DHT node listening port if (wire.peerExtensions.dht) { - console.log(wire.remoteAddress, 'supports DHT') - wire.port(self.dhtPort) + console.log(wire.remoteAddress, 'supports DHT'); + wire.port(self.dhtPort); } // When peer sends PORT, add them to the routing table wire.on('port', function (port) { - console.log(wire.remoteAddress, 'port', port) + console.log(wire.remoteAddress, 'port', port); // TODO: DHT doesn't have a routing table yet // dht.add(wire.remoteAddress, port) - }) + }); // Timeout for piece requests to this peer - wire.setTimeout(PIECE_TIMEOUT) -} + wire.setTimeout(PIECE_TIMEOUT); +}; Torrent.prototype._onWireWithMetadata = function (wire) { - var self = this + var self = this; function requestPiece (index) { - var len = wire.requests.length - if (len >= MAX_OUTSTANDING_REQUESTS) return - - var endGame = (len === 0 && self.storage.numMissing < 30) - var block = self.storage.selectBlock(index, endGame) - if (!block) return - - console.log(wire.remoteAddress, 'requestPiece', index, 'offset', block.offset, 'length', block.length) - wire.request(index, block.offset, block.length, function (err, bufffer) { - if (err) - return self.storage.deselectBlock(index, block.offset) + var len = wire.requests.length; + if (len >= MAX_OUTSTANDING_REQUESTS){ + return; + } - self.storage.writeBlock(index, block.offset, bufffer) - requestPieces() - }); + var endGame = (len === 0 && self.storage.numMissing < 30), + block = self.storage.selectBlock(index, endGame); + if (block){ + console.log(wire.remoteAddress, 'requestPiece', index, 'offset', block.offset, 'length', block.length); + wire.request(index, block.offset, block.length, function (err, bufffer) { + if (err){ + return self.storage.deselectBlock(index, block.offset); + } + + self.storage.writeBlock(index, block.offset, bufffer); + requestPieces(); + }); + } } function requestPieces () { for (var index = 0, len = wire.peerPieces.length; index < len; index++) { if (wire.peerPieces[index] && self.storage.pieces[index]) { // if peer has this piece AND it's a valid piece, then request blocks - requestPiece(index) + requestPiece(index); } } } wire.on('have', function (index) { - if (wire.peerChoking || !self.storage.pieces[index]) - return - requestPiece(index) + if (wire.peerChoking || !self.storage.pieces[index]){ + return; + } + requestPiece(index); }); - wire.on('unchoke', requestPieces) + wire.on('unchoke', requestPieces); wire.once('interested', function () { - wire.unchoke() - }) + wire.unchoke(); + }); wire.on('request', function (index, offset, length, cb) { // Disconnect from peers that request more than 128KB, per spec if (length > MAX_BLOCK_LENGTH) { - console.error(wire.remoteAddress, 'requested invalid block size', length) - return wire.destroy() + console.error(wire.remoteAddress, 'requested invalid block size', length); + return wire.destroy(); } process.nextTick(function () { - var block = self.storage.readBlock(index, offset, length) - if (!block) return cb(new Error('requested block not available')) - cb(null, block) - }) - }) - - wire.bitfield(self.storage.bitfield) // always send bitfield (required) - wire.interested() // always start out interested -} + var block = self.storage.readBlock(index, offset, length); + if (!block){ + return cb(new Error('requested block not available')); + } + cb(null, block); + }); + }); + + wire.bitfield(self.storage.bitfield); // always send bitfield (required) + wire.interested(); // always start out interested +}; Torrent.prototype._onMetadata = function (metadata) { - var self = this + var self = this; - self.metadata = metadata + self.metadata = metadata; try { - var info = bncode.decode(metadata) + var info = bncode.decode(metadata); // TODO: can this be removed? if (info.info) { - self.torrentFile = info + self.torrentFile = info; } else { self.torrentFile = bncode.encode({ 'announce-list': [], infoHash: self.infoHash, info: info - }) + }); } - self.parsedTorrent = parseTorrent(self.torrentFile) + self.parsedTorrent = parseTorrent(self.torrentFile); } catch (err) { - console.error(err) - return + console.error(err); + return; } - self.name = self.parsedTorrent.name - self.infoHash = self.parsedTorrent.infoHash + self.name = self.parsedTorrent.name; + self.infoHash = self.parsedTorrent.infoHash; - self.storage = new Storage(self.parsedTorrent) - self.storage.on('piece', self._onStoragePiece.bind(self)) + self.storage = new Storage(self.parsedTorrent); + self.storage.on('piece', self._onStoragePiece.bind(self)); self.storage.on('file', function (file) { - console.log('FILE', file.name) - }) + console.log('FILE', file.name); + }); self.storage.on('done', function () { - console.log('done with torrent!') - }) + console.log('done with torrent!'); + }); if (self.swarm) { self.swarm.wires.forEach(function (wire) { - self._onWireWithMetadata(wire) - }) + self._onWireWithMetadata(wire); + }); } -} +}; /** * When a piece is fully downloaded, notify all peers with a HAVE message. * @param {Piece} piece */ Torrent.prototype._onStoragePiece = function (piece) { - var self = this - console.log('PIECE', piece.index) + var self = this; + console.log('PIECE', piece.index); self.swarm.wires.forEach(function (wire) { - wire.have(piece.index) - }) -} + wire.have(piece.index); + }); +}; // // HELPER METHODS @@ -298,9 +303,9 @@ Torrent.prototype._onStoragePiece = function (piece) { * @return {Object} */ function parseMagnetUri (uri) { - var parsed = magnet(uri) + var parsed = magnet(uri); return { name: parsed.dn, // displayName infoHash: parsed.xt && parsed.xt.split('urn:btih:')[1] - } + }; } From c1500c171a4e7ee5031bfb39a3e83eacbdeb1bf8 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Mon, 12 May 2014 18:26:24 -0600 Subject: [PATCH 7/7] added gitignore, because you know, ignoring shit. --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file