WechatOnCloud/bridge/woc_bridge/routes/batch.py
Kris c45282f094 feat: 新增好友自动通过、UI自动化能力与多分辨率适配
- 新增登录状态守卫后台任务
- 新增好友申请自动通过规则引擎
- 新增多分辨率UI配置与模板资源
- 新增消息拉取复合游标支持
- 优化发送队列与UI自动化逻辑
- 新增批量发送日志与错误处理
- 优化Docker镜像构建与ptrace初始化
- 新增联系人名称缓存预热
2026-07-17 18:10:31 +08:00

139 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""群发消息路由。
端点:
- 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
import time
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):
"""提交群发任务。
请求体BatchSendRequesttargets / content / client_request_id / abort_on_consecutive_fail
返回:{"success": True, "batch_id": str, "status": str, "status_query_url": str}
异常:
- 400 INVALID_PARAMStargets 超过单批上限
- 409 INVALID_PARAMSbatch_id 重复(批级幂等命中)
- 429 RATE_LIMITED日频次超限 / 批间隔不足
"""
worker = _require_batch_worker()
t_total = time.perf_counter()
logger.info(
"send/batch: 收到请求 targets=%d content_len=%d client_request_id=%s",
len(req.targets), len(req.content), req.client_request_id or "(none)",
)
try:
batch_id = await worker.submit_batch(req)
except BridgeError as e:
logger.warning(
"send/batch: 提交失败 %s: %s",
e.code, e.message,
)
raise
status = await worker.get_status(batch_id)
logger.info(
"send/batch: ✓ batch_id=%s targets=%d (总耗时 %.0fms)",
batch_id, len(req.targets), (time.perf_counter() - t_total) * 1000,
)
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_FOUNDbatch_id 不存在
"""
logger.debug("send/batch/status: 查询 batch_id=%s", 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_FOUNDbatch_id 不存在或已完成
"""
logger.info("send/batch/cancel: 收到请求 batch_id=%s", batch_id)
worker = _require_batch_worker()
try:
cancelled = await worker.cancel_batch(batch_id)
except BridgeError as e:
logger.warning(
"send/batch/cancel: 失败 %s: %s (batch_id=%s)",
e.code, e.message, batch_id,
)
raise
if not cancelled:
logger.warning(
"send/batch/cancel: 失败 NOT_FOUND: batch_id 不存在或已完成 (batch_id=%s)",
batch_id,
)
raise BridgeError(
code="NOT_FOUND",
message=f"batch_id={batch_id} 不存在或已完成",
http_status=404,
)
logger.info("send/batch/cancel: ✓ batch_id=%s", batch_id)
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_PARAMSlimit 越界
"""
logger.debug("send/batches: 列表查询 limit=%d", 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}