ForcePilot/backend/server/routers/webhook_router.py
Kris 66916f9b36 feat(channel): 添加渠道网关服务端路由和端点
新增全渠道网关的 API 路由层和网关端点。

主要变更:
- channel_router.py: 渠道管理 API 路由(CRUD、配置、绑定等)
- gateway_sse_router.py: SSE 网关端点
- gateway_ws_router.py: WebSocket 网关端点
- webhook_router.py: Webhook 回调路由
- auth_router.py: 认证路由更新
- routers/__init__.py: 路由注册更新
- main.py: 主入口更新
- lifespan.py: 应用生命周期更新,渠道扩展加载与卸载
2026-05-21 12:09:29 +08:00

57 lines
1.5 KiB
Python

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"}