first commit
This commit is contained in:
commit
efa5080897
127 changed files with 18610 additions and 0 deletions
68
backend/app/sms_webhooks.py
Normal file
68
backend/app/sms_webhooks.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import httpx
|
||||
|
||||
from .endpoint_security import payload_signature
|
||||
from .models import SmsDeliveryWebhook
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _event_body(data: dict) -> bytes:
|
||||
payload = {
|
||||
"id": f"evt_{uuid.uuid4().hex}",
|
||||
"event": "message.delivery.updated",
|
||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||
"data": data,
|
||||
}
|
||||
return json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode()
|
||||
|
||||
|
||||
async def deliver_report(
|
||||
endpoint: SmsDeliveryWebhook,
|
||||
data: dict,
|
||||
*,
|
||||
attempts: int = 3,
|
||||
) -> int:
|
||||
body = _event_body(data)
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Urmi-Webhooks/1.0",
|
||||
"X-Urmi-Event": "message.delivery.updated",
|
||||
"X-Urmi-Endpoint-Id": str(endpoint.id),
|
||||
"X-Urmi-Signature": payload_signature("webhook", endpoint.id, body),
|
||||
}
|
||||
last_error: Exception | None = None
|
||||
async with httpx.AsyncClient(timeout=10.0, follow_redirects=False) as client:
|
||||
for attempt in range(attempts):
|
||||
try:
|
||||
response = await client.post(endpoint.url, content=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
return response.status_code
|
||||
except (httpx.HTTPError, httpx.TimeoutException) as exc:
|
||||
last_error = exc
|
||||
if attempt + 1 < attempts:
|
||||
await asyncio.sleep(2**attempt)
|
||||
logger.warning("SMS delivery webhook failed endpoint=%s: %s", endpoint.id, last_error)
|
||||
raise RuntimeError("Webhook endpoint did not return a successful response") from last_error
|
||||
|
||||
|
||||
async def deliver_test_report(endpoint: SmsDeliveryWebhook) -> int:
|
||||
if not endpoint.enabled:
|
||||
raise RuntimeError("Webhook is disabled")
|
||||
return await deliver_report(
|
||||
endpoint,
|
||||
{
|
||||
"message_id": f"msg_test_{uuid.uuid4().hex[:16]}",
|
||||
"to": "+919999999999",
|
||||
"from": endpoint.phone_number.phone_number if endpoint.phone_number else "test",
|
||||
"status": "delivered",
|
||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"test": True,
|
||||
},
|
||||
attempts=1,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue