feat: dailyco api module (#725)

* dailyco api module (no-mistakes)

* daily co library self-review

* uncurse

* self-review: daily resource leak, uniform types, enable_recording bomb, daily custom error, video_platforms/daily typing, daily timestamp dry

* dailyco docs parser

* remove generated daily docs

---------

Co-authored-by: Igor Loskutov <igor.loskutoff@gmail.com>
This commit is contained in:
Igor Monadical
2025-11-21 10:24:04 -05:00
committed by GitHub
parent 3e47c2c057
commit 4287f8b8ae
11 changed files with 1558 additions and 303 deletions

View File

@@ -6,53 +6,19 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
import httpx
from reflector.dailyco_api import DailyApiClient
from reflector.settings import settings
async def list_webhooks():
"""
List all Daily.co webhooks for this account.
"""
"""List all Daily.co webhooks for this account using dailyco_api module."""
if not settings.DAILY_API_KEY:
print("Error: DAILY_API_KEY not set")
return 1
headers = {
"Authorization": f"Bearer {settings.DAILY_API_KEY}",
"Content-Type": "application/json",
}
async with httpx.AsyncClient() as client:
async with DailyApiClient(api_key=settings.DAILY_API_KEY) as client:
try:
"""
Daily.co webhook list response format:
[
{
"uuid": "0b4e4c7c-5eaf-46fe-990b-a3752f5684f5",
"url": "{{webhook_url}}",
"hmac": "NQrSA5z0FkJ44QPrFerW7uCc5kdNLv3l2FDEKDanL1U=",
"basicAuth": null,
"eventTypes": [
"recording.started",
"recording.ready-to-download"
],
"state": "ACTVIE",
"failedCount": 0,
"lastMomentPushed": "2023-08-15T18:29:52.000Z",
"domainId": "{{domain_id}}",
"createdAt": "2023-08-15T18:28:30.000Z",
"updatedAt": "2023-08-15T18:29:52.000Z"
}
]
"""
resp = await client.get(
"https://api.daily.co/v1/webhooks",
headers=headers,
)
resp.raise_for_status()
webhooks = resp.json()
webhooks = await client.list_webhooks()
if not webhooks:
print("No webhooks found")
@@ -62,12 +28,12 @@ async def list_webhooks():
for webhook in webhooks:
print("=" * 80)
print(f"UUID: {webhook['uuid']}")
print(f"URL: {webhook['url']}")
print(f"State: {webhook['state']}")
print(f"Event Types: {', '.join(webhook.get('eventTypes', []))}")
print(f"UUID: {webhook.uuid}")
print(f"URL: {webhook.url}")
print(f"State: {webhook.state}")
print(f"Event Types: {', '.join(webhook.eventTypes)}")
print(
f"HMAC Secret: {'✓ Configured' if webhook.get('hmac') else '✗ Not set'}"
f"HMAC Secret: {'✓ Configured' if webhook.hmac else '✗ Not set'}"
)
print()
@@ -78,12 +44,8 @@ async def list_webhooks():
return 0
except httpx.HTTPStatusError as e:
print(f"Error fetching webhooks: {e}")
print(f"Response: {e.response.text}")
return 1
except Exception as e:
print(f"Unexpected error: {e}")
print(f"Error fetching webhooks: {e}")
return 1

View File

@@ -6,56 +6,60 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
import httpx
from reflector.dailyco_api import (
CreateWebhookRequest,
DailyApiClient,
)
from reflector.settings import settings
async def setup_webhook(webhook_url: str):
"""
Create or update Daily.co webhook for this environment.
Create or update Daily.co webhook for this environment using dailyco_api module.
Uses DAILY_WEBHOOK_UUID to identify existing webhook.
"""
if not settings.DAILY_API_KEY:
print("Error: DAILY_API_KEY not set")
return 1
headers = {
"Authorization": f"Bearer {settings.DAILY_API_KEY}",
"Content-Type": "application/json",
}
if not settings.DAILY_WEBHOOK_SECRET:
print("Error: DAILY_WEBHOOK_SECRET not set")
return 1
webhook_data = {
"url": webhook_url,
"eventTypes": [
"participant.joined",
"participant.left",
"recording.started",
"recording.ready-to-download",
"recording.error",
],
"hmac": settings.DAILY_WEBHOOK_SECRET,
}
event_types = [
"participant.joined",
"participant.left",
"recording.started",
"recording.ready-to-download",
"recording.error",
]
async with httpx.AsyncClient() as client:
async with DailyApiClient(api_key=settings.DAILY_API_KEY) as client:
webhook_uuid = settings.DAILY_WEBHOOK_UUID
if webhook_uuid:
# Update existing webhook
print(f"Updating existing webhook {webhook_uuid}...")
try:
resp = await client.patch(
f"https://api.daily.co/v1/webhooks/{webhook_uuid}",
headers=headers,
json=webhook_data,
# Note: Daily.co doesn't support PATCH well, so we delete + recreate
await client.delete_webhook(webhook_uuid)
print(f"Deleted old webhook {webhook_uuid}")
request = CreateWebhookRequest(
url=webhook_url,
eventTypes=event_types,
hmac=settings.DAILY_WEBHOOK_SECRET,
)
resp.raise_for_status()
result = resp.json()
print(f"✓ Updated webhook {result['uuid']} (state: {result['state']})")
print(f" URL: {result['url']}")
return 0
except httpx.HTTPStatusError as e:
if e.response.status_code == 404:
result = await client.create_webhook(request)
print(
f"✓ Created replacement webhook {result.uuid} (state: {result.state})"
)
print(f" URL: {result.url}")
webhook_uuid = result.uuid
except Exception as e:
if hasattr(e, "response") and e.response.status_code == 404:
print(f"Webhook {webhook_uuid} not found, creating new one...")
webhook_uuid = None # Fall through to creation
else:
@@ -63,17 +67,17 @@ async def setup_webhook(webhook_url: str):
return 1
if not webhook_uuid:
# Create new webhook
print("Creating new webhook...")
resp = await client.post(
"https://api.daily.co/v1/webhooks", headers=headers, json=webhook_data
request = CreateWebhookRequest(
url=webhook_url,
eventTypes=event_types,
hmac=settings.DAILY_WEBHOOK_SECRET,
)
resp.raise_for_status()
result = resp.json()
webhook_uuid = result["uuid"]
result = await client.create_webhook(request)
webhook_uuid = result.uuid
print(f"✓ Created webhook {webhook_uuid} (state: {result['state']})")
print(f" URL: {result['url']}")
print(f"✓ Created webhook {webhook_uuid} (state: {result.state})")
print(f" URL: {result.url}")
print()
print("=" * 60)
print("IMPORTANT: Add this to your environment variables:")
@@ -114,7 +118,7 @@ if __name__ == "__main__":
)
print()
print("Behavior:")
print(" - If DAILY_WEBHOOK_UUID set: Updates existing webhook")
print(" - If DAILY_WEBHOOK_UUID set: Deletes old webhook, creates new one")
print(
" - If DAILY_WEBHOOK_UUID empty: Creates new webhook, saves UUID to .env"
)