big update new dashboard and import export

This commit is contained in:
2026-04-10 00:39:35 +05:00
parent 4013701441
commit e2fb4ddb2a
19 changed files with 1324 additions and 159 deletions

View File

@@ -17,26 +17,10 @@ class RedisSettings(GenericModel):
else:
return f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
@property
def connection_kwargs(self) -> dict:
"""Получить параметры подключения для redis.Redis()"""
return {
"host": self.REDIS_HOST,
"port": self.REDIS_PORT,
"db": self.REDIS_DB,
"password": self.REDIS_PASSWORD,
"decode_responses": True,
}
def get_client(self) -> redis.Redis:
"""Создать и вернуть Redis клиент"""
return redis.Redis(**self.connection_kwargs)
def test_connection(self) -> bool:
"""Протестировать подключение к Redis"""
try:
client = self.get_client()
client.ping()
get_redis_client().ping()
print(f"✓ Успешно подключено к Redis на {self.REDIS_HOST}:{self.REDIS_PORT}")
return True
except redis.ConnectionError as e:
@@ -47,6 +31,19 @@ class RedisSettings(GenericModel):
# Глобальная конфигурация
_redis_settings = RedisSettings()
# Единый connection pool на весь процесс (max_connections=20 — для FastAPI с несколькими воркерами)
_pool = redis.ConnectionPool(
host=_redis_settings.REDIS_HOST,
port=_redis_settings.REDIS_PORT,
db=_redis_settings.REDIS_DB,
password=_redis_settings.REDIS_PASSWORD,
decode_responses=True,
max_connections=20,
socket_connect_timeout=3,
socket_timeout=3,
retry_on_timeout=True,
)
def get_redis_settings() -> RedisSettings:
"""Получить конфигурацию Redis"""
@@ -54,9 +51,72 @@ def get_redis_settings() -> RedisSettings:
def get_redis_client() -> redis.Redis:
"""Получить готовый клиент Redis"""
return _redis_settings.get_client()
"""Получить клиент из общего connection pool (не создаёт новое TCP-соединение)."""
return redis.Redis(connection_pool=_pool)
__all__ = ["RedisSettings", "get_redis_settings", "get_redis_client"]
# ---------------------------------------------------------------------------
# Блэклист токенов
# ---------------------------------------------------------------------------
_BLACKLIST_PREFIX = "token_blacklist:"
def blacklist_token(jti: str, ttl_seconds: int) -> None:
"""Добавить jti токена в блэклист на ttl_seconds секунд."""
try:
client = get_redis_client()
client.setex(f"{_BLACKLIST_PREFIX}{jti}", ttl_seconds, "1")
except redis.RedisError:
pass # Redis недоступен — не блокируем работу
def is_token_blacklisted(jti: str) -> bool:
"""Проверить, отозван ли токен."""
try:
client = get_redis_client()
return client.exists(f"{_BLACKLIST_PREFIX}{jti}") > 0
except redis.RedisError:
return False # при ошибке Redis не блокируем пользователей
# ---------------------------------------------------------------------------
# Кэш
# ---------------------------------------------------------------------------
_CACHE_PREFIX = "cache:"
def cache_get(key: str) -> str | None:
"""Получить значение из кэша по ключу. Возвращает None если нет или Redis недоступен."""
try:
client = get_redis_client()
return client.get(f"{_CACHE_PREFIX}{key}")
except redis.RedisError:
return None
def cache_set(key: str, value: str, ttl_seconds: int = 300) -> None:
"""Сохранить строку в кэш с TTL (по умолчанию 5 минут)."""
try:
client = get_redis_client()
client.setex(f"{_CACHE_PREFIX}{key}", ttl_seconds, value)
except redis.RedisError:
pass
def cache_delete(key: str) -> None:
"""Удалить ключ из кэша."""
try:
client = get_redis_client()
client.delete(f"{_CACHE_PREFIX}{key}")
except redis.RedisError:
pass
__all__ = [
"RedisSettings", "get_redis_settings", "get_redis_client",
"blacklist_token", "is_token_blacklisted",
"cache_get", "cache_set", "cache_delete",
]