-
Notifications
You must be signed in to change notification settings - Fork 87
/
pieces_manager.py
113 lines (88 loc) · 3.71 KB
/
pieces_manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
__author__ = 'alexisgallepe'
import piece
import bitstring
import logging
from pubsub import pub
class PiecesManager(object):
def __init__(self, torrent):
self.torrent = torrent
self.number_of_pieces = int(torrent.number_of_pieces)
self.bitfield = bitstring.BitArray(self.number_of_pieces)
self.pieces = self._generate_pieces()
self.files = self._load_files()
self.complete_pieces = 0
for file in self.files:
id_piece = file['idPiece']
self.pieces[id_piece].files.append(file)
# events
pub.subscribe(self.receive_block_piece, 'PiecesManager.Piece')
pub.subscribe(self.update_bitfield, 'PiecesManager.PieceCompleted')
def update_bitfield(self, piece_index):
self.bitfield[piece_index] = 1
def receive_block_piece(self, piece):
piece_index, piece_offset, piece_data = piece
if self.pieces[piece_index].is_full:
return
self.pieces[piece_index].set_block(piece_offset, piece_data)
if self.pieces[piece_index].are_all_blocks_full():
if self.pieces[piece_index].set_to_full():
self.complete_pieces +=1
def get_block(self, piece_index, block_offset, block_length):
for piece in self.pieces:
if piece_index == piece.piece_index:
if piece.is_full:
return piece.get_block(block_offset, block_length)
else:
break
return None
def all_pieces_completed(self):
for piece in self.pieces:
if not piece.is_full:
return False
return True
def _generate_pieces(self):
pieces = []
last_piece = self.number_of_pieces - 1
for i in range(self.number_of_pieces):
start = i * 20
end = start + 20
if i == last_piece:
piece_length = self.torrent.total_length - (self.number_of_pieces - 1) * self.torrent.piece_length
pieces.append(piece.Piece(i, piece_length, self.torrent.pieces[start:end]))
else:
pieces.append(piece.Piece(i, self.torrent.piece_length, self.torrent.pieces[start:end]))
return pieces
def _load_files(self):
files = []
piece_offset = 0
piece_size_used = 0
for f in self.torrent.file_names:
current_size_file = f["length"]
file_offset = 0
while current_size_file > 0:
id_piece = int(piece_offset / self.torrent.piece_length)
piece_size = self.pieces[id_piece].piece_size - piece_size_used
if current_size_file - piece_size < 0:
file = {"length": current_size_file,
"idPiece": id_piece,
"fileOffset": file_offset,
"pieceOffset": piece_size_used,
"path": f["path"]
}
piece_offset += current_size_file
file_offset += current_size_file
piece_size_used += current_size_file
current_size_file = 0
else:
current_size_file -= piece_size
file = {"length": piece_size,
"idPiece": id_piece,
"fileOffset": file_offset,
"pieceOffset": piece_size_used,
"path": f["path"]
}
piece_offset += piece_size
file_offset += piece_size
piece_size_used = 0
files.append(file)
return files