Initial commit: fastapi-traffic rate limiting library
- Core rate limiting with multiple algorithms (sliding window, token bucket, etc.) - SQLite and memory backends - Decorator and dependency injection patterns - Middleware support - Example usage files
This commit is contained in:
89
fastapi_traffic/core/models.py
Normal file
89
fastapi_traffic/core/models.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""Data models for rate limiting."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
|
||||
class KeyType(str, Enum):
|
||||
"""Type of key extraction for rate limiting."""
|
||||
|
||||
IP = "ip"
|
||||
USER = "user"
|
||||
API_KEY = "api_key"
|
||||
ENDPOINT = "endpoint"
|
||||
CUSTOM = "custom"
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RateLimitInfo:
|
||||
"""Information about the current rate limit state."""
|
||||
|
||||
limit: int
|
||||
remaining: int
|
||||
reset_at: float
|
||||
retry_after: float | None = None
|
||||
window_size: float = 60.0
|
||||
|
||||
def to_headers(self) -> dict[str, str]:
|
||||
"""Convert rate limit info to HTTP headers."""
|
||||
headers: dict[str, str] = {
|
||||
"X-RateLimit-Limit": str(self.limit),
|
||||
"X-RateLimit-Remaining": str(max(0, self.remaining)),
|
||||
"X-RateLimit-Reset": str(int(self.reset_at)),
|
||||
}
|
||||
if self.retry_after is not None:
|
||||
headers["Retry-After"] = str(int(self.retry_after))
|
||||
return headers
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RateLimitResult:
|
||||
"""Result of a rate limit check."""
|
||||
|
||||
allowed: bool
|
||||
info: RateLimitInfo
|
||||
key: str
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class TokenBucketState:
|
||||
"""State for token bucket algorithm."""
|
||||
|
||||
tokens: float
|
||||
last_update: float
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class SlidingWindowState:
|
||||
"""State for sliding window algorithm."""
|
||||
|
||||
timestamps: list[float] = field(default_factory=list)
|
||||
count: int = 0
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class FixedWindowState:
|
||||
"""State for fixed window algorithm."""
|
||||
|
||||
count: int
|
||||
window_start: float
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class LeakyBucketState:
|
||||
"""State for leaky bucket algorithm."""
|
||||
|
||||
water_level: float
|
||||
last_update: float
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class BackendRecord:
|
||||
"""Generic record stored in backends."""
|
||||
|
||||
key: str
|
||||
data: dict[str, Any]
|
||||
expires_at: float
|
||||
Reference in New Issue
Block a user