完善虎牙积分查询日志

This commit is contained in:
yml2213
2026-07-04 17:57:33 +08:00
parent 56ffaf531c
commit 3b88653e5d
3 changed files with 54 additions and 16 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ class ActivityUserId(TafStruct):
self.lUid: int = 0
self.sGuid: str = ""
self.sToken: str = ""
self.sHuYaUA: str = "web&1.0&huya"
self.sHuYaUA: str = "webh5&0.0.1&websocket&&diypc_52775"
self.sCookie: str = ""
self.iTokenType: int = 0
self.sDeviceInfo: str = ""
+48 -14
View File
@@ -42,7 +42,7 @@ class WSConnectParaInfo(TafStruct):
def __init__(self):
self.lUid: int = 0
self.sGuid: str = ""
self.sUA: str = "webh5&0.0.1&websocket&&diypc_52775"
self.sUA: str = HTTP_HUYA_UA
self.sAppSrc: str = "HUYA&ZH&2052"
self.sMid: str = ""
self.sExp: str = ""
@@ -53,7 +53,7 @@ class WSConnectParaInfo(TafStruct):
self.mCustomHeaders: dict = {}
def write_to(self, os: TafOutputStream):
# 与浏览器一致: 空字符串也写 (HAR 实证 tag4/5/7/8 都写了空串)
# 与浏览器一致: 可为空的字段也显式写入。
if self.lUid:
os.write_int64(0, self.lUid)
else:
@@ -70,7 +70,17 @@ class WSConnectParaInfo(TafStruct):
os.write_map(10, self.mCustomHeaders)
def read_from(self, ins: TafInputStream):
pass
self.lUid = ins.read_int64(0, default=self.lUid)
self.sGuid = ins.read_string(1, default=self.sGuid)
self.sUA = ins.read_string(2, default=self.sUA)
self.sAppSrc = ins.read_string(3, default=self.sAppSrc)
self.sMid = ins.read_string(4, default=self.sMid)
self.sExp = ins.read_string(5, default=self.sExp)
self.iTokenType = ins.read_int32(6, default=self.iTokenType)
self.sToken = ins.read_string(7, default=self.sToken)
self.sCookie = ins.read_string(8, default=self.sCookie)
self.sTraceId = ins.read_string(9, default=self.sTraceId)
self.mCustomHeaders = ins.read_map(10)
def _gen_trace_id() -> str:
@@ -84,20 +94,16 @@ def generate_http_baseinfo(uid: int, guid: str, cookie: str,
"""
构造 HTTP POST 的 baseinfo URL 参数
HAR 实证: getGoodsInfoV5 的 baseinfo lUid=0, sCookie="" (身份靠 Wup body 的 userId.sCookie)
HAR 实证: 当前 cdnws HTTP RPC 的 baseinfo 会带 lUid 和完整 Cookie
"""
info = WSConnectParaInfo()
info.lUid = 0 # HAR 实证: baseinfo 里 lUid=0
info.lUid = int(uid or 0)
info.sGuid = guid
info.sUA = "webh5&0.0.1&websocket&&diypc_52775"
info.sUA = HTTP_HUYA_UA
info.sAppSrc = "HUYA&ZH&2052"
info.sCookie = "" # HAR 实证: baseinfo 不带 cookie, cookie 在 Wup body
info.sCookie = cookie or ""
info.sTraceId = trace_id or _gen_trace_id()
os = TafOutputStream()
os.write_struct_begin(0) # WSConnectParaInfo 是顶层 struct? 实际 baseinfo 是裸 struct 字段
# 实际 HAR baseinfo 解码: 顶层直接是字段(tag0 lUid...), 不包 STRUCT_BEGIN
# 重置, 不写 STRUCT_BEGIN
os = TafOutputStream()
info.write_to(os)
raw = os.get_bytes()
@@ -168,7 +174,7 @@ class HuyaHttpClient:
from .activity_structs import ActivityUserId
user = ActivityUserId()
user.lUid = uid
user.sHuYaUA = "web&1.0&huya"
user.sHuYaUA = HTTP_HUYA_UA
user.sCookie = cookie or ""
return user
@@ -184,7 +190,7 @@ class HuyaHttpClient:
method: 方法名 (getGoodsInfoV5)
req_struct: 请求结构体 (TafStruct)
rsp_class: 响应类
uid/guid/cookie: 用于构造 baseinfo (cookie 主要放 Wup body)
uid/guid/cookie: 用于构造 baseinfo,业务请求体也会按各接口需要携带
"""
# 1. 构造 Wup 请求体
wup = WupRequest()
@@ -199,7 +205,7 @@ class HuyaHttpClient:
url = f"https://{CDNWS_HOST}/?baseinfo={baseinfo}"
self.logger(f"[HTTP] POST {service}.{method}")
self.logger(f"[HTTP] URL: {url[:100]}...")
self.logger(f"[HTTP] URL: https://{CDNWS_HOST}/?baseinfo=<redacted>")
self.logger(f"[HTTP] 发送 body: {len(wup_data)} 字节, hex前60: {wup_data[:60].hex()}")
# 3. POST
@@ -239,6 +245,9 @@ class HuyaHttpClient:
result = wup_resp.readStruct("tRsp", rsp_class)
if result is None:
result = wup_resp.readStruct("tResp", rsp_class)
if result is not None and hasattr(result, "to_dict"):
decoded = json.dumps(result.to_dict(), ensure_ascii=False, separators=(",", ":"))
self.logger(f"[HTTP] 解码 tRsp: {decoded}")
return result
# ---------- 业务便捷方法 ----------
@@ -381,3 +390,28 @@ class HuyaHttpClient:
if result is None:
result = wup_resp.readStruct("tResp", PayOrderRes)
return result
def _self_check():
uid = 1199647239697
cookie = "yyuid=1199647239697; udb_passport=test"
trace_id = "0123456789abcdef:0123456789abcdef:0:0"
encoded = generate_http_baseinfo(uid, "", cookie, trace_id=trace_id)
raw = base64.b64decode(urllib.parse.unquote(encoded))
parsed = WSConnectParaInfo()
parsed.read_from(TafInputStream(raw))
assert parsed.lUid == uid
assert parsed.sUA == HTTP_HUYA_UA
assert parsed.sCookie == cookie
assert parsed.sTraceId == trace_id
user = HuyaHttpClient._build_activity_user(uid, cookie)
assert user.sHuYaUA == HTTP_HUYA_UA
assert user.sCookie == cookie
if __name__ == "__main__":
_self_check()
+5 -1
View File
@@ -6,6 +6,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timezone
from typing import Optional
from loguru import logger
from sqlalchemy.orm import Session, joinedload
from core.huya import HuyaHttpClient
@@ -42,6 +43,9 @@ class HuyaBatchRunner:
self._stop.set()
def _push_log(self, level: str, message: str):
if level != "result" and message:
log_func = getattr(logger, level, logger.info)
log_func(f"[huya] {message}")
if self.log_queue and self.loop:
asyncio.run_coroutine_threadsafe(
self.log_queue.put({"level": level, "message": message}),
@@ -113,7 +117,7 @@ class HuyaBatchRunner:
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
return
client = HuyaHttpClient(logger=lambda _msg: None)
client = HuyaHttpClient(logger=lambda msg: self._push_log("info", f"[{uid}] {msg}"))
response = client.query_user_score(uid=uid, cookie=cookie, sid=sid_int)
if response is None:
self._mark_task(worker_db, task, "error", "虎牙积分接口无响应")