#!/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)}")