完成虎牙宝典WSS绑定与快照隔离重构

This commit is contained in:
yml2213
2026-09-01 12:40:22 +08:00
parent 24f312a3a9
commit 26514b332d
11 changed files with 181 additions and 24 deletions
@@ -0,0 +1,42 @@
"""按账号和活动隔离虎牙宝典商品快照。"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "20260901_0033"
down_revision: str | None = "20260831_0032"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def _columns(bind, table: str) -> set[str]:
return {item["name"] for item in sa.inspect(bind).get_columns(table)}
def upgrade() -> None:
bind = op.get_bind()
for table in ("huya_goods_snapshot", "huya_recharge_goods_snapshot"):
columns = _columns(bind, table)
if "account_id" not in columns:
op.add_column(table, sa.Column("account_id", sa.Integer(), nullable=True))
op.create_index(f"ix_{table}_account_id", table, ["account_id"])
if "sid" not in columns:
op.add_column(
table,
sa.Column("sid", sa.Integer(), nullable=False, server_default="0"),
)
op.create_index(f"ix_{table}_sid", table, ["sid"])
def downgrade() -> None:
bind = op.get_bind()
for table in ("huya_goods_snapshot", "huya_recharge_goods_snapshot"):
columns = _columns(bind, table)
if "sid" in columns:
op.drop_index(f"ix_{table}_sid", table_name=table)
op.drop_column(table, "sid")
if "account_id" in columns:
op.drop_index(f"ix_{table}_account_id", table_name=table)
op.drop_column(table, "account_id")
+4
View File
@@ -576,6 +576,8 @@ class HuyaGoodsSnapshot(Base):
__tablename__ = "huya_goods_snapshot"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
account_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
sid: Mapped[int] = mapped_column(Integer, default=0, index=True)
product_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
name: Mapped[str] = mapped_column(String(256), default="")
price: Mapped[int | None] = mapped_column(Integer, nullable=True)
@@ -592,6 +594,8 @@ class HuyaRechargeGoodsSnapshot(Base):
__tablename__ = "huya_recharge_goods_snapshot"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
account_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
sid: Mapped[int] = mapped_column(Integer, default=0, index=True)
spu_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
sku_id: Mapped[str] = mapped_column(String(64), default="", index=True)
name: Mapped[str] = mapped_column(String(256), default="")
+10 -8
View File
@@ -1823,8 +1823,11 @@ def list_goods(
current: User = Depends(require_permission("huya:task")),
):
"""查看已缓存的虎牙商品快照。"""
rows = db.query(HuyaGoodsSnapshot).order_by(HuyaGoodsSnapshot.id.asc()).all()
return rows
rows = db.query(HuyaGoodsSnapshot).order_by(HuyaGoodsSnapshot.id.desc()).all()
latest = {}
for row in rows:
latest.setdefault((row.sid, row.product_id), row)
return list(latest.values())
@router.get("/recharge-goods", response_model=list[HuyaRechargeGoodsOut])
@@ -1833,12 +1836,11 @@ def list_recharge_goods(
current: User = Depends(require_permission("huya:task")),
):
"""查看已缓存的虎牙充值商品快照。"""
rows = (
db.query(HuyaRechargeGoodsSnapshot)
.order_by(HuyaRechargeGoodsSnapshot.id.asc())
.all()
)
return rows
rows = db.query(HuyaRechargeGoodsSnapshot).order_by(HuyaRechargeGoodsSnapshot.id.desc()).all()
latest = {}
for row in rows:
latest.setdefault((row.sid, row.spu_id), row)
return list(latest.values())
@router.post("/tasks/batch")
+8
View File
@@ -551,6 +551,8 @@ class HuyaTaskOut(BaseModel):
class HuyaGoodsOut(BaseModel):
id: int
account_id: int | None = None
sid: int = 0
product_id: str
name: str = ""
price: int | None = None
@@ -564,6 +566,8 @@ class HuyaGoodsOut(BaseModel):
def _serialize(self) -> dict[str, Any]:
return {
"id": self.id,
"account_id": self.account_id,
"sid": self.sid,
"product_id": self.product_id,
"name": self.name,
"price": self.price,
@@ -575,6 +579,8 @@ class HuyaGoodsOut(BaseModel):
class HuyaRechargeGoodsOut(BaseModel):
id: int
account_id: int | None = None
sid: int = 0
spu_id: str
sku_id: str = ""
name: str = ""
@@ -594,6 +600,8 @@ class HuyaRechargeGoodsOut(BaseModel):
def _serialize(self) -> dict[str, Any]:
return {
"id": self.id,
"account_id": self.account_id,
"sid": self.sid,
"spu_id": self.spu_id,
"sku_id": self.sku_id,
"name": self.name,
+7 -11
View File
@@ -8,8 +8,6 @@ from typing import TYPE_CHECKING, Any
from sqlalchemy.orm import Session
from core.huya import HuyaHttpClient
from ..models import HuyaAccount, HuyaTask
HUYA_BIND_ROLE_POLL_SECONDS = 180
@@ -18,6 +16,9 @@ HUYA_BIND_ZT_UUID = "b02faae1"
HUYA_BIND_ROOM_ID = "30596253"
from .huya_runner_core import HUYA_RECHARGE_SOURCE_ID, HuyaBatchRunnerCore
if TYPE_CHECKING:
from core.huya import HuyaHttpClient
class BindMixin:
"""游戏角色绑定域:绑定状态机、扫码/确认绑定。"""
@@ -36,6 +37,7 @@ class BindMixin:
def _push_log(self, level: str, message: str) -> None: ...
def _mark_task(self, *args: Any, **kwargs: Any) -> None: ...
def _update_task_progress(self, *args: Any, **kwargs: Any) -> None: ...
def _activity_client(self, uid: int, cookie: str): ...
@staticmethod
def _role_name(bind_status) -> str:
@@ -315,9 +317,7 @@ class BindMixin:
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
return
client: Any = HuyaHttpClient(
logger=lambda msg: self._push_log("info", f"[{uid}] {msg}")
)
client: Any = self._activity_client(uid, cookie)
bind_status, bind_query_result = self._resolve_bind_status(
client=client,
uid=uid,
@@ -503,9 +503,7 @@ class BindMixin:
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
return
client: Any = HuyaHttpClient(
logger=lambda msg: self._push_log("info", f"[{uid}] {msg}")
)
client: Any = self._activity_client(uid, cookie)
bind_status, bind_query_result = self._resolve_bind_status(
client=client,
uid=uid,
@@ -577,9 +575,7 @@ class BindMixin:
self._mark_task(worker_db, task, "failed", "账号 Cookie 为空")
return
client: Any = HuyaHttpClient(
logger=lambda msg: self._push_log("info", f"[{uid}] {msg}")
)
client: Any = self._activity_client(uid, cookie)
role_status, role_query_result = self._resolve_bind_status(
client=client,
uid=uid,
+11 -2
View File
@@ -245,10 +245,15 @@ class GoodsMixin:
if item.get("product_id") and item.get("name")
]
now = datetime.now(UTC)
worker_db.query(HuyaGoodsSnapshot).delete(synchronize_session=False)
worker_db.query(HuyaGoodsSnapshot).filter(
HuyaGoodsSnapshot.account_id == account.id,
HuyaGoodsSnapshot.sid == sid_int,
).delete(synchronize_session=False)
for item in goods:
worker_db.add(
HuyaGoodsSnapshot(
account_id=account.id,
sid=sid_int,
product_id=item["product_id"],
name=item["name"],
price=item["price"],
@@ -298,7 +303,11 @@ class GoodsMixin:
snapshot = (
worker_db.query(HuyaGoodsSnapshot)
.filter(HuyaGoodsSnapshot.product_id == str(product_id))
.filter(
HuyaGoodsSnapshot.account_id == account.id,
HuyaGoodsSnapshot.sid == sid_int,
HuyaGoodsSnapshot.product_id == str(product_id),
)
.first()
)
product_name = str(
+11 -2
View File
@@ -310,10 +310,15 @@ class RechargeMixin:
}
goods.append(item)
worker_db.query(HuyaRechargeGoodsSnapshot).delete(synchronize_session=False)
worker_db.query(HuyaRechargeGoodsSnapshot).filter(
HuyaRechargeGoodsSnapshot.account_id == account.id,
HuyaRechargeGoodsSnapshot.sid == (self._to_int(config_info.get("sid")) or 2203),
).delete(synchronize_session=False)
for item in goods:
worker_db.add(
HuyaRechargeGoodsSnapshot(
account_id=account.id,
sid=self._to_int(config_info.get("sid")) or 2203,
spu_id=item["spu_id"],
sku_id=item["sku_id"],
name=item["name"],
@@ -382,7 +387,11 @@ class RechargeMixin:
snapshot = (
worker_db.query(HuyaRechargeGoodsSnapshot)
.filter(HuyaRechargeGoodsSnapshot.spu_id == spu_id)
.filter(
HuyaRechargeGoodsSnapshot.account_id == account.id,
HuyaRechargeGoodsSnapshot.sid == (self._to_int(config_info.get("sid")) or 2203),
HuyaRechargeGoodsSnapshot.spu_id == spu_id,
)
.first()
)
payload_sku_id = self._to_int(self.payload.get("sku_id"))