高优先级问题1 - Router层业务逻辑泄漏: - 新建 services/proxy_service.py: 从routers/proxy.py提取ProxyService类, 封装代理/白名单测试逻辑、全局状态管理、所有core/ import - 新建 services/account_service.py: 从routers/accounts.py提取 split_account_line、cookie_account_ids_query、parse_and_build_accounts, 封装core.douyu.email_verifier的import - 重写routers/proxy.py为薄HTTP/WS层,移除所有core/直接依赖 - 精简routers/accounts.py,从account_service导入业务函数 - 将_active_batches全局状态移入login_service.py的BatchRegistry类 - routers/login.py改为使用batch_registry单例 高优先级问题2 - 两套models.py冗余: - 删除core/models.py(Account dataclass + ProxyConfig死代码) - 在core/douyu/login.py新增AccountLike Protocol替代Account dataclass - login_service.py中Account(...)构造改为SimpleNamespace(...) - 清理core/__init__.py导出 附带修复: - core/geetest/common/network.py的get_picture()函数缩进错误 (缺少if match:块和data赋值语句)
119 lines
3.5 KiB
Python
119 lines
3.5 KiB
Python
"""代理 & 白名单配置路由 + WebSocket 实时日志"""
|
|
|
|
import asyncio
|
|
import threading
|
|
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..database import get_db
|
|
from ..models import User
|
|
from ..schemas import ProxyConfigOut, ProxyConfigUpdate
|
|
from ..deps import require_permission, authenticate_websocket
|
|
from ..services.proxy_service import proxy_service
|
|
|
|
router = APIRouter(prefix="/api/proxy", tags=["代理与白名单"])
|
|
|
|
|
|
@router.get("", response_model=ProxyConfigOut)
|
|
def get_proxy_config(
|
|
db: Session = Depends(get_db),
|
|
_: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
return proxy_service.get_or_create(db)
|
|
|
|
|
|
@router.put("", response_model=ProxyConfigOut)
|
|
def update_proxy_config(
|
|
req: ProxyConfigUpdate,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
return proxy_service.update_config(
|
|
db,
|
|
enabled=req.enabled,
|
|
api_url=req.api_url,
|
|
http=req.http,
|
|
https=req.https,
|
|
whitelist_enabled=req.whitelist_enabled,
|
|
whitelist_uid=req.whitelist_uid,
|
|
whitelist_ukey=req.whitelist_ukey,
|
|
current_user=current,
|
|
)
|
|
|
|
|
|
# ---- WebSocket 日志推送 ----
|
|
|
|
@router.websocket("/ws/test/{test_id}")
|
|
async def ws_test_logs(websocket: WebSocket, test_id: str):
|
|
"""WebSocket 推送代理/白名单测试实时日志(需认证)。"""
|
|
user = authenticate_websocket(websocket)
|
|
if not user:
|
|
await websocket.close(code=1008, reason="未授权")
|
|
return
|
|
|
|
await websocket.accept()
|
|
|
|
test = proxy_service.get_test(test_id)
|
|
if not test:
|
|
await websocket.send_json({"level": "error", "message": "测试任务不存在"})
|
|
await websocket.close()
|
|
return
|
|
|
|
log_queue: asyncio.Queue = test["log_queue"]
|
|
|
|
try:
|
|
while True:
|
|
try:
|
|
msg = await asyncio.wait_for(log_queue.get(), timeout=30)
|
|
await websocket.send_json(msg)
|
|
# 收到 result 消息表示测试结束
|
|
if msg.get("level") == "result":
|
|
await asyncio.sleep(0.1)
|
|
break
|
|
except asyncio.TimeoutError:
|
|
await websocket.send_json({"level": "heartbeat", "message": ""})
|
|
except WebSocketDisconnect:
|
|
pass
|
|
finally:
|
|
proxy_service.remove_test(test_id)
|
|
|
|
|
|
# ---- 异步测试 API 端点 ----
|
|
|
|
@router.post("/test")
|
|
async def test_proxy(
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
"""启动代理测试(异步执行,通过 WebSocket 推送日志)。"""
|
|
cfg = proxy_service.get_or_create(db)
|
|
test_id, log_queue, loop = proxy_service.register_test()
|
|
|
|
thread = threading.Thread(
|
|
target=proxy_service.run_proxy_test,
|
|
args=(cfg, log_queue, loop),
|
|
daemon=True,
|
|
)
|
|
thread.start()
|
|
|
|
return {"test_id": test_id, "success": True}
|
|
|
|
|
|
@router.post("/whitelist/test")
|
|
async def test_whitelist(
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("whitelist:test")),
|
|
):
|
|
"""启动白名单测试(异步执行,通过 WebSocket 推送日志)。"""
|
|
cfg = proxy_service.get_or_create(db)
|
|
test_id, log_queue, loop = proxy_service.register_test()
|
|
|
|
thread = threading.Thread(
|
|
target=proxy_service.run_whitelist_test,
|
|
args=(cfg, log_queue, loop),
|
|
daemon=True,
|
|
)
|
|
thread.start()
|
|
|
|
return {"test_id": test_id, "success": True}
|