import logging from fastapi import APIRouter, Request, Response from yuxi.channel.gateway.routes import webhook_registry logger = logging.getLogger(__name__) router = APIRouter(prefix="/webhook", tags=["webhook"]) def _extract_signature(headers: dict[str, str]) -> str | None: sig = headers.get("x-hub-signature-256") or headers.get("x-signature") if sig and sig.startswith("sha256="): sig = sig[7:] return sig @router.api_route( "/{channel_type}", methods=["POST", "PUT", "PATCH"], summary="接收渠道 Webhook 回调", ) async def webhook_receive( channel_type: str, request: Request, ): body = await request.body() method = request.method content_type = request.headers.get("content-type") headers = {k.lower(): v for k, v in request.headers.items()} guard_result, handler_result = await webhook_registry.dispatch_guarded( channel_type=channel_type, method=method, content_type=content_type, body=body, signature=_extract_signature(headers), extra_headers=headers, ) if guard_result is not None: logger.warning( "Webhook guard blocked: channel=%s method=%s status=%d error=%s", channel_type, method, guard_result.http_status, guard_result.error_code, ) return Response( content=guard_result.error_message or "", status_code=guard_result.http_status, media_type="text/plain", ) return handler_result or {"status": "ok"}