mirror of
https://github.com/insistence/RuoYi-Vue3-FastAPI.git
synced 2026-09-28 15:09:58 +00:00
103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
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)
|