init
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
"""Simple in-memory rate limiter per user."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
|
||||
from app.api.deps import require_student
|
||||
from app.core.schemas import UserProfile
|
||||
|
||||
|
||||
class RateLimiter:
|
||||
def __init__(self, max_requests: int, window_seconds: int) -> None:
|
||||
self._max = max_requests
|
||||
self._window = window_seconds
|
||||
self._buckets: dict[int, list[float]] = defaultdict(list)
|
||||
|
||||
def check(self, user_id: int) -> None:
|
||||
now = time.time()
|
||||
cutoff = now - self._window
|
||||
bucket = self._buckets[user_id]
|
||||
# purge expired entries
|
||||
while bucket and bucket[0] < cutoff:
|
||||
bucket.pop(0)
|
||||
if len(bucket) >= self._max:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail=f"请求过于频繁,请 {self._window // 60} 分钟后重试",
|
||||
)
|
||||
bucket.append(now)
|
||||
|
||||
|
||||
_diagnosis_limiter = RateLimiter(max_requests=5, window_seconds=60)
|
||||
|
||||
|
||||
def check_diagnosis_rate_limit(
|
||||
user: Annotated[UserProfile, Depends(require_student)],
|
||||
) -> None:
|
||||
_diagnosis_limiter.check(user.id)
|
||||
Reference in New Issue
Block a user