mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-13 00:32:58 -07:00
59 lines
1.5 KiB
Python
59 lines
1.5 KiB
Python
from math import floor
|
|
|
|
import time
|
|
import sys
|
|
import threading
|
|
import functools
|
|
|
|
|
|
def clamp(value):
|
|
'''
|
|
Clamp integer between 1 and max
|
|
|
|
There must be at least 1 method invocation
|
|
made over the time period. Make sure the
|
|
value passed is at least 1 and is not a
|
|
fraction of an invocation.
|
|
|
|
:param float value: The number of method invocations.
|
|
:return: Clamped number of invocations.
|
|
:rtype: int
|
|
'''
|
|
return max(1, min(sys.maxsize, floor(value)))
|
|
|
|
|
|
class RateLimitDecorator:
|
|
def __init__(self, period=1, every=1.0):
|
|
self.frequency = abs(every) / float(clamp(period))
|
|
self.last_called = 0.0
|
|
self.lock = threading.RLock()
|
|
|
|
def __call__(self, func):
|
|
'''
|
|
Extend the behaviour of the following
|
|
function, forwarding method invocations
|
|
if the time window hes elapsed.
|
|
|
|
:param function func: The function to decorate.
|
|
:return: Decorated function.
|
|
:rtype: function
|
|
'''
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
'''Decorator wrapper function'''
|
|
with self.lock:
|
|
elapsed = time.time() - self.last_called
|
|
left_to_wait = self.frequency - elapsed
|
|
if left_to_wait > 0:
|
|
time.sleep(left_to_wait)
|
|
self.last_called = time.time()
|
|
return func(*args, **kwargs)
|
|
return wrapper
|
|
|
|
|
|
rate_limited = RateLimitDecorator
|
|
|
|
|
|
__all__ = [
|
|
'rate_limited'
|
|
]
|