I’m stuck on Stage #ND2.
I am getting all zeroes as output from the peer and the hash is not matching
And here’s a snippet of my code:
waitForRequestedPiece(client) {
return new Promise((resolve, reject) => {
client.on("data", onData)
client.on("error", onError)
let buffer = Buffer.alloc(0)
function onData(chunk) {
buffer = Buffer.concat([buffer, chunk])
while (buffer.length >= 4) {
const msgLength = buffer.readInt32BE(0)
if (msgLength === 0) {
console.log("Got keep alive ;)")
buffer = buffer.subarray(4)
continue
}
if (buffer.length < msgLength + 4) {
console.log("waiting for data")
return
}
const msg = buffer.subarray(4, 4 + msgLength)
buffer = buffer.subarray(4 + msgLength)
const msgId = msg.readUInt8(0)
if (msgId === 7){
console.log(`Received piece index`)
const pieceIndex = msg.readInt32BE(1)
const begin = msg.readInt32BE(5)
const blockData = msg.readInt32BE(9)
cleanup()
return resolve({pieceIndex, begin, blockData})
}
else {
console.log(`Got msg ID ${msgId}, ignoring...`)
}
}
}
function onError(err) {
cleanup()
return reject(err)
}
function cleanup() {
client.removeListener("data", onData)
client.removeListener("error", onError)
}
});
}
async downloadPieces(pieceIndex, outFile) {
const peers = await this.torrent.getPeers()
const {client, response} = await this.initiateHandShake(peers[0]);
try {
this.sendInterested(client)
await this.waitForUnchoke(client);
const pieceLength = this.torrent.getPieceLength()
const fileLength = this.torrent.getFileLength()
const indexPieceLength = (pieceIndex === Math.floor(fileLength/pieceLength)) ? fileLength % pieceLength : pieceLength ;
const piece = Buffer.alloc(indexPieceLength)
const sixteenKb = 16 * 1024
let offset = 0;
while (offset < indexPieceLength) {
const requestedBlocks = []
for (let count = 0; count < 5 && offset < indexPieceLength ; count++){
const length = Math.min(sixteenKb, indexPieceLength - offset)
this.sendPieceRequest(pieceIndex, offset, length, client)
requestedBlocks.push(this.waitForRequestedPiece(client))
offset += sixteenKb
}
const responses = await Promise.all(requestedBlocks)
for (const {pieceIndex, offset, blockData} of responses){
piece[offset] = blockData
}
}
const pieceHashes = this.torrent.getPieces()
const hash = pieceHashes.slice(pieceIndex * 40, pieceIndex * 40 + 40)
const recievedHash = crypto
.createHash("sha1")
.update(piece)
.digest("hex")
if (recievedHash !== hash) {
throw new Error('Piece Hash mismatch')
}
fs.writeFileSync(outFile, piece)
}
finally {
client.end()
client.destroy()
}
// console.log(piece.toString("hex"))
}