Fix API compatibility and add user/role/permission and asset import/export

This commit is contained in:
2026-01-25 23:36:23 +08:00
commit 501d11e14e
371 changed files with 68853 additions and 0 deletions

View File

@@ -0,0 +1,219 @@
"""
Redis客户端工具类
"""
import json
import asyncio
import hashlib
from functools import wraps
from typing import Optional, Any, List, Callable
from redis.asyncio import Redis, ConnectionPool
from app.core.config import settings
class RedisClient:
"""Redis客户端"""
def __init__(self):
"""初始化Redis客户端"""
self.pool: Optional[ConnectionPool] = None
self.redis: Optional[Redis] = None
async def connect(self):
"""连接Redis"""
if not self.pool:
self.pool = ConnectionPool.from_url(
settings.REDIS_URL,
max_connections=settings.REDIS_MAX_CONNECTIONS,
decode_responses=True
)
self.redis = Redis(connection_pool=self.pool)
async def close(self):
"""关闭连接"""
if self.redis:
await self.redis.close()
if self.pool:
await self.pool.disconnect()
async def get(self, key: str) -> Optional[str]:
"""获取缓存"""
if not self.redis:
await self.connect()
return await self.redis.get(key)
async def set(
self,
key: str,
value: str,
expire: Optional[int] = None
) -> bool:
"""设置缓存"""
if not self.redis:
await self.connect()
return await self.redis.set(key, value, ex=expire)
async def delete(self, key: str) -> int:
"""删除缓存"""
if not self.redis:
await self.connect()
return await self.redis.delete(key)
async def exists(self, key: str) -> bool:
"""检查键是否存在"""
if not self.redis:
await self.connect()
return await self.redis.exists(key) > 0
async def expire(self, key: str, seconds: int) -> bool:
"""设置过期时间"""
if not self.redis:
await self.connect()
return await self.redis.expire(key, seconds)
async def keys(self, pattern: str) -> List[str]:
"""获取匹配的键"""
if not self.redis:
await self.connect()
return await self.redis.keys(pattern)
async def delete_pattern(self, pattern: str) -> int:
"""删除匹配的键"""
keys = await self.keys(pattern)
if keys:
return await self.redis.delete(*keys)
return 0
async def setex(self, key: str, time: int, value: str) -> bool:
"""设置缓存并指定过期时间(秒)"""
if not self.redis:
await self.connect()
return await self.redis.setex(key, time, value)
# JSON操作辅助方法
async def get_json(self, key: str) -> Optional[Any]:
"""获取JSON数据"""
value = await self.get(key)
if value:
try:
return json.loads(value)
except json.JSONDecodeError:
return value
return None
async def set_json(
self,
key: str,
value: Any,
expire: Optional[int] = None
) -> bool:
"""设置JSON数据"""
json_str = json.dumps(value, ensure_ascii=False)
return await self.set(key, json_str, expire)
# 缓存装饰器
def cache(self, key_prefix: str, expire: int = 300):
"""
Redis缓存装饰器改进版
Args:
key_prefix: 缓存键前缀
expire: 过期时间默认300秒5分钟
Example:
@redis_client.cache("device_types", expire=1800)
async def get_device_types(...):
pass
"""
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
# 使用MD5生成更稳定的缓存键
key_data = f"{key_prefix}:{str(args)}:{str(kwargs)}"
cache_key = f"cache:{hashlib.md5(key_data.encode()).hexdigest()}"
# 尝试从缓存获取
cached = await self.get_json(cache_key)
if cached is not None:
return cached
# 执行函数
result = await func(*args, **kwargs)
# 存入缓存
await self.set_json(cache_key, result, expire)
return result
return wrapper
return decorator
# 统计缓存辅助方法
async def cache_statistics(
self,
key: str,
data: Any,
expire: int = 600
):
"""缓存统计数据"""
return await self.set_json(key, data, expire)
async def get_cached_statistics(self, key: str) -> Optional[Any]:
"""获取缓存的统计数据"""
return await self.get_json(key)
async def invalidate_statistics_cache(self, pattern: str = "statistics:*"):
"""清除统计数据缓存"""
return await self.delete_pattern(pattern)
# 同步函数的异步缓存包装器
def cached_async(self, key_prefix: str, expire: int = 300):
"""
为同步函数提供异步缓存包装的装饰器
Args:
key_prefix: 缓存键前缀
expire: 过期时间默认300秒5分钟
Example:
@redis_client.cached_async("device_types", expire=1800)
async def cached_get_device_types(db, skip, limit, ...):
return device_type_service.get_device_types(...)
"""
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
# 使用MD5生成更稳定的缓存键
key_data = f"{key_prefix}:{str(args)}:{str(kwargs)}"
cache_key = f"cache:{hashlib.md5(key_data.encode()).hexdigest()}"
# 尝试从缓存获取
cached = await self.get_json(cache_key)
if cached is not None:
return cached
# 执行函数
result = await func(*args, **kwargs)
# 存入缓存
await self.set_json(cache_key, result, expire)
return result
return wrapper
return decorator
# 创建全局实例
redis_client = RedisClient()
async def init_redis():
"""初始化Redis连接"""
await redis_client.connect()
async def close_redis():
"""关闭Redis连接"""
await redis_client.close()