通知
This commit is contained in:
@@ -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,
|
||||
)
|
||||
Reference in New Issue
Block a user