# Written by Bram Cohen # see LICENSE.txt for license information from cStringIO import StringIO from urllib import quote from threading import Event try: True except: True = 1 False = 0 class DownloaderFeedback: def __init__(self, choker, httpdl, add_task, upfunc, downfunc, ratemeasure, leftfunc, file_length, finflag, sp, statistics, statusfunc = None, interval = None): self.choker = choker self.httpdl = httpdl self.add_task = add_task self.upfunc = upfunc self.downfunc = downfunc self.ratemeasure = ratemeasure self.leftfunc = leftfunc self.file_length = file_length self.finflag = finflag self.sp = sp self.statistics = statistics self.lastids = [] self.spewdata = None self.doneprocessing = Event() self.doneprocessing.set() if statusfunc: self.autodisplay(statusfunc, interval) def _rotate(self): cs = self.choker.connections for id in self.lastids: for i in xrange(len(cs)): if cs[i].get_id() == id: return cs[i:] + cs[:i] return cs def spews(self): l = [] cs = self._rotate() self.lastids = [c.get_id() for c in cs] for c in cs: a = {} a['id'] = c.get_readable_id() a['ip'] = c.get_ip() a['optimistic'] = (c is self.choker.connections[0]) if c.is_locally_initiated(): a['direction'] = 'L' else: a['direction'] = 'R' u = c.get_upload() a['uprate'] = int(u.measure.get_rate()) a['uinterested'] = u.is_interested() a['uchoked'] = u.is_choked() d = c.get_download() a['downrate'] = int(d.measure.get_rate()) a['dinterested'] = d.is_interested() a['dchoked'] = d.is_choked() a['snubbed'] = d.is_snubbed() a['utotal'] = d.connection.upload.measure.get_total() a['dtotal'] = d.connection.download.measure.get_total() if len(d.connection.download.have) > 0: a['completed'] = float(len(d.connection.download.have)-d.connection.download.have.numfalse)/float(len(d.connection.download.have)) else: a['completed'] = 1.0 a['speed'] = d.connection.download.peermeasure.get_rate() l.append(a) for dl in self.httpdl.get_downloads(): if dl.goodseed: a = {} a['id'] = 'http seed' a['ip'] = dl.baseurl a['optimistic'] = False a['direction'] = 'L' a['uprate'] = 0 a['uinterested'] = False a['uchoked'] = False a['downrate'] = int(dl.measure.get_rate()) a['dinterested'] = True a['dchoked'] = not dl.active a['snubbed'] = not dl.active a['utotal'] = None a['dtotal'] = dl.measure.get_total() a['completed'] = 1.0 a['speed'] = None l.append(a) return l def gather(self, displayfunc = None): s = {'stats': self.statistics.update()} if self.sp.isSet(): s['spew'] = self.spews() else: s['spew'] = None s['up'] = self.upfunc() if self.finflag.isSet(): s['done'] = self.file_length return s s['down'] = self.downfunc() obtained, desired = self.leftfunc() s['done'] = obtained s['wanted'] = desired if desired > 0: s['frac'] = float(obtained)/desired else: s['frac'] = 1.0 if desired == obtained: s['time'] = 0 else: s['time'] = self.ratemeasure.get_time_left(desired-obtained) return s def display(self, displayfunc): if not self.doneprocessing.isSet(): return self.doneprocessing.clear() stats = self.gather() if self.finflag.isSet(): displayfunc(dpflag = self.doneprocessing, upRate = stats['up'], statistics = stats['stats'], spew = stats['spew']) elif stats['time'] is not None: displayfunc(dpflag = self.doneprocessing, fractionDone = stats['frac'], sizeDone = stats['done'], downRate = stats['down'], upRate = stats['up'], statistics = stats['stats'], spew = stats['spew'], timeEst = stats['time']) else: displayfunc(dpflag = self.doneprocessing, fractionDone = stats['frac'], sizeDone = stats['done'], downRate = stats['down'], upRate = stats['up'], statistics = stats['stats'], spew = stats['spew']) def autodisplay(self, displayfunc, interval): self.displayfunc = displayfunc self.interval = interval self._autodisplay() def _autodisplay(self): self.add_task(self._autodisplay, self.interval) self.display(self.displayfunc)