fix(huya): 查询积分改走积分中心新接口(含成长等级)
旧活动接口 webActUI.getUserScore 对任何 sid 都返回 603「活动已结束」 (接口已下线,与工作台 SID/活动配置无关),刷新积分只会报错。 - 协议层新增两个 RPC(WSS + HTTP 双侧同签名): shopMiddleUI.getRedeemNeedGoods(tag2=当前积分、tag3=兑换门槛, 兑换商品号 POINTS_REDEEM_GOODS_NUM=8315982,传错直接 500) 与 GameBizUI.getGrowLevelUserInfo(成长值/成长等级/昵称/头像) - 新增结构体 GetRedeemNeedGoodsReq / GetGrowLevelUserInfoReq, 与 HuyaEliteWssSession 透传 - 服务层 _execute_query_points 主源改为积分中心接口,结果带 points/redeem_threshold/grow_level/grow_value,并同步 account.points; 接口无响应时才回退旧活动接口并如实报告其 603 返回 - 开通支付成功后的积分刷新同样改走积分中心接口 - 前端任务页积分结果优先读 points(兼容旧记录的 available_score), 并在有成长等级时一并展示 - 新增 tests/test_huya_points_query.py:真机响应字节回归 + 请求参数 字面量断言 + 服务层积分来源/回退语义(已做反向验证) 真机验证:HTTP 通道取到积分 280 / 门槛 20 / 成长等级 3
This commit is contained in:
@@ -8,6 +8,8 @@ from typing import TYPE_CHECKING, Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.huya.wss_client import POINTS_REDEEM_GOODS_NUM
|
||||
|
||||
from ..models import HuyaAccount, HuyaGoodsSnapshot, HuyaTask
|
||||
|
||||
|
||||
@@ -26,6 +28,7 @@ class GoodsMixin:
|
||||
def _resolve_uid(self, account_info: dict) -> int: ...
|
||||
def _push_log(self, level: str, message: str) -> None: ...
|
||||
def _activity_client(self, uid: int, cookie: str): ...
|
||||
def _shop_client(self, uid: int, cookie: str): ...
|
||||
def _mark_task(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
def _wait_until(self, when: datetime, uid: int) -> bool: ...
|
||||
def _parse_scheduled_time(self, value: Any) -> datetime | None: ...
|
||||
@@ -90,16 +93,13 @@ class GoodsMixin:
|
||||
account_info: dict,
|
||||
config_info: dict,
|
||||
):
|
||||
sid = str(self.payload.get("sid") or config_info.get("sid") or "").strip()
|
||||
if not sid:
|
||||
self._mark_task(worker_db, task, "failed", "请先配置虎牙活动 SID")
|
||||
return
|
||||
|
||||
sid_int = self._to_int(sid)
|
||||
if not sid_int:
|
||||
self._mark_task(worker_db, task, "failed", f"虎牙活动 SID 无效: {sid}")
|
||||
return
|
||||
"""查询积分:主源是积分中心的 shopMiddleUI.getRedeemNeedGoods。
|
||||
|
||||
2026-10-15 真机实测:旧活动接口 webActUI.getUserScore 对任何 sid 都返回
|
||||
603「活动已结束」(该接口已下线,与配置无关);积分中心接口返回
|
||||
``tag2``=当前积分、``tag3``=兑换门槛积分,另可顺手取 GameBizUI
|
||||
的成长值/成长等级。
|
||||
"""
|
||||
uid = self._resolve_uid(account_info)
|
||||
if not uid:
|
||||
self._mark_task(worker_db, task, "failed", "无法从账号或 Cookie 解析 yyuid")
|
||||
@@ -110,10 +110,76 @@ class GoodsMixin:
|
||||
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
|
||||
return
|
||||
|
||||
goods_num = (
|
||||
self._to_int(self.payload.get("goods_num")) or POINTS_REDEEM_GOODS_NUM
|
||||
)
|
||||
client: Any = self._shop_client(uid, cookie)
|
||||
redeem = client.get_redeem_need_goods(
|
||||
uid=uid, guid="", cookie=cookie, goods_num=goods_num
|
||||
)
|
||||
if redeem is None:
|
||||
self._query_points_legacy(
|
||||
worker_db, task, account, uid, cookie, config_info
|
||||
)
|
||||
return
|
||||
|
||||
result = redeem.to_dict()
|
||||
result["goods_num"] = goods_num
|
||||
if redeem.code != 200:
|
||||
self._mark_task(
|
||||
worker_db,
|
||||
task,
|
||||
"failed",
|
||||
redeem.message or f"虎牙积分查询失败: {redeem.code}",
|
||||
result,
|
||||
)
|
||||
return
|
||||
|
||||
points = self._to_int(redeem.value("tag2"))
|
||||
result["points"] = points
|
||||
result["redeem_threshold"] = self._to_int(redeem.value("tag3"))
|
||||
growth = client.get_grow_level_user_info(uid=uid, guid="", cookie=cookie)
|
||||
if growth is not None and growth.code == 0:
|
||||
result["grow_value"] = self._to_int(growth.value("tag1", "tag0"))
|
||||
result["grow_level"] = self._to_int(growth.value("tag1", "tag1"))
|
||||
result["nickname"] = growth.value("tag2") or ""
|
||||
|
||||
account.points = points
|
||||
account.status = "points_queried"
|
||||
account.updated_at = datetime.now(UTC)
|
||||
self._mark_task(worker_db, task, "success", f"积分: {points}", result)
|
||||
|
||||
def _query_points_legacy(
|
||||
self,
|
||||
worker_db: Session,
|
||||
task: HuyaTask,
|
||||
account: HuyaAccount,
|
||||
uid: int,
|
||||
cookie: str,
|
||||
config_info: dict,
|
||||
):
|
||||
"""积分中心接口没有响应时回退旧活动接口,并如实报告旧接口的返回。"""
|
||||
sid = str(self.payload.get("sid") or config_info.get("sid") or "").strip()
|
||||
if not sid:
|
||||
self._mark_task(
|
||||
worker_db, task, "error", "积分中心接口无响应,且未配置可回退的活动 SID"
|
||||
)
|
||||
return
|
||||
|
||||
sid_int = self._to_int(sid)
|
||||
if not sid_int:
|
||||
self._mark_task(worker_db, task, "failed", f"虎牙活动 SID 无效: {sid}")
|
||||
return
|
||||
|
||||
client: Any = self._activity_client(uid, cookie)
|
||||
response = client.query_user_score(uid=uid, cookie=cookie, sid=sid_int)
|
||||
if response is None:
|
||||
self._mark_task(worker_db, task, "error", "虎牙积分接口无响应")
|
||||
self._mark_task(
|
||||
worker_db,
|
||||
task,
|
||||
"error",
|
||||
"虎牙积分接口无响应(积分中心与旧活动接口均失败)",
|
||||
)
|
||||
return
|
||||
|
||||
result = response.to_dict()
|
||||
@@ -123,7 +189,8 @@ class GoodsMixin:
|
||||
worker_db,
|
||||
task,
|
||||
"failed",
|
||||
response.msg or f"虎牙积分查询失败: {response.status}",
|
||||
f"积分中心接口无响应;旧活动接口(sid={sid_int})返回 "
|
||||
f"{response.status} {response.msg}".strip(),
|
||||
result,
|
||||
)
|
||||
return
|
||||
@@ -132,7 +199,9 @@ class GoodsMixin:
|
||||
account.points = points
|
||||
account.status = "points_queried"
|
||||
account.updated_at = datetime.now(UTC)
|
||||
self._mark_task(worker_db, task, "success", f"积分: {points}", result)
|
||||
self._mark_task(
|
||||
worker_db, task, "success", f"积分: {points}(旧活动接口)", result
|
||||
)
|
||||
|
||||
def _execute_query_exchange_records(
|
||||
self,
|
||||
|
||||
@@ -506,12 +506,12 @@ class RechargeMixin:
|
||||
account.updated_at = datetime.now(UTC)
|
||||
if payment_status == "paid":
|
||||
account.status = "recharge_paid"
|
||||
post_score = client.query_user_score(
|
||||
uid=uid, cookie=cookie, sid=self._to_int(config_info.get("sid")) or 2203
|
||||
)
|
||||
if post_score is not None:
|
||||
result["post_payment_score"] = post_score.to_dict()
|
||||
account.points = post_score.available_score
|
||||
# 支付后刷新积分:旧活动接口 getUserScore 已下线(603 活动已结束),
|
||||
# 改走积分中心 getRedeemNeedGoods(tag2 = 当前积分)。
|
||||
post_redeem = client.get_redeem_need_goods(uid=uid, guid="", cookie=cookie)
|
||||
if post_redeem is not None and post_redeem.code == 200:
|
||||
result["post_payment_points"] = self._to_int(post_redeem.value("tag2"))
|
||||
account.points = result["post_payment_points"]
|
||||
paid_message = f"支付成功: {product_name} x{count} {result['amount_text']}"
|
||||
if payment_order and payment_order.get("pay_time"):
|
||||
paid_message += f",支付时间 {self._format_local_time(int(payment_order['pay_time']) // 1000)}"
|
||||
|
||||
@@ -1136,9 +1136,11 @@ export default function HuyaTasksPage() {
|
||||
return <Text type="secondary">-</Text>;
|
||||
}
|
||||
|
||||
const availableScore = value?.available_score;
|
||||
if (typeof availableScore === 'number') {
|
||||
return <Tag color="blue">可用积分 {availableScore}</Tag>;
|
||||
// 积分结果:新版走积分中心(points),旧任务记录里是活动接口的 available_score
|
||||
const points = typeof value?.points === 'number' ? value.points : value?.available_score;
|
||||
if (typeof points === 'number') {
|
||||
const level = value?.grow_level;
|
||||
return <Tag color="blue">可用积分 {points}{typeof level === 'number' ? ` · 等级 ${level}` : ''}</Tag>;
|
||||
}
|
||||
|
||||
return value ? <Text code style={{ fontSize: 12 }}>{JSON.stringify(value)}</Text> : <Text type="secondary">-</Text>;
|
||||
|
||||
Reference in New Issue
Block a user