初始提交
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import inspect
|
||||
from collections.abc import Awaitable, Callable, Sequence
|
||||
from typing import TypeVar
|
||||
|
||||
from fastapi import Request
|
||||
from redis import asyncio as aioredis
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
from common.enums import HttpMethod
|
||||
from utils.log_util import logger
|
||||
|
||||
P = ParamSpec('P')
|
||||
R = TypeVar('R')
|
||||
|
||||
|
||||
class ApiAnnotationUtil:
|
||||
"""
|
||||
接口装饰器通用工具类
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_request(cls, func: Callable[P, Awaitable[R]], *args: P.args, **kwargs: P.kwargs) -> Request | None:
|
||||
"""
|
||||
从被装饰函数的入参中提取Request对象
|
||||
|
||||
:param func: 被装饰的异步接口函数
|
||||
:param args: 位置参数
|
||||
:param kwargs: 关键字参数
|
||||
:return: Request对象,未找到时返回None
|
||||
"""
|
||||
signature = inspect.signature(func)
|
||||
bound_arguments = signature.bind_partial(*args, **kwargs)
|
||||
for argument in bound_arguments.arguments.values():
|
||||
if isinstance(argument, Request):
|
||||
return argument
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_redis_client(cls, request: Request, skip_message: str) -> aioredis.Redis | None:
|
||||
"""
|
||||
从应用状态中获取Redis连接
|
||||
|
||||
:param request: 当前请求对象
|
||||
:param skip_message: 未初始化Redis连接时的日志信息
|
||||
:return: Redis连接对象,未初始化时返回None
|
||||
"""
|
||||
redis = getattr(request.app.state, 'redis', None)
|
||||
if redis is None:
|
||||
logger.warning(skip_message)
|
||||
|
||||
return redis
|
||||
|
||||
@classmethod
|
||||
def resolve_request_redis(
|
||||
cls,
|
||||
func: Callable[P, Awaitable[R]],
|
||||
skip_message: str,
|
||||
*args: P.args,
|
||||
**kwargs: P.kwargs,
|
||||
) -> tuple[Request | None, aioredis.Redis | None]:
|
||||
"""
|
||||
从被装饰函数入参中同时解析Request与Redis连接
|
||||
|
||||
:param func: 被装饰的异步接口函数
|
||||
:param skip_message: 未初始化Redis连接时的日志信息
|
||||
:param args: 位置参数
|
||||
:param kwargs: 关键字参数
|
||||
:return: Request对象与Redis连接对象组成的元组
|
||||
"""
|
||||
request = cls.get_request(func, *args, **kwargs)
|
||||
if request is None:
|
||||
return None, None
|
||||
|
||||
return request, cls.get_redis_client(request, skip_message)
|
||||
|
||||
@classmethod
|
||||
def normalize_http_methods(
|
||||
cls,
|
||||
methods: Sequence[HttpMethod] | None,
|
||||
default_methods: Sequence[HttpMethod] | None = None,
|
||||
) -> tuple[str, ...]:
|
||||
"""
|
||||
标准化HTTP请求方法配置
|
||||
|
||||
:param methods: 显式配置的HTTP请求方法
|
||||
:param default_methods: methods为空时使用的默认HTTP请求方法
|
||||
:return: 去重且标准化后的HTTP请求方法元组
|
||||
"""
|
||||
target_methods = methods if methods is not None else default_methods
|
||||
if not target_methods:
|
||||
return ()
|
||||
|
||||
normalized_methods: list[str] = []
|
||||
for method in target_methods:
|
||||
if not isinstance(method, HttpMethod):
|
||||
raise TypeError('methods参数仅支持HttpMethod枚举')
|
||||
normalized_method = method.value
|
||||
if normalized_method not in normalized_methods:
|
||||
normalized_methods.append(normalized_method)
|
||||
|
||||
return tuple(normalized_methods)
|
||||
Reference in New Issue
Block a user