Blame | Last modification | View Log | Download
# Written by Bram Cohen# see LICENSE.txt for license informationfrom BitTornado.CurrentRateMeasure import Measuretry:Trueexcept:True = 1False = 0class Upload:def __init__(self, connection, ratelimiter, totalup, choker, storage,picker, config):self.connection = connectionself.ratelimiter = ratelimiterself.totalup = totalupself.choker = chokerself.storage = storageself.picker = pickerself.config = configself.max_slice_length = config['max_slice_length']self.choked = Trueself.cleared = Trueself.interested = Falseself.super_seeding = Falseself.buffer = []self.measure = Measure(config['max_rate_period'], config['upload_rate_fudge'])self.was_ever_interested = Falseif storage.get_amount_left() == 0:if choker.super_seed:self.super_seeding = True # flag, and don't send bitfieldself.seed_have_list = [] # set from piecepickerself.skipped_count = 0else:if config['breakup_seed_bitfield']:bitfield, msgs = storage.get_have_list_cloaked()connection.send_bitfield(bitfield)for have in msgs:connection.send_have(have)else:connection.send_bitfield(storage.get_have_list())else:if storage.do_I_have_anything():connection.send_bitfield(storage.get_have_list())self.piecedl = Noneself.piecebuf = Nonedef got_not_interested(self):if self.interested:self.interested = Falsedel self.buffer[:]self.piecedl = Noneif self.piecebuf:self.piecebuf.release()self.piecebuf = Noneself.choker.not_interested(self.connection)def got_interested(self):if not self.interested:self.interested = Trueself.was_ever_interested = Trueself.choker.interested(self.connection)def get_upload_chunk(self):if self.choked or not self.buffer:return Noneindex, begin, length = self.buffer.pop(0)if self.config['buffer_reads']:if index != self.piecedl:if self.piecebuf:self.piecebuf.release()self.piecedl = indexself.piecebuf = self.storage.get_piece(index, 0, -1)try:piece = self.piecebuf[begin:begin+length]assert len(piece) == lengthexcept: # fails if storage.get_piece returns None or if out of rangeself.connection.close()return Noneelse:if self.piecebuf:self.piecebuf.release()self.piecedl = Nonepiece = self.storage.get_piece(index, begin, length)if piece is None:self.connection.close()return Noneself.measure.update_rate(len(piece))self.totalup.update_rate(len(piece))return (index, begin, piece)def got_request(self, index, begin, length):if ( (self.super_seeding and not index in self.seed_have_list)or not self.interested or length > self.max_slice_length ):self.connection.close()returnif not self.cleared:self.buffer.append((index, begin, length))if not self.choked and self.connection.next_upload is None:self.ratelimiter.queue(self.connection)def got_cancel(self, index, begin, length):try:self.buffer.remove((index, begin, length))except ValueError:passdef choke(self):if not self.choked:self.choked = Trueself.connection.send_choke()self.piecedl = Noneif self.piecebuf:self.piecebuf.release()self.piecebuf = Nonedef choke_sent(self):del self.buffer[:]self.cleared = Truedef unchoke(self):if self.choked:self.choked = Falseself.cleared = Falseself.connection.send_unchoke()def disconnected(self):if self.piecebuf:self.piecebuf.release()self.piecebuf = Nonedef is_choked(self):return self.chokeddef is_interested(self):return self.interesteddef has_queries(self):return not self.choked and len(self.buffer) > 0def get_rate(self):return self.measure.get_rate()