Files
ds-chat/backend/app/services/webhook_delivery.py
T
ksmithandClaude Sonnet 5 14dc340174 Rename project from KeepItTalking to DS Chat
Renames the app's display name everywhere (page titles, PWA manifest,
TopBar, email subject lines, HMAC signature header) and its internal
technical slug from chatapp to ds-chat/ds_chat: the Python package name
and console script, the systemd unit and its user/group/paths, the deploy
scripts, the Docker container names, and the Postgres database name.

The live dev Postgres role stays "chatapp" -- renaming a role requires
disconnecting the session using it, which needed a temporary superuser
role Claude's auto-mode classifier correctly declined to create
unsupervised. Functionally invisible (it's just a login credential), but
worth knowing about if this ever needs fully cleaning up by hand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 21:11:41 -06:00

42 lines
1.4 KiB
Python

import hashlib
import hmac
import json
import logging
import httpx
from app.models import EventSubscription
logger = logging.getLogger(__name__)
_TIMEOUT_SECONDS = 5.0
async def deliver_event(subscription: EventSubscription, event_type: str, payload: dict) -> None:
"""POST a signed event to a subscription's target_url.
Fire-once, best-effort: no retry/backoff, any failure is logged and
swallowed rather than raised -- a slow or dead third-party endpoint must
never affect message delivery to real room members. Safe to run in a
background asyncio.create_task (unlike the Phase 4 push lesson) because
there's no DB session involved here, just the already-serialized
payload and secret -- nothing that can outlive an event loop.
"""
body = json.dumps({"event": event_type, "data": payload}).encode()
signature = hmac.new(subscription.signing_secret.encode(), body, hashlib.sha256).hexdigest()
try:
async with httpx.AsyncClient(timeout=_TIMEOUT_SECONDS) as client:
await client.post(
subscription.target_url,
content=body,
headers={
"Content-Type": "application/json",
"X-DS-Chat-Signature": f"sha256={signature}",
},
)
except httpx.HTTPError:
logger.warning(
"Failed to deliver %s event to subscription %s", event_type, subscription.id
)