fix(huya): 精英宝典绑定二维码对齐最新抓包并支持配置 bind_gid
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
Reference in New Issue
Block a user