Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
36 kaklik 1
# Written by Bram Cohen
2
# see LICENSE.txt for license information
3
 
4
from BitTornado.CurrentRateMeasure import Measure
5
 
6
try:
7
    True
8
except:
9
    True = 1
10
    False = 0
11
 
12
class Upload:
13
    def __init__(self, connection, ratelimiter, totalup, choker, storage,
14
                 picker, config):
15
        self.connection = connection
16
        self.ratelimiter = ratelimiter
17
        self.totalup = totalup
18
        self.choker = choker
19
        self.storage = storage
20
        self.picker = picker
21
        self.config = config
22
        self.max_slice_length = config['max_slice_length']
23
        self.choked = True
24
        self.cleared = True
25
        self.interested = False
26
        self.super_seeding = False
27
        self.buffer = []
28
        self.measure = Measure(config['max_rate_period'], config['upload_rate_fudge'])
29
        self.was_ever_interested = False
30
        if storage.get_amount_left() == 0:
31
            if choker.super_seed:
32
                self.super_seeding = True   # flag, and don't send bitfield
33
                self.seed_have_list = []    # set from piecepicker
34
                self.skipped_count = 0
35
            else:
36
                if config['breakup_seed_bitfield']:
37
                    bitfield, msgs = storage.get_have_list_cloaked()
38
                    connection.send_bitfield(bitfield)
39
                    for have in msgs:
40
                        connection.send_have(have)
41
                else:
42
                    connection.send_bitfield(storage.get_have_list())
43
        else:
44
            if storage.do_I_have_anything():
45
                connection.send_bitfield(storage.get_have_list())
46
        self.piecedl = None
47
        self.piecebuf = None
48
 
49
    def got_not_interested(self):
50
        if self.interested:
51
            self.interested = False
52
            del self.buffer[:]
53
            self.piecedl = None
54
            if self.piecebuf:
55
                self.piecebuf.release()
56
            self.piecebuf = None
57
            self.choker.not_interested(self.connection)
58
 
59
    def got_interested(self):
60
        if not self.interested:
61
            self.interested = True
62
            self.was_ever_interested = True
63
            self.choker.interested(self.connection)
64
 
65
    def get_upload_chunk(self):
66
        if self.choked or not self.buffer:
67
            return None
68
        index, begin, length = self.buffer.pop(0)
69
        if self.config['buffer_reads']:
70
            if index != self.piecedl:
71
                if self.piecebuf:
72
                    self.piecebuf.release()
73
                self.piecedl = index
74
                self.piecebuf = self.storage.get_piece(index, 0, -1)
75
            try:
76
                piece = self.piecebuf[begin:begin+length]
77
                assert len(piece) == length
78
            except:     # fails if storage.get_piece returns None or if out of range
79
                self.connection.close()
80
                return None
81
        else:
82
            if self.piecebuf:
83
                self.piecebuf.release()
84
                self.piecedl = None
85
            piece = self.storage.get_piece(index, begin, length)
86
            if piece is None:
87
                self.connection.close()
88
                return None
89
        self.measure.update_rate(len(piece))
90
        self.totalup.update_rate(len(piece))
91
        return (index, begin, piece)
92
 
93
    def got_request(self, index, begin, length):
94
        if ( (self.super_seeding and not index in self.seed_have_list)
95
                   or not self.interested or length > self.max_slice_length ):
96
            self.connection.close()
97
            return
98
        if not self.cleared:
99
            self.buffer.append((index, begin, length))
100
        if not self.choked and self.connection.next_upload is None:
101
                self.ratelimiter.queue(self.connection)
102
 
103
 
104
    def got_cancel(self, index, begin, length):
105
        try:
106
            self.buffer.remove((index, begin, length))
107
        except ValueError:
108
            pass
109
 
110
    def choke(self):
111
        if not self.choked:
112
            self.choked = True
113
            self.connection.send_choke()
114
        self.piecedl = None
115
        if self.piecebuf:
116
            self.piecebuf.release()
117
            self.piecebuf = None
118
 
119
    def choke_sent(self):
120
        del self.buffer[:]
121
        self.cleared = True
122
 
123
    def unchoke(self):
124
        if self.choked:
125
            self.choked = False
126
            self.cleared = False
127
            self.connection.send_unchoke()
128
 
129
    def disconnected(self):
130
        if self.piecebuf:
131
            self.piecebuf.release()
132
            self.piecebuf = None
133
 
134
    def is_choked(self):
135
        return self.choked
136
 
137
    def is_interested(self):
138
        return self.interested
139
 
140
    def has_queries(self):
141
        return not self.choked and len(self.buffer) > 0
142
 
143
    def get_rate(self):
144
        return self.measure.get_rate()
145