This commit is contained in:
2026-06-13 20:00:45 +08:00
parent 09f12c6c47
commit 2bcaab1626
6 changed files with 167 additions and 2 deletions
+72
View File
@@ -0,0 +1,72 @@
"""通知(お知らせ)路由:从 Redis 读取 worker 抓取的账号通知。
worker(pruchase_jhw)定时抓取骏河屋 action_news 页面,把每条通知按 data_id
作为 field 写入 Redis Hash(key 见 redis_keys.news_hash)。本路由读取该 Hash,
按 data_id 倒序(新→旧)返回,只读不删除。Redis 读取沿用 session_store 复用的连接,
与 scrape 路由保持一致。
"""
from __future__ import annotations
import json
import logging
from typing import Any
from fastapi import APIRouter, Depends, Query
from app.api.dependencies import get_container, require_bearer_token
from app.core.container import ServiceContainer
from app.models.scrape import ApiResponse, NewsItemData
from surugaya_common import redis_keys
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api", tags=["news"])
def _news_sort_key(item: dict[str, Any]) -> tuple[int, int]:
"""排序键:优先按 data_id 数值倒序,非数值退化到最小,保证排序稳定。"""
raw = str(item.get("data_id", "")).strip()
if raw.isdigit():
return (1, int(raw))
return (0, 0)
@router.get(
"/news",
response_model=ApiResponse[list[NewsItemData]],
dependencies=[Depends(require_bearer_token)],
)
async def list_news(
limit: int | None = Query(default=None, ge=1, le=500, description="返回条数上限,省略则返回全部"),
container: ServiceContainer = Depends(get_container),
) -> ApiResponse[list[NewsItemData]]:
"""读取通知列表(按 data_id 倒序,新→旧),只读不删除。"""
if container.session_store._redis is None:
return ApiResponse[list[NewsItemData]](
success=False,
msg="Redis 未配置",
data=None,
code=500,
)
# dev/prod 由本服务 app_env 推导,需与 worker 写入端(APP_ENV)保持一致。
is_dev = "1" if container.settings.app_env == "dev" else "0"
raw_map = await container.session_store._redis.hgetall(redis_keys.news_hash(is_dev))
items: list[dict[str, Any]] = []
for data_id, raw_value in raw_map.items():
try:
items.append(json.loads(raw_value))
except (json.JSONDecodeError, TypeError):
logger.warning("通知 data_id=%s 的 JSON 解析失败,已跳过。", data_id)
items.sort(key=_news_sort_key, reverse=True)
if limit is not None and limit > 0:
items = items[:limit]
return ApiResponse[list[NewsItemData]](
success=True,
msg="success",
data=[NewsItemData(**item) for item in items],
code=0,
)