Desi-Clans/backend/app/core/rate_limit.py
2026-10-08 02:52:58 +05:30

37 lines
1.1 KiB
Python

import threading
import time
from collections import defaultdict
from fastapi import Request
from app.core.errors import AppError
_buckets: dict[str, list[float]] = defaultdict(list)
_lock = threading.Lock()
def _client_ip(request: Request) -> str:
forwarded = request.headers.get("x-forwarded-for")
if forwarded:
return forwarded.split(",")[0].strip()
if request.client and request.client.host:
return request.client.host
return "unknown"
def enforce_rate_limit(request: Request, *, scope: str, limit: int, window_seconds: int) -> None:
"""In-memory sliding window limiter (per process). Use edge/WAF limits in production at scale."""
import os
if os.environ.get("DESI_CLANS_DISABLE_RATE_LIMIT", "").lower() in {"1", "true", "yes"}:
return
if limit <= 0:
return
key = f"{scope}:{_client_ip(request)}"
now = time.time()
with _lock:
window = _buckets[key]
window[:] = [stamp for stamp in window if now - stamp < window_seconds]
if len(window) >= limit:
raise AppError("Too many requests. Try again shortly.", status_code=429)
window.append(now)