Первоначальная версия VidConf
This commit is contained in:
63
backend/api/livekit_webhook.py
Normal file
63
backend/api/livekit_webhook.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""Приёмник webhook-событий LiveKit (без JWT — верификация подписью LiveKit)."""
|
||||
|
||||
import logging
|
||||
from typing import Annotated, Any, cast
|
||||
|
||||
from fastapi import APIRouter, Depends, Header, HTTPException, Request, status
|
||||
from livekit import api
|
||||
from sqlalchemy import CursorResult
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.config import get_settings
|
||||
from core.db import get_session
|
||||
from models.webhook_event import LivekitWebhookEvent
|
||||
from services.webhook_handlers import WebhookDispatcher
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/api/v1/livekit", tags=["livekit"])
|
||||
|
||||
|
||||
@router.post("/webhook")
|
||||
async def receive_webhook(
|
||||
request: Request,
|
||||
session: Annotated[AsyncSession, Depends(get_session)],
|
||||
authorization: Annotated[str | None, Header()] = None,
|
||||
) -> dict[str, str]:
|
||||
"""Принять, верифицировать и обработать webhook-событие LiveKit.
|
||||
|
||||
Дедупликация по `event.id`: `INSERT ... ON CONFLICT DO NOTHING` в
|
||||
`livekit_webhook_events` в одной транзакции с эффектами обработчика —
|
||||
при конфликте (дубль) эффекты пропускаются, но ответ всё равно 200.
|
||||
"""
|
||||
settings = get_settings()
|
||||
raw_body = await request.body()
|
||||
|
||||
receiver = api.WebhookReceiver(
|
||||
api.TokenVerifier(settings.livekit_api_key, settings.livekit_api_secret)
|
||||
)
|
||||
try:
|
||||
event = receiver.receive(raw_body.decode(), authorization or "")
|
||||
except Exception as exc: # noqa: BLE001 — SDK кидает generic Exception на невалидную подпись
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid_signature"
|
||||
) from exc
|
||||
|
||||
insert_result = cast(
|
||||
CursorResult[Any],
|
||||
await session.execute(
|
||||
pg_insert(LivekitWebhookEvent)
|
||||
.values(event_id=event.id, event_type=event.event)
|
||||
.on_conflict_do_nothing(index_elements=["event_id"])
|
||||
),
|
||||
)
|
||||
if insert_result.rowcount == 0:
|
||||
# Дубль уже обработанного события — пропускаем эффекты, но отвечаем 200.
|
||||
await session.commit()
|
||||
return {"status": "duplicate"}
|
||||
|
||||
dispatcher = WebhookDispatcher(session)
|
||||
await dispatcher.dispatch(event)
|
||||
await session.commit()
|
||||
return {"status": "ok"}
|
||||
Reference in New Issue
Block a user