fix(douyu): 精英宝典兑换等斗鱼任务接入代理 — 此前全部裸连
问题: DouyuBatchRunner/_client 创建的 DouyuActivityClient 无 proxies,
trust_env=False 下斗鱼任务(精英宝典兑换/和平小店/电竞/送礼等全部 45 个
请求点)直连本机出口 IP, 代理配置页形同虚设。
- activity_client: __init__ 支持 proxies (session 级, 一次覆盖全部请求)
- douyu_runner: 装载全局代理配置 (与 CK 检测/虎牙注册同源 代理配置页):
· 静态模式: 配置页手填 http/https → 全任务同一代理
· API 模式: 每任务从代理 API 取新代理 (ProxyFetcher, 含白名单同步,
1.5s 最小间隔防打爆), 失败降级直连并推送告警日志
- 验证: 77 单测 OK; 三种模式(静态/API/关闭)行为断言通过
This commit is contained in:
@@ -22,8 +22,9 @@ from core.douyu import (
|
||||
FishFinRechargeError,
|
||||
)
|
||||
|
||||
from core.douyu.proxy_fetcher import ProxyFetcher
|
||||
from ..database import SessionLocal
|
||||
from ..models import Account, DouyuEsportsGoodsSnapshot, DouyuGoodsSnapshot, DouyuTask, DouyuXpdGoodsSnapshot
|
||||
from ..models import Account, DouyuEsportsGoodsSnapshot, DouyuGoodsSnapshot, DouyuTask, DouyuXpdGoodsSnapshot, ProxyConfig as ProxyConfigModel
|
||||
from .douyu_service import (
|
||||
DOUYU_CONFIG_FIELDS,
|
||||
account_uid,
|
||||
@@ -72,6 +73,55 @@ class DouyuBatchRunner:
|
||||
self._stop = threading.Event()
|
||||
self._counter_lock = threading.Lock()
|
||||
self._started = 0
|
||||
# 代理接入 (与 CK 检测/虎牙注册同一配置源): 代理配置页开启后,
|
||||
# 斗鱼任务(含精英宝典兑换)的出网请求统一走代理, 不再裸连
|
||||
self._proxy_cfg = db.query(ProxyConfigModel).first() if db else None
|
||||
self._proxy_fetcher = self._create_proxy_fetcher()
|
||||
self._static_proxies = self._resolve_static_proxies()
|
||||
if self._static_proxies:
|
||||
logger.info(f"[douyu] 任务将走静态代理: {self._static_proxies.get('https','')}")
|
||||
elif self._proxy_fetcher:
|
||||
logger.info("[douyu] 任务将按任务从代理 API 取新代理")
|
||||
|
||||
def _create_proxy_fetcher(self) -> ProxyFetcher | None:
|
||||
"""API 代理模式: 每个任务从代理 API 取 1 个新代理 (与虎牙注册链同款)."""
|
||||
cfg = self._proxy_cfg
|
||||
if not cfg or not cfg.enabled or not cfg.api_url:
|
||||
return None
|
||||
wl_platform = getattr(cfg, "whitelist_platform", None) or "xiequ"
|
||||
wl_credentials = getattr(cfg, "whitelist_credentials", None)
|
||||
if not wl_credentials and getattr(cfg, "whitelist_uid", "") and getattr(cfg, "whitelist_ukey", ""):
|
||||
wl_credentials = {"uid": cfg.whitelist_uid, "ukey": cfg.whitelist_ukey}
|
||||
return ProxyFetcher(
|
||||
api_url=cfg.api_url,
|
||||
whitelist_platform=wl_platform,
|
||||
whitelist_credentials=wl_credentials if cfg.whitelist_enabled else None,
|
||||
stop_event=self._stop,
|
||||
)
|
||||
|
||||
def _resolve_static_proxies(self) -> dict[str, str] | None:
|
||||
"""静态代理模式: 代理配置页手填的 http/https 地址."""
|
||||
cfg = self._proxy_cfg
|
||||
if not cfg or not cfg.enabled:
|
||||
return None
|
||||
http, https = (cfg.http or "").strip(), (cfg.https or "").strip()
|
||||
if not http and not https:
|
||||
return None
|
||||
return {"http": http or https, "https": https or http}
|
||||
|
||||
def _proxies_for_task(self) -> dict[str, str] | None:
|
||||
"""取本任务出网代理: 静态优先; API 模式每任务取新代理, 失败降级直连并告警."""
|
||||
if self._static_proxies:
|
||||
return self._static_proxies
|
||||
if self._proxy_fetcher:
|
||||
try:
|
||||
proxy_url = self._proxy_fetcher.fetch_new_proxy()
|
||||
if proxy_url:
|
||||
return {"http": proxy_url, "https": proxy_url}
|
||||
self._push_log("warning", "代理 API 未返回可用代理, 本任务降级直连")
|
||||
except Exception as exc:
|
||||
self._push_log("warning", f"取代理失败, 本任务降级直连: {exc}")
|
||||
return None
|
||||
|
||||
def stop(self):
|
||||
self._stop.set()
|
||||
@@ -876,7 +926,12 @@ class DouyuBatchRunner:
|
||||
return {**payload, **self.payload}
|
||||
|
||||
def _client(self, cookie: str) -> DouyuActivityClient:
|
||||
return DouyuActivityClient(cookie, logger=lambda msg: self._push_log("debug", msg))
|
||||
"""任务 HTTP 客户端: 会话级代理 (覆盖精英宝典/和平小店/电竞等全部请求)."""
|
||||
return DouyuActivityClient(
|
||||
cookie,
|
||||
logger=lambda msg: self._push_log("debug", msg),
|
||||
proxies=self._proxies_for_task(),
|
||||
)
|
||||
|
||||
def _fetch_bind_info_candidates(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user