Spaces:
Sleeping
Sleeping
| import time | |
| import threading | |
| from collections import deque | |
| from functools import wraps | |
| class RateLimitExceeded(Exception): | |
| pass | |
| class GlobalRateLimiter: | |
| def __init__(self, max_calls: int, window_seconds: int): | |
| self.max_calls = max_calls | |
| self.window = window_seconds | |
| self._lock = threading.Lock() | |
| self._events = deque() | |
| def allow(self) -> bool: | |
| now = time.time() | |
| with self._lock: | |
| while self._events and now - self._events[0] > self.window: | |
| self._events.popleft() | |
| if len(self._events) < self.max_calls: | |
| self._events.append(now) | |
| return True | |
| return False | |
| def enforce(self, func=None): | |
| def decorator(f): | |
| def wrapper(*args, **kwargs): | |
| if not self.allow(): | |
| raise RateLimitExceeded(f"Rate limit exceeded ({self.max_calls} req/{self.window}s)") | |
| return f(*args, **kwargs) | |
| return wrapper | |
| return decorator if func is None else decorator(func) | |