diff options
author | Feross Aboukhadijeh <feross@feross.org> | 2014-09-21 05:41:24 +0400 |
---|---|---|
committer | Feross Aboukhadijeh <feross@feross.org> | 2014-09-21 05:41:24 +0400 |
commit | 93686505fbc90522c75b6c151ec7261aa76098de (patch) | |
tree | 5b474b920e79b7b39b6804fac5e6a641de6ae843 /lib/rarity-map.js | |
parent | 2e14192c311f64c20496a72af7ffce36495be92b (diff) |
merge `bittorrent-client` into this module
When I started the WebTorrent project I thought there were going to
need to be two separate client implementations (bittorrent-client and
webtorrent-client) that would get tied together in a higher-level
module.
Fortunately, this was not necessary because of the awesome “browser”
field support in browserify. By substituting just a few modules, we can
make the same module (webtorrent) work in node AND the browser, with
the same codebase!
So, from now on, you can just `require(‘webtorrent’)` in node or the
browser, and it will just work. You can also `npm install webtorrent`
if you want to use bittorrent in a node app or script. Lastly, you can
`npm install webtorrent -g` if you want to use webtorrent as a command
line app (it installs a `webtorrent` command).
Diffstat (limited to 'lib/rarity-map.js')
-rw-r--r-- | lib/rarity-map.js | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/lib/rarity-map.js b/lib/rarity-map.js new file mode 100644 index 0000000..2d7a2ce --- /dev/null +++ b/lib/rarity-map.js @@ -0,0 +1,86 @@ +module.exports = RarityMap + +/** + * Mapping of torrent pieces to their respective availability in the swarm. Used by + * the torrent manager for implementing the rarest piece first selection strategy. + * + * @param {Swarm} swarm bittorrent-swarm to track availability + * @param {number} numPieces number of pieces in the torrent + */ +function RarityMap (swarm, numPieces) { + var self = this + + self.swarm = swarm + self.numPieces = numPieces + + function initWire (wire) { + wire.on('have', function (index) { + self.pieces[index]++ + }) + wire.on('bitfield', self.recalculate.bind(self)) + wire.on('close', function () { + for (var i = 0; i < self.numPieces; ++i) { + self.pieces[i] -= wire.peerPieces.get(i) + } + }) + } + + self.swarm.wires.forEach(initWire) + self.swarm.on('wire', function (wire) { + self.recalculate() + initWire(wire) + }) + + self.recalculate() +} + +/** + * Recalculates piece availability across all peers in the swarm. + */ +RarityMap.prototype.recalculate = function () { + var self = this + + self.pieces = [] + for (var i = 0; i < self.numPieces; ++i) { + self.pieces[i] = 0 + } + + self.swarm.wires.forEach(function (wire) { + for (var i = 0; i < self.numPieces; ++i) { + self.pieces[i] += wire.peerPieces.get(i) + } + }) +} + +/** + * Get the index of the rarest piece. Optionally, pass a filter function to exclude + * certain pieces (for instance, those that we already have). + * + * @param {function} pieceFilterFunc + * @return {number} index of rarest piece, or -1 + */ +RarityMap.prototype.getRarestPiece = function (pieceFilterFunc) { + var self = this + var candidates = [] + var min = Infinity + pieceFilterFunc = pieceFilterFunc || function () { return true } + + for (var i = 0; i < self.numPieces; ++i) { + if (!pieceFilterFunc(i)) continue + + var availability = self.pieces[i] + if (availability === min) { + candidates.push(i) + } else if (availability < min) { + candidates = [ i ] + min = availability + } + } + + if (candidates.length > 0) { + // if there are multiple pieces with the same availability, choose one randomly + return candidates[Math.random() * candidates.length | 0] + } else { + return -1 + } +} |