fix(huya): 精英宝典绑定二维码对齐最新抓包并支持配置 bind_gid

This commit is contained in:
yml2213
2026-11-09 21:01:42 +08:00
parent 7282787398
commit 5f1d78e1e4
16 changed files with 446 additions and 80 deletions
+182 -1
View File
@@ -18,6 +18,7 @@ from core.huya.shop_structs import ShopRawRsp
from web.backend.models import HuyaAccount
from web.backend.services.huya_pay_link import PayTargets, pay_qr_path
from web.backend.services.huya_runner import HuyaBatchRunner
from web.backend.services.huya_runner_bind import BindMixin
UID = 1199668595203
COOKIE = f"yyuid={UID}; udb_uid={UID}"
@@ -155,6 +156,7 @@ class _FakeBindResponse:
self.status = status
self.msg = msg
self.gameName = "和平精英"
self.gameAuthScene = ""
self.changeBindDay = 7
self.accountData = _FakeBindAccountData(nick, role_name)
@@ -787,8 +789,10 @@ def test_query_game_name_uses_new_probe_params_and_saves_role(monkeypatch):
"uid": UID,
"cookie": COOKIE,
"b_act_id": 9271,
"is_use_outer_act_id": 1,
"gid": 0,
"outer_act_id": "17096",
"is_use_outer_act_id": 1,
"scene": "",
"timeout": 15.0,
}
]
@@ -862,3 +866,180 @@ def test_shop_client_falls_back_to_http_when_wss_init_fails(monkeypatch):
assert logs and logs[-1][0] == "warning"
assert "WSS 会话不可用" in logs[-1][1]
assert "sdid" not in json.dumps(logs[-1][1]) # 日志不带 Cookie 值
class _FakeConfirmResponse:
def __init__(self, status: int = 200, msg: str = ""):
self.status = status
self.msg = msg
def to_dict(self) -> dict:
return {"status": self.status, "msg": self.msg}
class _BindConfirmClient:
def __init__(self):
self.check_calls: list[dict] = []
self.confirm_calls: list[dict] = []
def check_user_bind_game_account(self, **kwargs):
self.check_calls.append(kwargs)
return _FakeBindResponse()
def confirm_bind_act_account(self, **kwargs):
self.confirm_calls.append(kwargs)
return _FakeConfirmResponse()
class _FakeLiveLink:
def __init__(self):
self.status = 200
self.msg = ""
self.livelinkParam = {
"actId": 17096,
"code": "code",
"gameIdList": "cjm",
"livePlatId": "huya",
"sig": "sig",
"t": "t",
}
def to_log_dict(self) -> dict:
return {"status": self.status}
class _BindQrClient:
def __init__(self):
self.check_calls: list[dict] = []
self.live_link_calls: list[dict] = []
self.qrcode_calls: list[str] = []
def check_user_bind_game_account(self, **kwargs):
self.check_calls.append(kwargs)
return _FakeBindResponse()
def get_live_link_param(self, **kwargs):
self.live_link_calls.append(kwargs)
return _FakeLiveLink()
def get_user_profile_batch(self, **kwargs):
return None
def build_bind_urls(self, _param, _b_act_id, **kwargs):
return {"qr_url": "https://livelink.example/qr"}
def get_livelink_mini_qrcode(self, url):
self.qrcode_calls.append(url)
return {
"mini_qrcode_image": "base64-image",
"qrcode_token": "token",
}
def _task_runner(monkeypatch, task_type: str):
runner = HuyaBatchRunner(db=None, batch_id="test-batch", task_type=task_type)
marks: list[tuple[str, str, dict | None]] = []
monkeypatch.setattr(
runner,
"_mark_task",
lambda _db, _task, status, message, result=None: marks.append(
(status, message, result)
),
raising=False,
)
monkeypatch.setattr(
runner,
"_update_task_progress",
lambda *_args, **_kwargs: None,
raising=False,
)
return runner, marks
def test_bind_protocol_prefers_configured_gid_and_keeps_legacy_fallback():
"""精英宝典绑定可配置 gid;旧配置没填 gid 时保持 9271 协议。"""
assert BindMixin._bind_protocol({"bind_gid": "3203", "outer_act_id": "17096"}) == {
"bind_gid": "3203",
"b_act_id": 0,
"gid": 3203,
"outer_act_id": "17096",
"is_use_outer_act_id": 0,
"scene": "undefined",
}
assert BindMixin._bind_protocol({"bind_act_id": "9271"}) == {
"bind_gid": "",
"b_act_id": 9271,
"gid": 0,
"outer_act_id": "",
"is_use_outer_act_id": 1,
"scene": "",
}
def test_confirm_bind_uses_latest_har_protocol(monkeypatch):
"""确认绑定复用抓包里的 gid=3203 / bActId=0 / outerActId=17096。"""
client = _BindConfirmClient()
runner, marks = _task_runner(monkeypatch, "confirm_bind")
monkeypatch.setattr(runner, "_activity_client", lambda uid, cookie: client)
account = HuyaAccount(uid=str(UID), cookie=COOKIE)
runner._execute_confirm_bind(
None,
None,
account,
{"uid": UID, "cookie": COOKIE},
{"bind_gid": "3203", "outer_act_id": "17096"},
)
assert marks[-1][0] == "success"
assert client.confirm_calls == [
{
"uid": UID,
"cookie": COOKIE,
"b_act_id": 0,
"gid": 3203,
"outer_act_id": "17096",
}
]
assert all(
call["b_act_id"] == 0
and call["gid"] == 3203
and call["outer_act_id"] == "17096"
and call["is_use_outer_act_id"] == 0
and call["scene"] == "undefined"
for call in client.check_calls
)
def test_get_bind_qr_uses_latest_har_protocol(monkeypatch):
"""获取二维码的完整链路与 2026-11 抓包参数一致。"""
client = _BindQrClient()
runner, marks = _task_runner(monkeypatch, "get_bind_qr")
monkeypatch.setattr(runner, "_activity_client", lambda uid, cookie: client)
runner._stop.set()
account = HuyaAccount(uid=str(UID), cookie=COOKIE)
runner._execute_get_bind_qr(
None,
None,
account,
{"uid": UID, "cookie": COOKIE},
{"bind_gid": "3203", "outer_act_id": "17096"},
)
assert marks[-1][2]["gid"] == 3203
assert marks[-1][2]["bind_gid"] == "3203"
assert client.live_link_calls == [
{
"uid": UID,
"cookie": COOKIE,
"b_act_id": 0,
"gid": 3203,
"outer_act_id": 17096,
"game_auth_scene": "",
}
]
assert client.check_calls[0]["b_act_id"] == 0
assert client.check_calls[0]["gid"] == 3203
assert client.check_calls[0]["is_use_outer_act_id"] == 0
assert client.check_calls[0]["scene"] == "undefined"
+4 -1
View File
@@ -258,7 +258,10 @@ def test_query_points_uses_http_and_prechecks_ck_with_new_probe(monkeypatch):
"uid": UID,
"cookie": COOKIE,
"b_act_id_int": 9271,
"outer_act_id": "17096",
"outer_act_id": "",
"gid": 0,
"is_use_outer_act_id": 1,
"scene": "",
}
]
assert marks[-1][0] == "success"
+1 -1
View File
@@ -26,7 +26,7 @@ TESTS_DIR = Path(__file__).resolve().parent
PROJECT_ROOT = TESTS_DIR.parent
VERSIONS_DIR = PROJECT_ROOT / "web" / "backend" / "migrations" / "versions"
HEAD_REVISION = "20261108_0074"
HEAD_REVISION = "20261109_0075"
# 迁移新增、但不声明在模型里的复合查询索引。
EXTRA_INDEXES = (