config_proxy.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. from fastapi import APIRouter, Depends, HTTPException, Body, status, Query
  2. from fastapi.responses import JSONResponse
  3. import httpx
  4. from app.api.users import require_admin_user
  5. from ..core.logger import get_logger
  6. from ..core.config import settings
  7. from contextlib import asynccontextmanager
  8. logger = get_logger(__name__)
  9. router = APIRouter()
  10. # 1. 创建一个全局的 client (配置好超时和连接池)
  11. # limits: max_keepalive_connections 控制连接池大小
  12. http_client = httpx.AsyncClient(timeout=10.0, limits=httpx.Limits(max_keepalive_connections=20, max_connections=100))
  13. @router.get("/scoring_config", summary="[代理] 获取评分配置")
  14. async def proxy_get_scoring_config(current_user: dict = Depends(require_admin_user)):
  15. target_url = settings.SCORE_SERVER_CONFIG_URL
  16. try:
  17. # 2. 直接使用全局 client,不需要 async with
  18. resp = await http_client.get(target_url)
  19. if resp.status_code != 200:
  20. logger.error(f"项目1返回错误: {resp.status_code} - {resp.text}")
  21. raise HTTPException(
  22. status_code=resp.status_code,
  23. detail=resp.json().get("detail", "上游服务错误")
  24. )
  25. return resp.json()
  26. except httpx.RequestError as exc:
  27. logger.error(f"连接项目1失败: {exc}")
  28. raise HTTPException(status_code=503, detail=str(exc))
  29. @router.put("/scoring_config", summary="[代理] 更新评分配置")
  30. async def proxy_update_scoring_config(
  31. config_data: dict = Body(...),
  32. current_user: dict = Depends(require_admin_user)
  33. ):
  34. target_url = settings.SCORE_SERVER_CONFIG_URL
  35. try:
  36. # 2. 复用连接
  37. resp = await http_client.put(target_url, json=config_data)
  38. if resp.status_code != 200:
  39. raise HTTPException(status_code=resp.status_code, detail=f"保存失败: {resp.json()['detail']}")
  40. return_data = {"detail": f"{resp.json()['message']}"}
  41. return JSONResponse(status_code=resp.status_code, content=return_data)
  42. except httpx.RequestError as exc:
  43. logger.error(f"连接项目1失败: {exc}")
  44. raise HTTPException(status_code=503, detail=str(exc))
  45. @router.get("/severity_names", summary="[代理] 获取缺陷严重程度列表")
  46. async def proxy_get_severity_names(defect_label: str = Query(..., description="缺陷标签")):
  47. target_url = f"{settings.SCORE_SERVER_CONFIG_URL.replace('/scoring_config', '')}/severity_names"
  48. # 注意:settings.SCORE_SERVER_CONFIG_URL 通常是 http://host:port/api/config/scoring_config
  49. # 我们需要构建 http://host:port/api/config/severity_names
  50. # 更加稳健的写法是基于 base URL 拼接,这里假设 replace 可行,或者直接使用 query params
  51. # 假设 settings.SCORE_SERVER_CONFIG_URL 是完整路径 ".../scoring_config"
  52. # 我们需要把它替换掉
  53. base_url = settings.SCORE_SERVER_CONFIG_URL.rsplit('/', 1)[0]
  54. final_url = f"{base_url}/severity_names"
  55. try:
  56. # 发送带参数的 GET 请求
  57. resp = await http_client.get(final_url, params={"defect_label": defect_label})
  58. if resp.status_code != 200:
  59. logger.error(f"项目1返回错误: {resp.status_code} - {resp.text}")
  60. raise HTTPException(
  61. status_code=resp.status_code,
  62. detail=resp.json().get("detail", "上游服务错误")
  63. )
  64. return resp.json()
  65. except httpx.RequestError as exc:
  66. logger.error(f"连接项目1失败: {exc}")
  67. raise HTTPException(status_code=503, detail=str(exc))