feat: add rate_limit
This commit is contained in:
parent
da29380087
commit
21e19ed6a9
|
|
@ -14,6 +14,8 @@ class Settings(BaseSettings):
|
|||
|
||||
DATABASE_URL: str
|
||||
REDIS_URL: str
|
||||
REDIS_USERNAME: str
|
||||
REDIS_PASSWORD: str
|
||||
|
||||
LIVEKIT_API_KEY: str
|
||||
LIVEKIT_API_SECRET: str
|
||||
|
|
|
|||
|
|
@ -15,33 +15,22 @@ class RateLimiter:
|
|||
self.scope = scope
|
||||
|
||||
async def __call__(self, request: Request):
|
||||
# getting client ip
|
||||
client_ip = request.client.host if request.client else "127.0.0.1"
|
||||
|
||||
# when project is in docker and behind nginx, the real ip is in the headers
|
||||
real_ip = request.headers.get("x-real-ip", request.headers.get("x-forwarded-for", client_ip))
|
||||
# if there are multiple ips, take the first ip (the real user ip)
|
||||
real_ip = real_ip.split(",")[0].strip()
|
||||
|
||||
# creating redis key based on scope
|
||||
if self.scope == "global":
|
||||
# key for global limit (e.g., rate_limit:global:192.168.1.5)
|
||||
key = f"rate_limit:global:{real_ip}"
|
||||
else:
|
||||
# key for endpoint limit (e.g., rate_limit:endpoint:192.168.1.5:/admin/login)
|
||||
path = request.scope["path"]
|
||||
key = f"rate_limit:endpoint:{real_ip}:{path}"
|
||||
|
||||
# adding 1 to the number of requests for this ip in redis
|
||||
current_count = await redis_client.incr(key)
|
||||
|
||||
# if this is the first request in this time window, set the expiration time (TTL)
|
||||
if current_count == 1:
|
||||
await redis_client.expire(key, self.window_seconds)
|
||||
|
||||
# if the number of requests exceeds the limit, access is blocked
|
||||
if current_count > self.requests:
|
||||
# penalty: if someone spams, the time they are blocked is extended from zero again
|
||||
await redis_client.expire(key, self.window_seconds)
|
||||
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ services:
|
|||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: always
|
||||
|
||||
ports:
|
||||
- "5432:5432"
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
|
||||
interval: 5s
|
||||
|
|
@ -22,9 +25,13 @@ services:
|
|||
volumes:
|
||||
- redis_data:/data
|
||||
restart: always
|
||||
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- internal
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "ping" ]
|
||||
test: [ "CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping" ]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
|
@ -35,30 +42,22 @@ services:
|
|||
ports:
|
||||
- "7780:7880"
|
||||
- "7781:7881"
|
||||
- "50000-50100:50000-50100/udp"
|
||||
- "51000-51100:51000-51100/udp"
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./livekit.yaml:/etc/livekit/livekit.yaml
|
||||
command: [ "--config", "/etc/livekit/livekit.yaml", "--keys", "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}" ]
|
||||
restart: always
|
||||
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4:latest
|
||||
container_name: neda_pgadmin
|
||||
restart: always
|
||||
ports:
|
||||
- "5050:80"
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL}
|
||||
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD}
|
||||
PGADMIN_CONFIG_SERVER_MODE: 'True'
|
||||
PGADMIN_CONFIG_UPGRADE_CHECK_ENABLED: 'False'
|
||||
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False'
|
||||
volumes:
|
||||
- pgadmin_data:/var/lib/pgadmin
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- public
|
||||
- internal
|
||||
healthcheck:
|
||||
test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7880/health" ] # بررسی سلامت LiveKit
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
pg_backup:
|
||||
image: prodrigestivill/postgres-backup-local
|
||||
|
|
@ -75,7 +74,8 @@ services:
|
|||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
SCHEDULE: '@daily'
|
||||
BACKUP_KEEP_DAYS: 7
|
||||
|
||||
networks:
|
||||
- internal
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
@ -89,6 +89,9 @@ services:
|
|||
- "./:/app"
|
||||
env_file:
|
||||
- .env
|
||||
networks:
|
||||
- public
|
||||
- internal
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
@ -98,6 +101,13 @@ services:
|
|||
condition: service_started
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
public:
|
||||
driver: bridge
|
||||
internal:
|
||||
driver: bridge
|
||||
# internal: true
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ port: 7880
|
|||
|
||||
rtc:
|
||||
tcp_port: 7881
|
||||
port_range_start: 50000
|
||||
port_range_end: 50100
|
||||
port_range_start: 51000
|
||||
port_range_end: 51100
|
||||
use_external_ip: false
|
||||
# node_ip: "94.183.170.121"
|
||||
|
||||
|
|
|
|||
15
Back/tests/test_redis.py
Normal file
15
Back/tests/test_redis.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import asyncio
|
||||
import redis.asyncio as redis
|
||||
from core.config import settings
|
||||
|
||||
async def test_redis():
|
||||
print(f"Testing connection to: {settings.REDIS_URL}")
|
||||
try:
|
||||
client = redis.from_url(settings.REDIS_URL, decode_responses=True)
|
||||
pong = await client.ping()
|
||||
print(f"Ping successful: {pong}")
|
||||
except Exception as e:
|
||||
print(f"Connection failed: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_redis())
|
||||
Loading…
Reference in New Issue
Block a user