90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
import torrent_parser as tp
|
|
import threading
|
|
from math import ceil
|
|
|
|
BUFFER_SIZE = 10 * 1024 * 1024
|
|
|
|
class Cron(object):
|
|
alive = False
|
|
def __init__(self, interval, func, *a, **kw):
|
|
self.interval = interval
|
|
self.func = func
|
|
self.a = a
|
|
self.kw = kw
|
|
self.ticker = threading.Event()
|
|
def start(self):
|
|
self.t = threading.Thread(target=self.run)
|
|
self.alive = True
|
|
self.t.start()
|
|
def run(self):
|
|
while self.alive and not self.ticker.wait(self.interval):
|
|
self.func(*self.a, **self.kw)
|
|
def stop(self):
|
|
self.alive = False
|
|
|
|
class Buffer(object):
|
|
def __init__(self, piece_size):
|
|
self.buf_reset_pending = False
|
|
self.buf_changed = threading.Event()
|
|
self.size = ceil(BUFFER_SIZE / piece_size)
|
|
self.buf = []
|
|
def buf_changed_event(self):
|
|
self.buf_changed.set()
|
|
self.buf_changed.clear()
|
|
def put(self, piece):
|
|
if not self.buf_reset_pending:
|
|
self.buf.append(piece)
|
|
self.buf_changed_event()
|
|
return True
|
|
else:
|
|
return False
|
|
def get(self):
|
|
if not self.buf_reset_pending:
|
|
if len(self.buf):
|
|
return self.buf.pop(0)
|
|
return None
|
|
def reset(self):
|
|
self.buf_reset_pending = True
|
|
self.buf = []
|
|
self.buf_reset_pending = False
|
|
self.buf_changed_event()
|
|
def pieces(self):
|
|
if not self.buf_reset_pending:
|
|
return list(map(lambda x: (x.index, x.hash), self.buf))
|
|
else:
|
|
return []
|
|
|
|
class Piece(object):
|
|
def __init__(self, p_index, p_hash, payload):
|
|
self.index = p_index
|
|
self.hash = p_hash
|
|
self.payload = payload
|
|
|
|
class Pyrrent(object):
|
|
multifile = False
|
|
def __init__(self, filepath):
|
|
self.data = tp.parse_torrent_file(filepath)
|
|
self.piece_length = self.data['info']['piece length']
|
|
self.buffer = Buffer(self.piece_length)
|
|
self.pieces = self.data['info']['pieces']
|
|
if 'files' in self.data['info'].keys():
|
|
self.multifile = True
|
|
if not self.multifile:
|
|
self.file_addresses = [(0, self.piece_length)]
|
|
else:
|
|
self.file_addresses = []
|
|
addr_ptr = 0
|
|
for length in map(lambda x: x['length'], self.data['info']['files']):
|
|
next_at = addr_ptr + length
|
|
self.file_addresses.append((addr_ptr, next_at))
|
|
addr_ptr += length
|
|
def piece_range(self, f_index):
|
|
start, next_at = self.file_addresses[f_index]
|
|
start_piece = start // self.piece_length
|
|
start_byte = start % self.piece_length
|
|
tail = next_at % self.piece_length
|
|
end_piece = next_at // self.piece_length - int(not bool(tail))
|
|
end_byte = self.piece_length if not tail else tail
|
|
return [(start_piece, start_byte),(end_piece, end_byte)]
|
|
|