📄 choker.py
字号:
# Written by Bram Cohen# see LICENSE.txt for license informationfrom random import randrange, shufflefrom time import timetrue = 1false = 0class Choker: def __init__(self, config, schedule, picker, done = lambda: false): self.config = config self.schedule = schedule self.picker = picker self.connections = [] self.last_preferred = 0 self.last_round_robin = time() self.done = done self.super_seed = false schedule(self._round_robin, 5) def _round_robin(self): self.schedule(self._round_robin, 5) if self.super_seed: cons = range(len(self.connections)) to_close = [] count = self.config['min_uploads']-self.last_preferred if count > 0: # optimization shuffle(cons) for c in cons: i = self.picker.next_have(self.connections[c], count > 0) if i is None: continue if i < 0: to_close.append(self.connections[c]) continue self.connections[c].send_have(i) count -= 1 for c in to_close: c.close() if self.last_round_robin + self.config['round_robin_period'] < time(): self.last_round_robin = time() for i in xrange( min(len(self.connections),self.config['min_uploads']), len(self.connections) ): c = self.connections[i] u = c.get_upload() if u.is_choked() and u.is_interested(): self.connections = self.connections[i:] + self.connections[:i] break self._rechoke() def _snubbed(self, c): if self.done(): return false return c.get_download().is_snubbed() def _rate(self, c): if self.done(): return c.get_upload().get_rate() else: return c.get_download().get_rate() def _rechoke(self): preferred = [] for c in self.connections: if not self._snubbed(c) and c.get_upload().is_interested(): preferred.append((-self._rate(c), c)) self.last_preferred = len(preferred) preferred.sort() del preferred[(self.config['max_uploads']) - 1:] preferred = [x[1] for x in preferred] count = len(preferred) hit = false for c in self.connections: u = c.get_upload() if c in preferred: u.unchoke() else: if count < self.config['min_uploads'] or not hit: u.unchoke() if u.is_interested(): count += 1 hit = true else: u.choke() def connection_made(self, connection, p = None): if p is None: p = randrange(-2, len(self.connections) + 1) self.connections.insert(max(p, 0), connection) self._rechoke() def connection_lost(self, connection): self.connections.remove(connection) try: self.strangled.remove(connection) except: pass self.picker.lost_peer(connection) if connection.get_upload().is_interested() and not connection.get_upload().is_choked(): self._rechoke() def interested(self, connection): if not connection.get_upload().is_choked(): self._rechoke() def not_interested(self, connection): if not connection.get_upload().is_choked(): self._rechoke() def set_super_seed(self): self.super_seed = true while self.connections: # close all connections self.connections[0].close()class DummyScheduler: def __init__(self): self.s = [] def __call__(self, func, delay): self.s.append((func, delay))class DummyConnection: def __init__(self, v = 0): self.u = DummyUploader() self.d = DummyDownloader(self) self.v = v def get_upload(self): return self.u def get_download(self): return self.dclass DummyDownloader: def __init__(self, c): self.s = false self.c = c def is_snubbed(self): return self.s def get_rate(self): return self.c.vclass DummyUploader: def __init__(self): self.i = false self.c = true def choke(self): if not self.c: self.c = true def unchoke(self): if self.c: self.c = false def is_choked(self): return self.c def is_interested(self): return self.idef test_round_robin_with_no_downloads(): s = DummyScheduler() Choker(2, s) assert len(s.s) == 1 assert s.s[0][1] == 10 s.s[0][0]() del s.s[0] assert len(s.s) == 1 assert s.s[0][1] == 10 s.s[0][0]() del s.s[0] s.s[0][0]() del s.s[0] s.s[0][0]() del s.s[0]def test_resort(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection() c2 = DummyConnection(1) c3 = DummyConnection(2) c4 = DummyConnection(3) c2.u.i = true c3.u.i = true choker.connection_made(c1) assert not c1.u.c choker.connection_made(c2, 1) assert not c1.u.c assert not c2.u.c choker.connection_made(c3, 1) assert not c1.u.c assert c2.u.c assert not c3.u.c c2.v = 2 c3.v = 1 choker.connection_made(c4, 1) assert not c1.u.c assert c2.u.c assert not c3.u.c assert not c4.u.c choker.connection_lost(c4) assert not c1.u.c assert c2.u.c assert not c3.u.c s.s[0][0]() assert not c1.u.c assert c2.u.c assert not c3.u.cdef test_interest(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection() c2 = DummyConnection(1) c3 = DummyConnection(2) c2.u.i = true c3.u.i = true choker.connection_made(c1) assert not c1.u.c choker.connection_made(c2, 1) assert not c1.u.c assert not c2.u.c choker.connection_made(c3, 1) assert not c1.u.c assert c2.u.c assert not c3.u.c c3.u.i = false choker.not_interested(c3) assert not c1.u.c assert not c2.u.c assert not c3.u.c c3.u.i = true choker.interested(c3) assert not c1.u.c assert c2.u.c assert not c3.u.c choker.connection_lost(c3) assert not c1.u.c assert not c2.u.cdef test_robin_interest(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection(0) c2 = DummyConnection(1) c1.u.i = true choker.connection_made(c2) assert not c2.u.c choker.connection_made(c1, 0) assert not c1.u.c assert c2.u.c c1.u.i = false choker.not_interested(c1) assert not c1.u.c assert not c2.u.c c1.u.i = true choker.interested(c1) assert not c1.u.c assert c2.u.c choker.connection_lost(c1) assert not c2.u.cdef test_skip_not_interested(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection(0) c2 = DummyConnection(1) c3 = DummyConnection(2) c1.u.i = true c3.u.i = true choker.connection_made(c2) assert not c2.u.c choker.connection_made(c1, 0) assert not c1.u.c assert c2.u.c choker.connection_made(c3, 2) assert not c1.u.c assert c2.u.c assert c3.u.c f = s.s[0][0] f() assert not c1.u.c assert c2.u.c assert c3.u.c f() assert not c1.u.c assert c2.u.c assert c3.u.c f() assert c1.u.c assert c2.u.c assert not c3.u.cdef test_connection_lost_no_interrupt(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection(0) c2 = DummyConnection(1) c3 = DummyConnection(2) c1.u.i = true c2.u.i = true c3.u.i = true choker.connection_made(c1) choker.connection_made(c2, 1) choker.connection_made(c3, 2) f = s.s[0][0] f() assert not c1.u.c assert c2.u.c assert c3.u.c f() assert not c1.u.c assert c2.u.c assert c3.u.c f() assert c1.u.c assert not c2.u.c assert c3.u.c f() assert c1.u.c assert not c2.u.c assert c3.u.c f() assert c1.u.c assert not c2.u.c assert c3.u.c choker.connection_lost(c3) assert c1.u.c assert not c2.u.c f() assert not c1.u.c assert c2.u.c choker.connection_lost(c2) assert not c1.u.cdef test_connection_made_no_interrupt(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection(0) c2 = DummyConnection(1) c3 = DummyConnection(2) c1.u.i = true c2.u.i = true c3.u.i = true choker.connection_made(c1) choker.connection_made(c2, 1) f = s.s[0][0] assert not c1.u.c assert c2.u.c f() assert not c1.u.c assert c2.u.c f() assert not c1.u.c assert c2.u.c choker.connection_made(c3, 1) assert not c1.u.c assert c2.u.c assert c3.u.c f() assert c1.u.c assert c2.u.c assert not c3.u.cdef test_round_robin(): s = DummyScheduler() choker = Choker(1, s) c1 = DummyConnection(0) c2 = DummyConnection(1) c1.u.i = true c2.u.i = true choker.connection_made(c1) choker.connection_made(c2, 1) f = s.s[0][0] assert not c1.u.c assert c2.u.c f() assert not c1.u.c assert c2.u.c f() assert not c1.u.c assert c2.u.c f() assert c1.u.c assert not c2.u.c f() assert c1.u.c assert not c2.u.c f() assert c1.u.c assert not c2.u.c f() assert not c1.u.c assert c2.u.c def test_multi(): s = DummyScheduler() choker = Choker(4, s) c1 = DummyConnection(0) c2 = DummyConnection(0) c3 = DummyConnection(0) c4 = DummyConnection(8) c5 = DummyConnection(0) c6 = DummyConnection(0) c7 = DummyConnection(6) c8 = DummyConnection(0) c9 = DummyConnection(9) c10 = DummyConnection(7) c11 = DummyConnection(10) choker.connection_made(c1, 0) choker.connection_made(c2, 1) choker.connection_made(c3, 2) choker.connection_made(c4, 3) choker.connection_made(c5, 4) choker.connection_made(c6, 5) choker.connection_made(c7, 6) choker.connection_made(c8, 7) choker.connection_made(c9, 8) choker.connection_made(c10, 9) choker.connection_made(c11, 10) c2.u.i = true c4.u.i = true c6.u.i = true c8.u.i = true c10.u.i = true c2.d.s = true c6.d.s = true c8.d.s = true s.s[0][0]() assert not c1.u.c assert not c2.u.c assert not c3.u.c assert not c4.u.c assert not c5.u.c assert not c6.u.c assert c7.u.c assert c8.u.c assert c9.u.c assert not c10.u.c assert c11.u.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -