def torrent(self): while not self.shutdown: self.pieces_left = len([m for m in self.pieces if not m['have']]) self.update_peers(self.query_trackers()) # Check whether we still have pieces left to send if not self.pieces_left: sys.stdout.write("\nDownload completed, cleaning up...\n") sys.exit(0) for peer_index, peer in enumerate(self.peers): # Process requests # TODO: Work on strategy for pieces that need be requested multiple times if peer.can_request(): for piece_index, piece in [(n, m) for (n, m) in enumerate(self.pieces) if not m['have']]: if peer.can_request() and peer.has_piece(piece_index) and not piece['requested']: peer.request_piece(piece_index, piece.get('size', self.piece_size)) piece['requested'] = True piece['attempts'] += 1 # Process completed pieces if peer.has_complete_pieces(): sys.stdout.write("\r%s/%s ({0:.2f}%%) pieces downloaded. Rate: %s/s". format((len(self.pieces) - self.pieces_left)/len(self.pieces)*100) % (len(self.pieces) - self.pieces_left, len(self.pieces), strmanip.parse_filesize(self.downloaded/(time.time() - self.runtime), 1000))) sys.stdout.flush() for piece in peer.complete_pieces(): if self.check_piece(piece['index'], piece['data']): self.write_piece(piece['index'], piece['data']) else: self.log.warn("Piece hash FAILED. Index: %s" % piece['index']) self.pieces[piece['index']]['requested'] = False sys.exit(0) Peer.loop() print("Exiting BitClient") sys.exit(1)
def map_pieces(self, current_map): '''Given the pieces string, map them 20-byte sized chunks The piece map contains a list of dictionaries (one per piece) each containing the keys: hash | have | requested | priority | attempts''' piece_length = 20 # the hash is 20 bytes long if isinstance(current_map, str): current_map = current_map.encode("latin-1") self.pieces = [{ "hash": current_map[i:i + piece_length], "have": False, "requested": False, "priority": 0, "attempts": 0 } for i in range(0, len(current_map), piece_length)] calc_total = len(self.pieces) * self.piece_size overage = calc_total - self.total_size if overage: self.pieces[-1]['size'] = self.piece_size - overage calc_total = calc_total - overage if calc_total != self.total_size: self.log.critical( "The pieces for the torrent were incorrectly mapped") sys.exit(0) self.log.debug("Attempting to download: %s\t%s" \ % (calc_total, strmanip.parse_filesize(calc_total, 1000))) self.update_map()
def torrent(self): while not self.shutdown: self.pieces_left = len([m for m in self.pieces if not m['have']]) self.update_peers(self.query_trackers()) # Check whether we still have pieces left to send if not self.pieces_left: sys.stdout.write("\nDownload completed, cleaning up...\n") sys.exit(0) for peer_index, peer in enumerate(self.peers): # Process requests # TODO: Work on strategy for pieces that need be requested multiple times if peer.can_request(): for piece_index, piece in [ (n, m) for (n, m) in enumerate(self.pieces) if not m['have'] ]: if peer.can_request() and peer.has_piece( piece_index) and not piece['requested']: peer.request_piece( piece_index, piece.get('size', self.piece_size)) piece['requested'] = True piece['attempts'] += 1 # Process completed pieces if peer.has_complete_pieces(): sys.stdout.write( "\r%s/%s ({0:.2f}%%) pieces downloaded. Rate: %s/s". format((len(self.pieces) - self.pieces_left) / len(self.pieces) * 100) % (len(self.pieces) - self.pieces_left, len(self.pieces), strmanip.parse_filesize( self.downloaded / (time.time() - self.runtime), 1000))) sys.stdout.flush() for piece in peer.complete_pieces(): if self.check_piece(piece['index'], piece['data']): self.write_piece(piece['index'], piece['data']) else: self.log.warn("Piece hash FAILED. Index: %s" % piece['index']) self.pieces[piece['index']]['requested'] = False sys.exit(0) Peer.loop() print("Exiting BitClient") sys.exit(1)
def map_pieces(self, current_map): '''Given the pieces string, map them 20-byte sized chunks The piece map contains a list of dictionaries (one per piece) each containing the keys: hash | have | requested | priority | attempts''' piece_length = 20 # the hash is 20 bytes long if isinstance(current_map, str): current_map = current_map.encode("latin-1") self.pieces = [{"hash":current_map[i:i+piece_length], "have": False, "requested": False, "priority": 0, "attempts": 0} for i in range(0, len(current_map), piece_length)] calc_total = len(self.pieces) * self.piece_size overage = calc_total - self.total_size if overage: self.pieces[-1]['size'] = self.piece_size - overage calc_total = calc_total - overage if calc_total != self.total_size: self.log.critical("The pieces for the torrent were incorrectly mapped") sys.exit(0) self.log.debug("Attempting to download: %s\t%s" \ % (calc_total, strmanip.parse_filesize(calc_total, 1000))) self.update_map()