140 lines
5.3 KiB
Python
Executable File
140 lines
5.3 KiB
Python
Executable File
# The contents of this file are subject to the BitTorrent Open Source License
|
|
# Version 1.1 (the License). You may not copy or use this file, in either
|
|
# source code or executable form, except in compliance with the License. You
|
|
# may obtain a copy of the License at http://www.bittorrent.com/license/.
|
|
#
|
|
# Software distributed under the License is distributed on an AS IS basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
# for the specific language governing rights and limitations under the
|
|
# License.
|
|
|
|
# Written by Bram Cohen, Uoti Urpala
|
|
|
|
from __future__ import division
|
|
|
|
|
|
class DownloaderFeedback(object):
|
|
|
|
def __init__(self, choker, upfunc, upfunc2, downfunc, uptotal, downtotal,
|
|
remainingfunc, leftfunc, file_length, finflag, downloader,
|
|
files, ever_got_incoming, rerequester):
|
|
self.downloader = downloader
|
|
self.picker = downloader.picker
|
|
self.storage = downloader.storage
|
|
self.choker = choker
|
|
self.upfunc = upfunc
|
|
self.upfunc2 = upfunc2
|
|
self.downfunc = downfunc
|
|
self.uptotal = uptotal
|
|
self.downtotal = downtotal
|
|
self.remainingfunc = remainingfunc
|
|
self.leftfunc = leftfunc
|
|
self.file_length = file_length
|
|
self.finflag = finflag
|
|
self.files = files
|
|
self.ever_got_incoming = ever_got_incoming
|
|
self.rerequester = rerequester
|
|
self.lastids = []
|
|
|
|
def _rotate(self):
|
|
cs = self.choker.connections
|
|
for peerid in self.lastids:
|
|
for i in xrange(len(cs)):
|
|
if cs[i].id == peerid:
|
|
return cs[i:] + cs[:i]
|
|
return cs
|
|
|
|
def collect_spew(self):
|
|
l = [ ]
|
|
cs = self._rotate()
|
|
self.lastids = [c.id for c in cs]
|
|
for c in cs:
|
|
rec = {}
|
|
rec['id'] = c.id
|
|
rec["ip"] = c.ip
|
|
rec["is_optimistic_unchoke"] = (c is self.choker.connections[0])
|
|
if c.locally_initiated:
|
|
rec["initiation"] = "L"
|
|
else:
|
|
rec["initiation"] = "R"
|
|
u = c.upload
|
|
rec["upload"] = (u.measure.get_total(), int(u.measure.get_rate()),
|
|
u.interested, u.choked)
|
|
|
|
d = c.download
|
|
rec["download"] = (d.measure.get_total(),int(d.measure.get_rate()),
|
|
d.interested, d.choked, d.is_snubbed())
|
|
rec['completed'] = 1 - d.have.numfalse / len(d.have)
|
|
rec['speed'] = d.connection.download.peermeasure.get_rate()
|
|
l.append(rec)
|
|
return l
|
|
|
|
def get_statistics(self, spewflag=False, fileflag=False):
|
|
status = {}
|
|
numSeeds = 0
|
|
numPeers = 0
|
|
for d in self.downloader.downloads:
|
|
if d.have.numfalse == 0:
|
|
numSeeds += 1
|
|
else:
|
|
numPeers += 1
|
|
status['numSeeds'] = numSeeds
|
|
status['numPeers'] = numPeers
|
|
status['trackerSeeds'] = self.rerequester.tracker_num_seeds
|
|
status['trackerPeers'] = self.rerequester.tracker_num_peers
|
|
status['upRate'] = self.upfunc()
|
|
status['upRate2'] = self.upfunc2()
|
|
status['upTotal'] = self.uptotal()
|
|
status['ever_got_incoming'] = self.ever_got_incoming()
|
|
missingPieces = 0
|
|
numCopyList = []
|
|
numCopies = 0
|
|
for i in self.picker.crosscount:
|
|
missingPieces += i
|
|
if missingPieces == 0:
|
|
numCopies += 1
|
|
else:
|
|
fraction = 1 - missingPieces / self.picker.numpieces
|
|
numCopyList.append(fraction)
|
|
if fraction == 0 or len(numCopyList) >= 3:
|
|
break
|
|
numCopies -= numSeeds
|
|
if self.picker.numgot == self.picker.numpieces:
|
|
numCopies -= 1
|
|
status['numCopies'] = numCopies
|
|
status['numCopyList'] = numCopyList
|
|
status['discarded'] = self.downloader.discarded_bytes
|
|
status['storage_numcomplete'] = self.storage.stat_numfound + \
|
|
self.storage.stat_numdownloaded
|
|
status['storage_dirty'] = len(self.storage.stat_dirty)
|
|
status['storage_active'] = len(self.storage.stat_active)
|
|
status['storage_new'] = len(self.storage.stat_new)
|
|
status['storage_numflunked'] = self.storage.stat_numflunked
|
|
|
|
if spewflag:
|
|
status['spew'] = self.collect_spew()
|
|
status['bad_peers'] = self.downloader.bad_peers
|
|
if fileflag:
|
|
undl = self.storage.storage.undownloaded
|
|
unal = self.storage.storage.unallocated
|
|
status['files_left'] = [undl[fname] for fname in self.files]
|
|
status['files_allocated'] = [not unal[fn] for fn in self.files]
|
|
if self.finflag.isSet():
|
|
status['downRate'] = 0
|
|
status['downTotal'] = self.downtotal()
|
|
status['fractionDone'] = 1
|
|
return status
|
|
timeEst = self.remainingfunc()
|
|
status['timeEst'] = timeEst
|
|
|
|
if self.file_length > 0:
|
|
fractionDone = 1 - self.leftfunc() / self.file_length
|
|
else:
|
|
fractionDone = 1
|
|
status.update({
|
|
"fractionDone" : fractionDone,
|
|
"downRate" : self.downfunc(),
|
|
"downTotal" : self.downtotal()
|
|
})
|
|
return status
|