mirror of
https://github.com/MemeMeow-Studio/MemeMeow.git
synced 2026-10-26 03:39:24 +08:00
74 lines
3.2 KiB
Python
74 lines
3.2 KiB
Python
"""缩略图 reconciliation 的公共 HTTP 边界。
|
|
|
|
本模块位于 FastAPI 路由模板与 scope-bound 缩略图服务之间,只处理管理凭据、请求
|
|
参数和稳定错误投影;当前 scope、服务装配和路由错误工厂均由入口显式注入。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
from fastapi import HTTPException, Request
|
|
|
|
from backend.persistence.engine import DatabaseError
|
|
from backend.services.thumbnails import ThumbnailError
|
|
|
|
|
|
ThumbnailServiceProvider = Callable[[Request], Any]
|
|
AuthorizeProvider = Callable[[Request, str | None], None]
|
|
ErrorFactory = Callable[[int, str, str], HTTPException]
|
|
|
|
|
|
def _reconcile_error(exc: ThumbnailError, *, error: ErrorFactory) -> HTTPException:
|
|
"""把 reconciliation 的领域异常压缩成稳定 HTTP 错误。"""
|
|
if exc.code == "thumbnail_backpressure":
|
|
return error(429, "thumbnail_backpressure", "缩略图任务队列已满,请稍后重试")
|
|
if exc.code in {"thumbnail_task_unavailable", "thumbnail_generation_unavailable"}:
|
|
return error(503, "thumbnail_reconcile_unavailable", "缩略图回填服务当前不可用")
|
|
return error(500, "thumbnail_reconcile_failed", "缩略图回填失败")
|
|
|
|
|
|
async def reconcile_thumbnails(
|
|
request: Request,
|
|
*,
|
|
page: int,
|
|
page_size: int | None,
|
|
limit: int | None,
|
|
token: str | None,
|
|
thumbnail_service: ThumbnailServiceProvider,
|
|
authorize: AuthorizeProvider,
|
|
error: ErrorFactory,
|
|
) -> dict[str, int]:
|
|
"""在当前可信 scope 内分页提交缩略图回填任务。
|
|
|
|
输入是已由 FastAPI 校验的分页参数和 Settings 管理 token;输出是服务返回的
|
|
扫描、提交、可用和失败计数。调用场景是受保护的存量图片 reconciliation 入口,
|
|
不接受客户端 scope、路径或内部派生 key。
|
|
"""
|
|
authorize(request, token)
|
|
unknown = set(request.query_params) - {"page", "page_size", "limit"}
|
|
if unknown:
|
|
raise error(400, "invalid_request", "缩略图回填只接受 page、page_size 和 limit")
|
|
service = thumbnail_service(request)
|
|
if service is None or not callable(getattr(service, "reconcile", None)):
|
|
raise error(503, "thumbnail_reconcile_unavailable", "缩略图回填服务当前不可用")
|
|
try:
|
|
result = service.reconcile(page=page, page_size=page_size, limit=limit)
|
|
except ThumbnailError as exc:
|
|
raise _reconcile_error(exc, error=error) from exc
|
|
except (DatabaseError, RuntimeError, ValueError) as exc:
|
|
raise error(503, "thumbnail_reconcile_unavailable", "缩略图回填服务当前不可用") from exc
|
|
if not isinstance(result, dict) or not {"scanned", "submitted", "available", "failed"} <= set(result):
|
|
raise error(503, "thumbnail_reconcile_unavailable", "缩略图回填服务返回了无效结果")
|
|
counts: dict[str, int] = {}
|
|
for key in ("scanned", "submitted", "available", "failed"):
|
|
value = result[key]
|
|
if type(value) is not int or value < 0:
|
|
raise error(503, "thumbnail_reconcile_unavailable", "缩略图回填服务返回了无效结果")
|
|
counts[key] = value
|
|
return counts
|
|
|
|
|
|
__all__ = ["reconcile_thumbnails"]
|