Files
live-hub-py/web/backend/routers/proxy.py
T
yml2213 2ab6724543 refactor: 补全services层+消除core/models.py冗余+修复network.py缩进错误
高优先级问题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赋值语句)
2026-06-23 07:34:17 +08:00

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}