76 lines
2.7 KiB
Python
Executable File
76 lines
2.7 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.
|
|
|
|
from BitTorrent.platform import bttime as time
|
|
from BitTorrent.CurrentRateMeasure import Measure
|
|
from const import *
|
|
from random import randrange, shuffle
|
|
from traceback import print_exc
|
|
|
|
class KRateLimiter:
|
|
# special rate limiter that drops entries that have been sitting in the queue for longer than self.age seconds
|
|
# by default we toss anything that has less than 5 seconds to live
|
|
def __init__(self, transport, rate, call_later, rlcount, rate_period, age=(KRPC_TIMEOUT - 5)):
|
|
self.q = []
|
|
self.transport = transport
|
|
self.rate = rate
|
|
self.curr = 0
|
|
self.running = False
|
|
self.age = age
|
|
self.last = 0
|
|
self.call_later = call_later
|
|
self.rlcount = rlcount
|
|
self.measure = Measure(rate_period)
|
|
self.sent=self.dropped=0
|
|
if self.rate == 0:
|
|
self.rate = 1e10
|
|
|
|
def sendto(self, s, i, addr):
|
|
self.q.append((time(), (s, i, addr)))
|
|
if not self.running:
|
|
self.run(check=True)
|
|
|
|
def run(self, check=False):
|
|
t = time()
|
|
self.expire(t)
|
|
self.curr -= (t - self.last) * self.rate
|
|
self.last = t
|
|
if check:
|
|
self.curr = max(self.curr, 0 - self.rate)
|
|
|
|
shuffle(self.q)
|
|
while self.q and self.curr <= 0:
|
|
x, tup = self.q.pop()
|
|
size = len(tup[0])
|
|
self.curr += size
|
|
try:
|
|
self.transport.sendto(*tup)
|
|
self.sent+=1
|
|
self.rlcount(size)
|
|
self.measure.update_rate(size)
|
|
except:
|
|
if tup[2][1] != 0:
|
|
print ">>> sendto exception", tup
|
|
print_exc()
|
|
self.q.sort()
|
|
if self.q or self.curr > 0:
|
|
self.running = True
|
|
# sleep for at least a half second
|
|
self.call_later(self.run, max(self.curr / self.rate, 0.5))
|
|
else:
|
|
self.running = False
|
|
|
|
def expire(self, t=time()):
|
|
if self.q:
|
|
expire_time = t - self.age
|
|
while self.q and self.q[0][0] < expire_time:
|
|
self.q.pop(0)
|
|
self.dropped+=1
|