""" Middleware de rate limiting — par client et par plan. Utilise slowapi (basé sur limits) avec identification par client_id plutôt que par IP, pour compter les requêtes par client API. Limites par plan (par heure) : - free : 20 uploads, 50 AI - standard : 100 uploads, 200 AI - premium : 500 uploads, 1000 AI """ import logging from slowapi import Limiter from slowapi.util import get_remote_address from starlette.requests import Request from app.config import settings logger = logging.getLogger(__name__) def _get_client_id_from_request(request: Request) -> str: """ Extrait le client_id depuis la state de la requête. Fallback vers l'IP si le client n'est pas encore authentifié. """ # Le client_id est injecté par le middleware ou la dépendance auth client_id = getattr(request.state, "client_id", None) if client_id: return str(client_id) return get_remote_address(request) # Instance globale du limiter limiter = Limiter(key_func=_get_client_id_from_request) def get_upload_rate_limit(plan: str) -> str: """Retourne la limite de rate pour les uploads selon le plan.""" limits = { "free": f"{settings.RATE_LIMIT_FREE_UPLOAD}/hour", "standard": f"{settings.RATE_LIMIT_STANDARD_UPLOAD}/hour", "premium": f"{settings.RATE_LIMIT_PREMIUM_UPLOAD}/hour", } return limits.get(plan, limits["free"]) def get_ai_rate_limit(plan: str) -> str: """Retourne la limite de rate pour les endpoints AI selon le plan.""" limits = { "free": f"{settings.RATE_LIMIT_FREE_AI}/hour", "standard": f"{settings.RATE_LIMIT_STANDARD_AI}/hour", "premium": f"{settings.RATE_LIMIT_PREMIUM_AI}/hour", } return limits.get(plan, limits["free"]) def upload_rate_limit_key(request: Request) -> str: """Clé dynamique pour le rate limiting des uploads.""" return _get_client_id_from_request(request) def ai_rate_limit_key(request: Request) -> str: """Clé dynamique pour le rate limiting des endpoints AI.""" return _get_client_id_from_request(request)