"""代理相关路由""" from typing import Optional from fastapi import APIRouter, Depends, Query from services.proxy_service import ProxyService from models.schemas import ProxyListRequest, BatchDeleteRequest from api.deps import get_proxy_service router = APIRouter(prefix="/api/proxies", tags=["proxies"]) def success_response(message: str, data=None): return {"code": 200, "message": message, "data": data} def error_response(message: str, code: int = 500): return {"code": code, "message": message, "data": None} @router.post("") async def list_proxies( request: ProxyListRequest, service: ProxyService = Depends(get_proxy_service), ): proxies, total = await service.list_proxies( page=request.page, page_size=request.page_size, protocol=request.protocol, min_score=request.min_score, max_score=request.max_score, sort_by=request.sort_by, sort_order=request.sort_order, ) return success_response( "获取代理列表成功", { "list": [ { "ip": p.ip, "port": p.port, "protocol": p.protocol, "score": p.score, "last_check": p.last_check.isoformat() if p.last_check else None, } for p in proxies ], "total": total, "page": request.page, "page_size": request.page_size, }, ) @router.get("/random") async def get_random_proxy(service: ProxyService = Depends(get_proxy_service)): proxy = await service.get_random_proxy() if not proxy: return error_response("没有找到可用的代理", 404) return success_response( "获取随机代理成功", { "ip": proxy.ip, "port": proxy.port, "protocol": proxy.protocol, "score": proxy.score, "last_check": proxy.last_check.isoformat() if proxy.last_check else None, }, ) @router.get("/export/{fmt}") async def export_proxies( fmt: str, protocol: Optional[str] = None, limit: int = Query(default=10000, ge=1, le=100000), service: ProxyService = Depends(get_proxy_service), ): if fmt not in ("csv", "txt", "json"): return error_response("不支持的导出格式", 400) from fastapi.responses import StreamingResponse media_types = {"csv": "text/csv", "txt": "text/plain", "json": "application/json"} async def generate(): async for chunk in service.export_proxies(fmt, protocol, limit): yield chunk return StreamingResponse( generate(), media_type=media_types[fmt], headers={"Content-Disposition": f"attachment; filename=proxies.{fmt}"}, ) @router.delete("/{ip}/{port}") async def delete_proxy(ip: str, port: int, service: ProxyService = Depends(get_proxy_service)): await service.delete_proxy(ip, port) return success_response("删除代理成功") @router.post("/batch-delete") async def batch_delete( request: BatchDeleteRequest, service: ProxyService = Depends(get_proxy_service), ): proxies = [(item.ip, item.port) for item in request.proxies] deleted = await service.batch_delete(proxies) return success_response(f"批量删除 {deleted} 个代理成功", {"deleted_count": deleted}) @router.delete("/clean-invalid") async def clean_invalid(service: ProxyService = Depends(get_proxy_service)): count = await service.clean_invalid() return success_response(f"清理了 {count} 个无效代理", {"deleted_count": count})