"""群发消息路由。 端点: - POST /api/send/batch 提交群发任务 - GET /api/send/batch 列出最近 N 条群发任务 - GET /api/send/batch/{batch_id}/status 查询群发进度 - POST /api/send/batch/{batch_id}/cancel 取消群发 """ from __future__ import annotations import logging from fastapi import APIRouter, Request from woc_bridge.config import _require_batch_worker from woc_bridge.models import BridgeError, BatchSendRequest logger = logging.getLogger("woc-bridge") router = APIRouter(prefix="/api/send/batch", tags=["batch-send"]) @router.post("") async def submit_batch(req: BatchSendRequest, request: Request): """提交群发任务。 请求体:BatchSendRequest(targets / content / client_request_id / abort_on_consecutive_fail) 返回:{"success": True, "batch_id": str, "status": str, "status_query_url": str} 异常: - 400 INVALID_PARAMS:targets 超过单批上限 - 409 INVALID_PARAMS:batch_id 重复(批级幂等命中) - 429 RATE_LIMITED:日频次超限 / 批间隔不足 """ worker = _require_batch_worker() batch_id = await worker.submit_batch(req) status = await worker.get_status(batch_id) return { "success": True, "batch_id": batch_id, "status": status.status if status is not None else "pending", "status_query_url": f"/api/send/batch/{batch_id}/status", } @router.get("/{batch_id}/status") async def get_batch_status(batch_id: str): """查询群发进度。 返回 BatchSendStatus(含 total / processed / success / failed / skipped / progress / estimated_remaining_sec / items 等字段)。 异常: - 404 NOT_FOUND:batch_id 不存在 """ worker = _require_batch_worker() status = await worker.get_status(batch_id) if status is None: raise BridgeError( code="NOT_FOUND", message=f"batch_id={batch_id} 不存在", http_status=404, ) return status @router.post("/{batch_id}/cancel") async def cancel_batch(batch_id: str): """取消群发。 已处理条目保留结果,未处理条目标记 skipped。 异常: - 404 NOT_FOUND:batch_id 不存在或已完成 """ worker = _require_batch_worker() cancelled = await worker.cancel_batch(batch_id) if not cancelled: raise BridgeError( code="NOT_FOUND", message=f"batch_id={batch_id} 不存在或已完成", http_status=404, ) return {"success": True, "batch_id": batch_id, "status": "cancelled"} @router.get("") async def list_batches(limit: int = 20): """列出最近 N 条群发任务(按提交时间倒序)。 Query 参数: - limit:返回条数,1-100,默认 20 异常: - 400 INVALID_PARAMS:limit 越界 """ worker = _require_batch_worker() if limit < 1 or limit > 100: raise BridgeError( code="INVALID_PARAMS", message="limit 必须在 1-100 之间", http_status=400, ) batches = await worker.list_batches(limit) return {"batches": batches}