diff --git a/lib/rarity-map.js b/lib/rarity-map.js index 430f62f8..76307344 100644 --- a/lib/rarity-map.js +++ b/lib/rarity-map.js @@ -1,121 +1,108 @@ -module.exports = RarityMap /** * Mapping of torrent pieces to their respective availability in the torrent swarm. Used * by the torrent manager for implementing the rarest piece first selection strategy. */ -function RarityMap (torrent) { - var self = this - - self._torrent = torrent - self._numPieces = torrent.pieces.length - self._pieces = [] +class RarityMap { + constructor (torrent) { + this._torrent = torrent + this._numPieces = torrent.pieces.length + this._pieces = new Array(this._numPieces) + + this._onWire = wire => { + this.recalculate() + this._initWire(wire) + } + this._onWireHave = index => { + this._pieces[index] += 1 + } + this._onWireBitfield = () => { + this.recalculate() + } - self._onWire = function (wire) { - self.recalculate() - self._initWire(wire) - } - self._onWireHave = function (index) { - self._pieces[index] += 1 - } - self._onWireBitfield = function () { - self.recalculate() + this._torrent.wires.forEach(wire => { + this._initWire(wire) + }) + this._torrent.on('wire', this._onWire) + this.recalculate() } - self._torrent.wires.forEach(function (wire) { - self._initWire(wire) - }) - self._torrent.on('wire', self._onWire) - self.recalculate() -} - -/** - * 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) { - if (!pieceFilterFunc) pieceFilterFunc = trueFn - - var candidates = [] - var min = Infinity - - for (var i = 0; i < this._numPieces; ++i) { - if (!pieceFilterFunc(i)) continue + /** + * 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 + */ + getRarestPiece (pieceFilterFunc) { + let candidates = [] + let min = Infinity + + for (let i = 0; i < this._numPieces; ++i) { + if (pieceFilterFunc && !pieceFilterFunc(i)) continue + + const availability = this._pieces[i] + if (availability === min) { + candidates.push(i) + } else if (availability < min) { + candidates = [ i ] + min = availability + } + } - var availability = this._pieces[i] - if (availability === min) { - candidates.push(i) - } else if (availability < min) { - candidates = [ i ] - min = availability + if (candidates.length) { + // if there are multiple pieces with the same availability, choose one randomly + return candidates[Math.random() * candidates.length | 0] + } else { + return -1 } } - 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 + destroy () { + this._torrent.removeListener('wire', this._onWire) + this._torrent.wires.forEach(wire => { + this._cleanupWireEvents(wire) + }) + this._torrent = null + this._pieces = null + + this._onWire = null + this._onWireHave = null + this._onWireBitfield = null } -} -RarityMap.prototype.destroy = function () { - var self = this - self._torrent.removeListener('wire', self._onWire) - self._torrent.wires.forEach(function (wire) { - self._cleanupWireEvents(wire) - }) - self._torrent = null - self._pieces = null - - self._onWire = null - self._onWireHave = null - self._onWireBitfield = null -} - -RarityMap.prototype._initWire = function (wire) { - var self = this - - wire._onClose = function () { - self._cleanupWireEvents(wire) - for (var i = 0; i < this._numPieces; ++i) { - self._pieces[i] -= wire.peerPieces.get(i) + _initWire (wire) { + wire._onClose = () => { + this._cleanupWireEvents(wire) + for (let i = 0; i < this._numPieces; ++i) { + this._pieces[i] -= wire.peerPieces.get(i) + } } - } - - wire.on('have', self._onWireHave) - wire.on('bitfield', self._onWireBitfield) - wire.once('close', wire._onClose) -} -/** - * Recalculates piece availability across all peers in the torrent. - */ -RarityMap.prototype.recalculate = function () { - var i - for (i = 0; i < this._numPieces; ++i) { - this._pieces[i] = 0 + wire.on('have', this._onWireHave) + wire.on('bitfield', this._onWireBitfield) + wire.once('close', wire._onClose) } - var numWires = this._torrent.wires.length - for (i = 0; i < numWires; ++i) { - var wire = this._torrent.wires[i] - for (var j = 0; j < this._numPieces; ++j) { - this._pieces[j] += wire.peerPieces.get(j) + /** + * Recalculates piece availability across all peers in the torrent. + */ + recalculate () { + this._pieces.fill(0) + + for (const wire of this._torrent.wires) { + for (let i = 0; i < this._numPieces; ++i) { + this._pieces[i] += wire.peerPieces.get(i) + } } } -} -RarityMap.prototype._cleanupWireEvents = function (wire) { - wire.removeListener('have', this._onWireHave) - wire.removeListener('bitfield', this._onWireBitfield) - if (wire._onClose) wire.removeListener('close', wire._onClose) - wire._onClose = null + _cleanupWireEvents (wire) { + wire.removeListener('have', this._onWireHave) + wire.removeListener('bitfield', this._onWireBitfield) + if (wire._onClose) wire.removeListener('close', wire._onClose) + wire._onClose = null + } } -function trueFn () { - return true -} +module.exports = RarityMap