VWED_server/routes/dynamic_api.py

255 lines
9.4 KiB
Python
Raw Normal View History

2025-09-12 16:15:13 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
动态API路由处理器
处理脚本注册的动态API请求
"""
import time
import asyncio
from fastapi import APIRouter, Request
from services.script_registry_service import get_global_registry
from utils.logger import get_logger
from utils.api_response import success_response, error_response
logger = get_logger("routes.dynamic_api")
router = APIRouter()
@router.api_route("/api/dynamic/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
async def handle_dynamic_api(request: Request, path: str):
"""处理脚本注册的动态API请求"""
try:
registry = get_global_registry()
method = request.method
route_key = f"{method}:/{path}"
# 查找对应的路由处理器
route_info = registry.get_api_route(f"/{path}", method)
if not route_info:
return error_response(f"API路由未找到: {method} /{path}", code=404)
# 获取请求数据
request_data = {
"method": method,
"path": f"/{path}",
"query_params": dict(request.query_params),
"headers": dict(request.headers)
}
# 处理请求体数据
if method in ["POST", "PUT", "PATCH"]:
try:
body = await request.json()
request_data["body"] = body
except:
request_data["body"] = {}
else:
request_data["body"] = {}
# 获取处理器
handler = route_info["handler"]
start_time = time.time()
# 处理简化参数格式
params = route_info.get("params", {})
if params and method in ["POST", "PUT", "PATCH"]:
# 从请求体提取参数并传递给处理器(新的简化格式)
handler_args = {}
for param_name, default_value in params.items():
handler_args[param_name] = request_data["body"].get(param_name, default_value)
# 检测处理器是否为异步函数
if asyncio.iscoroutinefunction(handler):
result = await handler(**handler_args)
else:
result = handler(**handler_args)
else:
# 传递原始请求数据(兼容旧格式)
if asyncio.iscoroutinefunction(handler):
result = await handler(request_data)
else:
result = handler(request_data)
# 计算响应时间
response_time_ms = int((time.time() - start_time) * 1000)
# 更新调用统计
registry.update_api_call_stats(route_key, response_time_ms)
logger.info(f"动态API调用成功: {method} /{path} (脚本: {route_info['script_id']}, 耗时: {response_time_ms}ms)")
return success_response(
data=result,
message=f"API调用成功"
)
except Exception as e:
logger.error(f"动态API处理失败: {method} /{path} - {e}", exc_info=True)
return error_response(f"动态API处理失败: {str(e)}", code=500)
@router.get("/api/dynamic-registry/status")
async def get_dynamic_registry_status():
"""获取动态API注册状态"""
try:
registry = get_global_registry()
registrations = registry.get_all_registrations()
# 统计信息
stats = {
"total_apis": len(registrations["api_routes"]),
"total_functions": len(registrations["registered_functions"]),
"total_events": sum(len(listeners) for listeners in registrations["event_listeners"].values()),
"total_timers": len(registrations["timers"]),
"active_scripts": len(registrations["active_scripts"])
}
return success_response(
data={
"stats": stats,
"registrations": registrations
},
message="获取注册状态成功"
)
except Exception as e:
logger.error(f"获取动态注册状态失败: {e}", exc_info=True)
return error_response(f"获取注册状态失败: {str(e)}")
@router.get("/api/dynamic-registry/apis")
async def list_dynamic_apis():
"""列出所有动态注册的API"""
try:
registry = get_global_registry()
api_routes = registry.api_routes
# 格式化API列表
api_list = []
for route_key, route_info in api_routes.items():
api_list.append({
"route_key": route_key,
"path": route_info["path"],
"method": route_info["method"],
"script_id": route_info["script_id"],
"description": route_info["description"],
"call_count": route_info["call_count"],
"last_called_at": route_info["last_called_at"],
"average_response_time_ms": route_info["average_response_time_ms"],
"registered_at": route_info["registered_at"],
"params": route_info.get("params", {}) # 显示简化的参数格式
})
return success_response(
data={"apis": api_list, "total": len(api_list)},
message=f"获取动态API列表成功{len(api_list)}个接口"
)
except Exception as e:
logger.error(f"获取动态API列表失败: {e}", exc_info=True)
return error_response(f"获取API列表失败: {str(e)}")
@router.get("/api/dynamic-registry/functions")
async def list_dynamic_functions():
"""列出所有动态注册的函数"""
try:
registry = get_global_registry()
functions = registry.registered_functions
# 格式化函数列表
function_list = []
for function_name, function_info in functions.items():
function_list.append({
"name": function_name,
"script_id": function_info["script_id"],
"description": function_info["description"],
"is_async": function_info["is_async"],
"call_count": function_info["call_count"],
"success_count": function_info["success_count"],
"error_count": function_info["error_count"],
"last_called_at": function_info["last_called_at"],
"average_execution_time_ms": function_info["average_execution_time_ms"],
"registered_at": function_info["registered_at"],
"params": function_info.get("params", {}), # 显示简化的参数格式
"tags": function_info["tags"]
})
return success_response(
data={"functions": function_list, "total": len(function_list)},
message=f"获取动态函数列表成功,共{len(function_list)}个函数"
)
except Exception as e:
logger.error(f"获取动态函数列表失败: {e}", exc_info=True)
return error_response(f"获取函数列表失败: {str(e)}")
@router.post("/api/dynamic-registry/test-function/{function_name}")
async def test_dynamic_function(function_name: str, request: Request):
"""测试动态注册的函数"""
try:
registry = get_global_registry()
function_info = registry.get_function_info(function_name)
if not function_info:
return error_response(f"函数 {function_name} 未注册")
# 获取测试参数
try:
test_args = await request.json()
except:
test_args = {}
# 获取处理器
handler = function_info["handler"]
start_time = time.time()
# 处理简化参数格式
params = function_info.get("params", {})
if params:
# 使用简化的参数格式
handler_args = {}
for param_name, default_value in params.items():
handler_args[param_name] = test_args.get(param_name, default_value)
if function_info["is_async"]:
result = await handler(**handler_args)
else:
result = handler(**handler_args)
else:
# 兼容旧格式
if function_info["is_async"]:
result = await handler(test_args)
else:
result = handler(test_args)
# 计算执行时间
execution_time_ms = int((time.time() - start_time) * 1000)
# 更新统计
registry.update_function_call_stats(function_name, execution_time_ms, True)
logger.info(f"动态函数测试成功: {function_name} (脚本: {function_info['script_id']}, 耗时: {execution_time_ms}ms)")
return success_response(
data={
"result": result,
"execution_time_ms": execution_time_ms,
"function_name": function_name,
"script_id": function_info["script_id"]
},
message=f"函数测试成功"
)
except Exception as e:
logger.error(f"测试动态函数失败: {function_name} - {e}", exc_info=True)
# 更新失败统计
if function_info:
execution_time_ms = int((time.time() - start_time) * 1000) if 'start_time' in locals() else 0
registry.update_function_call_stats(function_name, execution_time_ms, False)
return error_response(f"函数测试失败: {str(e)}")