📄 downloader.py
字号:
if self.downloader.storage.am_I_complete() and have.complete(): if self.downloader.super_seeding: self.connection.send_bitfield(have.tostring()) # be nice, show you're a seed too self.connection.close() self.downloader.add_disconnected_seed(self.connection.get_readable_id()) return False self.have = have if have.complete(): self.downloader.picker.got_seed() else: for i in xrange(len(have)): if have[i]: self.downloader.picker.got_have(i) if self.downloader.endgamemode and not self.downloader.paused: for piece, begin, length in self.downloader.all_requests: if self.have[piece]: self.send_interested() break else: self._check_interests() return have.complete() def get_rate(self): return self.measure.get_rate() def is_snubbed(self): if ( self.interested and not self.choked and clock() - self.last2 > self.downloader.snub_time ): for index, begin, length in self.active_requests: self.connection.send_cancel(index, begin, length) self.got_choke() # treat it just like a choke return clock() - self.last > self.downloader.snub_timeclass Downloader: def __init__(self, storage, picker, backlog, max_rate_period, numpieces, chunksize, measurefunc, snub_time, kickbans_ok, kickfunc, banfunc): self.storage = storage self.picker = picker self.backlog = backlog self.max_rate_period = max_rate_period self.measurefunc = measurefunc self.totalmeasure = Measure(max_rate_period*storage.piece_length/storage.request_size) self.numpieces = numpieces self.chunksize = chunksize self.snub_time = snub_time self.kickfunc = kickfunc self.banfunc = banfunc self.disconnectedseeds = {} self.downloads = [] self.perip = {} self.gotbaddata = {} self.kicked = {} self.banned = {} self.kickbans_ok = kickbans_ok self.kickbans_halted = False self.super_seeding = False self.endgamemode = False self.endgame_queued_pieces = [] self.all_requests = [] self.discarded = 0L# self.download_rate = 25000 # 25K/s test rate self.download_rate = 0 self.bytes_requested = 0 self.last_time = clock() self.queued_out = {} self.requeueing = False self.paused = False def set_download_rate(self, rate): self.download_rate = rate * 1000 self.bytes_requested = 0 def queue_limit(self): if not self.download_rate: return 10e10 # that's a big queue! t = clock() self.bytes_requested -= (t - self.last_time) * self.download_rate self.last_time = t if not self.requeueing and self.queued_out and self.bytes_requested < 0: self.requeueing = True q = self.queued_out.keys() shuffle(q) self.queued_out = {} for d in q: d._request_more() self.requeueing = False if -self.bytes_requested > 5*self.download_rate: self.bytes_requested = -5*self.download_rate return max(int(-self.bytes_requested/self.chunksize),0) def chunk_requested(self, size): self.bytes_requested += size external_data_received = chunk_requested def make_download(self, connection): ip = connection.get_ip() if self.perip.has_key(ip): perip = self.perip[ip] else: perip = self.perip.setdefault(ip, PerIPStats(ip)) perip.peerid = connection.get_readable_id() perip.numconnections += 1 d = SingleDownload(self, connection) perip.lastdownload = d self.downloads.append(d) return d def piece_flunked(self, index): if self.paused: return if self.endgamemode: if self.downloads: while self.storage.do_I_have_requests(index): nb, nl = self.storage.new_request(index) self.all_requests.append((index, nb, nl)) for d in self.downloads: d.fix_download_endgame() return self._reset_endgame() return ds = [d for d in self.downloads if not d.choked] shuffle(ds) for d in ds: d._request_more() ds = [d for d in self.downloads if not d.interested and d.have[index]] for d in ds: d.example_interest = index d.send_interested() def has_downloaders(self): return len(self.downloads) def lost_peer(self, download): ip = download.ip self.perip[ip].numconnections -= 1 if self.perip[ip].lastdownload == download: self.perip[ip].lastdownload = None self.downloads.remove(download) if self.endgamemode and not self.downloads: # all peers gone self._reset_endgame() def _reset_endgame(self): self.storage.reset_endgame(self.all_requests) self.endgamemode = False self.all_requests = [] self.endgame_queued_pieces = [] def add_disconnected_seed(self, id):# if not self.disconnectedseeds.has_key(id):# self.picker.seed_seen_recently() self.disconnectedseeds[id]=clock()# def expire_disconnected_seeds(self): def num_disconnected_seeds(self): # first expire old ones expired = [] for id,t in self.disconnectedseeds.items(): if clock() - t > EXPIRE_TIME: #Expire old seeds after so long expired.append(id) for id in expired:# self.picker.seed_disappeared() del self.disconnectedseeds[id] return len(self.disconnectedseeds) # if this isn't called by a stats-gathering function # it should be scheduled to run every minute or two. def _check_kicks_ok(self): if len(self.gotbaddata) > 10: self.kickbans_ok = False self.kickbans_halted = True return self.kickbans_ok and len(self.downloads) > 2 def try_kick(self, download): if self._check_kicks_ok(): download.guard.download = None ip = download.ip id = download.connection.get_readable_id() self.kicked[ip] = id self.perip[ip].peerid = id self.kickfunc(download.connection) def try_ban(self, ip): if self._check_kicks_ok(): self.banfunc(ip) self.banned[ip] = self.perip[ip].peerid if self.kicked.has_key(ip): del self.kicked[ip] def set_super_seed(self): self.super_seeding = True def check_complete(self, index): if self.endgamemode and not self.all_requests: self.endgamemode = False if self.endgame_queued_pieces and not self.endgamemode: self.requeue_piece_download() if self.storage.am_I_complete(): assert not self.all_requests assert not self.endgamemode for d in [i for i in self.downloads if i.have.complete()]: d.connection.send_have(index) # be nice, tell the other seed you completed self.add_disconnected_seed(d.connection.get_readable_id()) d.connection.close() return True return False def too_many_partials(self): return len(self.storage.dirty) > (len(self.downloads)/2) def cancel_piece_download(self, pieces): if self.endgamemode: if self.endgame_queued_pieces: for piece in pieces: try: self.endgame_queued_pieces.remove(piece) except: pass new_all_requests = [] for index, nb, nl in self.all_requests: if index in pieces: self.storage.request_lost(index, nb, nl) else: new_all_requests.append((index, nb, nl)) self.all_requests = new_all_requests for d in self.downloads: hit = False for index, nb, nl in d.active_requests: if index in pieces: hit = True d.connection.send_cancel(index, nb, nl) if not self.endgamemode: self.storage.request_lost(index, nb, nl) if hit: d.active_requests = [ r for r in d.active_requests if r[0] not in pieces ] d._request_more() if not self.endgamemode and d.choked: d._check_interests() def requeue_piece_download(self, pieces = []): if self.endgame_queued_pieces: for piece in pieces: if not piece in self.endgame_queued_pieces: self.endgame_queued_pieces.append(piece) pieces = self.endgame_queued_pieces if self.endgamemode: if self.all_requests: self.endgame_queued_pieces = pieces return self.endgamemode = False self.endgame_queued_pieces = None ds = [d for d in self.downloads] shuffle(ds) for d in ds: if d.choked: d._check_interests() else: d._request_more() def start_endgame(self): assert not self.endgamemode self.endgamemode = True assert not self.all_requests for d in self.downloads: if d.active_requests: assert d.interested and not d.choked for request in d.active_requests: assert not request in self.all_requests self.all_requests.append(request) for d in self.downloads: d.fix_download_endgame() def pause(self, flag): self.paused = flag if flag: for d in self.downloads: for index, begin, length in d.active_requests: d.connection.send_cancel(index, begin, length) d._letgo() d.send_not_interested() if self.endgamemode: self._reset_endgame() else: shuffle(self.downloads) for d in self.downloads: d._check_interests() if d.interested and not d.choked: d._request_more()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -