def __init__(self, btm): self.btm = btm self.info_hash = btm.metainfo.info_hash self.active_connection = {} self.downloadSpeedMonitor = SpeedMonitor() self.downloadSpeedMonitor.registerObserver(btm.downloadSpeedMonitor) self.uploadSpeedMonitor = SpeedMonitor() self.uploadSpeedMonitor.registerObserver(btm.uploadSpeedMonitor)
def __init__(self, app, config): self.app = app self.config = config self.metainfo = config.metainfo self.info_hash = self.metainfo.info_hash self.downloadSpeedMonitor = SpeedMonitor(5) self.uploadSpeedMonitor = SpeedMonitor(5) self.my_peer_id = generate_peer_id() self.connectionManager = ConnectionManager(self) self.pieceManager = BTPieceManager(self) if not self.config.trackerless: if len(self.metainfo.announce_list) > 0: self.bttrackerclient = BTTrackerClient(self) else: raise Exception("Need at least one tracker if torrent is "+\ "not trackerless.") self.status = None
class ConnectionManagerBase (IConnectionManager): def __init__(self, btm): self.btm = btm self.info_hash = btm.metainfo.info_hash self.active_connection = {} self.downloadSpeedMonitor = SpeedMonitor() self.downloadSpeedMonitor.registerObserver(btm.downloadSpeedMonitor) self.uploadSpeedMonitor = SpeedMonitor() self.uploadSpeedMonitor.registerObserver(btm.uploadSpeedMonitor) def addActiveConnection(self, peerid, connection): peerid = connection.peer_id self.active_connection[peerid] = connection def removeActiveConnection(self, peerid): if peerid in self.active_connection: del self.active_connection[peerid] def isAlreadyConnected(self, peer_id) : return peer_id in self.active_connection def getConnection(self, peer_id) : return self.active_connection.get(peer_id, None) def broadcastHave(self, idx): for peerid, con in self.active_connection.iteritems(): con.send_have(idx) def redownloadPiece(self, idx): for peerid, con in self.active_connection.iteritems(): con.redownloadPiece(idx) def broadcastCancelPiece(self, idx, begin, length): for peerid, con in self.active_connection.iteritems(): con.send_cancel(idx, begin, length) def start(self): pass def stop(self): pass
def __init__(self, protocol): self.protocol = protocol self.piece_doing = [] self.piece_done = [] self.peer_choke = None self.am_interested = None self.downloadSpeedMonitor = SpeedMonitor() self.task_max_size = 5
def __init__(self, protocol): self.protocol = protocol self.peer_interested = None self.am_choke = None self.uploadSpeedMonitor = SpeedMonitor() self.upload_todo = [] self.upload_doing = [] self.upload_done = [] self.status = None
class BTUpload (object) : # producer interface implementation def __init__(self, protocol): self.protocol = protocol self.peer_interested = None self.am_choke = None self.uploadSpeedMonitor = SpeedMonitor() self.upload_todo = [] self.upload_doing = [] self.upload_done = [] self.status = None def start(self): if self.status == 'started' : return if not self.protocol: return self.btm = self.protocol.factory.btm self.pieceManager = self.btm.pieceManager self.uploadSpeedMonitor.start() self.uploadSpeedMonitor.registerObserver(self.protocol.factory.uploadSpeedMonitor) self.choke(False) self.protocol.transport.registerProducer(self, False) self.status = 'started' def stop(self): if self.status == 'stopped': return self.uploadSpeedMonitor.stop() self.protocol.transport.unregisterProducer() del self.protocol del self.btm del self.pieceManager self.status = 'stopped' def pause(self): pass def resume(self): pass def _interested(self, val): self.peer_interested = bool(val) def _request(self, idx, begin, length): if not self.pieceManager.doIHave(idx): # I don't have return self.upload_todo.append((idx, (begin, length))) # data = self.pieceManager.getPieceData(idx, begin, length) # if data : # self.protocol.send_piece(idx, begin, data) if self.status == 'idle' : self.resumeProducing() def _cancel(self, idx, begin, length): task = idx, (begin, length) if task in self.upload_todo : self.upload_todo.remove(task) def choke(self, val): am_choke = bool(val) if self.am_choke is am_choke : return if am_choke : self.protocol.send_choke() else : self.protocol.send_unchoke() self.am_choke = am_choke def _uploadMonitor(self, _type, data): self.uploadSpeedMonitor.addBytes(len(data)) # called by transport and do write def resumeProducing(self): for i in range(len(self.upload_todo)) : idx, (begin, length) = self.upload_todo[i] data = self.pieceManager.getPieceData(idx, begin, length) if data : self.protocol.send_piece(idx, begin, data) self.status = 'uploading' del self.upload_todo[i] break else: self.status = 'idle' def stopProducing(self): pass
class BTManager (object): def __init__(self, app, config): self.app = app self.config = config self.metainfo = config.metainfo self.info_hash = self.metainfo.info_hash self.downloadSpeedMonitor = SpeedMonitor(5) self.uploadSpeedMonitor = SpeedMonitor(5) self.my_peer_id = generate_peer_id() self.connectionManager = ConnectionManager(self) self.pieceManager = BTPieceManager(self) if not self.config.trackerless: if len(self.metainfo.announce_list) > 0: self.bttrackerclient = BTTrackerClient(self) else: raise Exception("Need at least one tracker if torrent is "+\ "not trackerless.") self.status = None def startDownload(self): self.pieceManager.start() self.connectionManager.start() self.downloadSpeedMonitor.start() self.uploadSpeedMonitor.start() if not self.config.trackerless: self.bttrackerclient.start() self.status = 'running' def stopDownload(self): self.pieceManager.stop() self.connectionManager.stop() self.downloadSpeedMonitor.stop() self.uploadSpeedMonitor.stop() if not self.config.trackerless: self.bttrackerclient.stop() self.status = 'stopped' def get_speed(self): """Returns the speed in kibibit per second (Kibit/s). """ return { "down": self.downloadSpeedMonitor.get_speed(), "up": self.uploadSpeedMonitor.get_speed() } def get_num_connections(self): return { "client": len(self.connectionManager.clientFactory.active_connection), "server": len(self.connectionManager.serverFactory.active_connection)} def add_peers(self, peers): """Adds peers to the torrent for downloading pieces. @param peers list of tuples e.g. [('173.248.194.166', 12005), ('192.166.145.8', 13915)] """ self.connectionManager.clientFactory.updateTrackerPeers(peers) def exit(self): if self.status == 'running' : self.stopDownload() for i in self.__dict__ : del self.__dict__[i]
class BTDownload(object) : task_max_size = 5 def __init__(self, protocol): self.protocol = protocol self.piece_doing = [] self.piece_done = [] self.peer_choke = None self.am_interested = None self.downloadSpeedMonitor = SpeedMonitor() self.task_max_size = 5 def start(self): if not self.protocol: return self.status = 'running' self.btm = self.protocol.factory.btm self.pieceManager = self.btm.pieceManager pm = self.pieceManager self.peer_bitfield = Bitfield(pm.pieces_size) self.downloadSpeedMonitor.start() self.downloadSpeedMonitor.registerObserver(self.protocol.factory.downloadSpeedMonitor) #reactor.callLater(0, self.interested, True) def stop(self): for task in self.piece_doing: self.pieceManager.failedPieceTask(*task) del self.piece_doing[:] self.downloadSpeedMonitor.stop() del self.protocol del self.btm del self.pieceManager self.status = 'stopped' def _choke(self, val): self.peer_choke = bool(val) if val: pass else: self.__pieceRequest() def interested(self, val): # 发送 am_interested = bool(val) if self.am_interested is am_interested : return if am_interested : self.protocol.send_interested() else : self.protocol.send_not_interested() self.am_interested = am_interested def cancel(self, task): idx, (beg, length) = task self.protocol.send_cancel(idx, beg, length) def _downloadMonitor(self, data): self.downloadSpeedMonitor.addBytes(len(data)) def __pieceRequest(self): # 全部接受上次请求的块数据后才能发送新请求, 5分钟超时断连接 if self.am_interested==True and self.peer_choke==False: #if self.am_interested==True : if self.piece_doing : return new_task = self.__getTask() if new_task : self.__sendTaskRequest(new_task) def __getTask(self, size=None): if size is None : size = self.task_max_size pm = self.pieceManager new_task = pm.getMorePieceTask(self.peer_bitfield, size) return new_task @defer.inlineCallbacks def __sendTaskRequest(self, new_task, timeout=None): if not new_task: return if timeout is None: timeout = len(new_task) * 60 for task in new_task : i, (beg, size) = task self.protocol.send_request(i, beg, size) self.piece_doing.append(task) yield sleep(timeout) self.__checkTimeout(new_task) def __checkTimeout(self, task_plan): if self.status == 'stopped' : return #self.transport.loseConnection() set_plan = set(task_plan) set_ing = set(self.piece_doing) set_undo = set_plan & set_ing set_new = set_ing - set_plan task_size = self.task_max_size - len(set_undo) if set_new: task_size += 1 if task_size < 1: task_size = 1 elif task_size > BTDownload.task_max_size : task_size = BTDownload.task_max_size self.task_max_size = task_size if not set_undo: return new_task = self.__getTask(self.task_max_size) for task in set_undo: self.cancel(task) self.piece_doing.remove(task) self.pieceManager.failedPieceTask(*task) if new_task: self.__sendTaskRequest(new_task) def _piece(self, index, beg, piece): # 接收发来的piece task = index, (beg, len(piece)) if task not in self.piece_doing: #log.msg('-->> drop canceled piece: {0}'.format(task)) return self.pieceManager.finishPieceTask(index, (beg, len(piece)), piece) self.piece_doing.remove(task) if len(self.piece_doing) == 0: self.__pieceRequest() def _bitfield(self, data): # 接收 pm = self.pieceManager bf = Bitfield(pm.pieces_size, data) self.peer_bitfield = bf if self.pieceManager.amInterested(bf): self.interested(True) self.__pieceRequest() else: # print self.peer_bitfield # print self.pieceManager.bfNeed # assert False self.interested(False) #print 'interested ', self.am_interested, 'bitfield', bf.any() def _have(self, index): # 接收 self.peer_bitfield[index] = 1 if self.pieceManager.amInterested(index) : self.interested(True) self.__pieceRequest()