Files
kami_apple_exchage/backend/app/api/v1/links.py
danial 8bc8e1c664 feat(links): 实现基于权重的轮询算法和链接管理功能
- 新增链接权重字段,支持1-100范围设置
- 修改轮询算法为基于权重的选择机制
- 更新链接API接口返回统一使用LinkInfo模型
- 添加更新链接权重的PATCH端点
- 调整链接仓库查询逻辑,只包含激活状态链接
- 迁移链接相关Pydantic模型到task模块统一管理
- 修改分页响应格式为通用PaginatedResponse包装
- 禁用OpenTelemetry监控配置
2025-09-30 17:02:02 +08:00

150 lines
5.4 KiB
Python

"""
链接相关的API接口
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_async_db
from app.core.log import get_logger
from app.schemas.link import (
LinkCreate,
LinkStatus,
LinkUpdate,
)
from app.schemas.task import (
LinkInfo,
PaginatedResponse,
)
from app.services.link_service import LinksService
logger = get_logger(__name__)
router = APIRouter()
def get_link_service(db: AsyncSession = Depends(get_async_db)) -> LinksService:
"""获取链接服务实例"""
return LinksService(db)
@router.post("/", response_model=LinkInfo)
async def create_link(
link_data: LinkCreate, link_service: LinksService = Depends(get_link_service)
) -> LinkInfo:
"""创建新链接"""
try:
return await link_service.create_link(link_data)
except ValueError as e:
logger.warning(
f"创建链接失败 - 参数验证错误: {str(e)}", link_data=link_data.model_dump()
)
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"创建链接失败: {str(e)}", link_data=link_data.model_dump())
raise HTTPException(status_code=500, detail="创建链接失败")
@router.get("/list", response_model=PaginatedResponse[LinkInfo])
async def get_links(
page: int = Query(1, ge=1, description="页码"),
size: int = Query(20, ge=1, le=1000, description="每页大小"),
min_amount: float | None = Query(None, description="最小金额"),
max_amount: float | None = Query(None, description="最大金额"),
url_pattern: str | None = Query(None, description="URL模式"),
link_service: LinksService = Depends(get_link_service),
) -> PaginatedResponse[LinkInfo]:
"""获取链接列表"""
try:
result = await link_service.get_links(
page=page,
size=size,
min_amount=min_amount,
max_amount=max_amount,
url_pattern=url_pattern,
)
# 按更新时间逆向排序
return result
except Exception as e:
logger.error(f"获取链接列表失败: {str(e)}")
raise HTTPException(status_code=500, detail="获取链接列表失败")
@router.get("/{link_id}", response_model=LinkInfo)
async def get_link(
link_id: int, link_service: LinksService = Depends(get_link_service)
) -> LinkInfo:
"""获取单个链接详情"""
try:
link = await link_service.get_link(str(link_id))
if not link:
logger.warning(f"获取链接详情失败 - 链接不存在: {link_id}")
raise HTTPException(status_code=404, detail="链接不存在")
return link
except HTTPException:
raise
except Exception as e:
logger.error(f"获取链接详情失败: {str(e)}", link_id=link_id, exc_info=True)
raise HTTPException(status_code=500, detail="获取链接详情失败")
@router.delete("/{link_id}")
async def delete_link(
link_id: str, link_service: LinksService = Depends(get_link_service)
) -> dict[str, str]:
"""删除链接"""
try:
success = await link_service.delete_link(link_id)
if not success:
logger.warning(f"删除链接失败 - 链接不存在: {link_id}")
raise HTTPException(status_code=404, detail="链接不存在")
logger.info(f"链接删除成功: {link_id}")
return {"message": "链接删除成功"}
except HTTPException:
raise
except Exception as e:
logger.error(f"删除链接失败: {str(e)}", link_id=link_id, exc_info=True)
raise HTTPException(status_code=500, detail="删除链接失败")
@router.patch("/{link_id}/status")
async def toggle_link_status(
link_id: str,
status: LinkStatus,
link_service: LinksService = Depends(get_link_service),
) -> LinkInfo:
"""切换链接状态"""
try:
updated_link = await link_service.update_link_status(link_id, status)
if not updated_link:
logger.warning(f"切换链接状态失败 - 链接不存在: {link_id}")
raise HTTPException(status_code=404, detail="链接不存在")
logger.info(f"链接状态切换成功: {link_id} -> {status}")
return updated_link
except HTTPException:
raise
except Exception as e:
logger.error(f"切换链接状态失败: {str(e)}", link_id=link_id, exc_info=True)
raise HTTPException(status_code=500, detail="切换链接状态失败")
@router.patch("/{link_id}/weight")
async def update_link_weight(
link_id: str,
weight: int = Query(..., ge=1, le=100, description="权重值(1-100)"),
link_service: LinksService = Depends(get_link_service),
) -> LinkInfo:
"""更新链接权重"""
try:
link_update = LinkUpdate(url=None, amount=None, weight=weight, status=None)
updated_link = await link_service.update_link(link_id, link_update)
if not updated_link:
logger.warning(f"更新链接权重失败 - 链接不存在: {link_id}")
raise HTTPException(status_code=404, detail="链接不存在")
logger.info(f"链接权重更新成功: {link_id} -> {weight}")
return updated_link
except HTTPException:
raise
except Exception as e:
logger.error(f"更新链接权重失败: {str(e)}", link_id=link_id, exc_info=True)
raise HTTPException(status_code=500, detail="更新链接权重失败")