mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-13 08:15:21 +02:00
feat: Enable telephony for OSS (#21)
* fix: fix tooltip bug * feat: add Twilio with CloudFlare configuration * chore: update Tella Video
This commit is contained in:
parent
d39a8111a6
commit
8e2e5c9327
21 changed files with 891 additions and 191 deletions
104
api/utils/tunnel.py
Normal file
104
api/utils/tunnel.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"""Utility for getting the cloudflared tunnel URL at runtime."""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
import aiohttp
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class TunnelURLProvider:
|
||||
"""Provider for getting the tunnel URL from cloudflared or environment."""
|
||||
|
||||
@classmethod
|
||||
async def get_tunnel_url(cls) -> str:
|
||||
"""
|
||||
Get the tunnel URL for external access.
|
||||
|
||||
Priority:
|
||||
1. BACKEND_API_ENDPOINT environment variable (if set)
|
||||
2. Query cloudflared metrics endpoint
|
||||
3. Raise error if neither available
|
||||
|
||||
Returns:
|
||||
str: The tunnel domain (without protocol)
|
||||
|
||||
Raises:
|
||||
ValueError: If no tunnel URL can be determined
|
||||
"""
|
||||
# First priority: Check environment variable
|
||||
env_endpoint = os.getenv("BACKEND_API_ENDPOINT")
|
||||
if env_endpoint:
|
||||
logger.debug(f"Using BACKEND_API_ENDPOINT from environment: {env_endpoint}")
|
||||
return env_endpoint
|
||||
|
||||
# Second priority: Query cloudflared
|
||||
try:
|
||||
# Try to get URL from cloudflared metrics
|
||||
url = await cls._get_cloudflared_url()
|
||||
if url:
|
||||
logger.info(f"Retrieved tunnel URL from cloudflared: {url}")
|
||||
return url
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to get tunnel URL from cloudflared: {e}")
|
||||
|
||||
raise ValueError(
|
||||
"No tunnel URL available. Please set BACKEND_API_ENDPOINT environment "
|
||||
"variable or ensure cloudflared service is running."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def _get_cloudflared_url(cls) -> Optional[str]:
|
||||
"""
|
||||
Query cloudflared metrics endpoint to get the tunnel URL.
|
||||
|
||||
Returns:
|
||||
Optional[str]: The tunnel domain (without protocol), or None if not found
|
||||
"""
|
||||
try:
|
||||
# Try to connect to cloudflared metrics endpoint
|
||||
# The service name in docker-compose is 'cloudflared'
|
||||
metrics_url = "http://cloudflared:2000/metrics"
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
metrics_url, timeout=aiohttp.ClientTimeout(total=5)
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
logger.warning(
|
||||
f"Cloudflared metrics returned status {response.status}"
|
||||
)
|
||||
return None
|
||||
|
||||
text = await response.text()
|
||||
|
||||
# Look for the tunnel URL in metrics
|
||||
# Cloudflared exposes this in the userHostname metric
|
||||
match = re.search(r'userHostname="([^"]+)"', text)
|
||||
if match:
|
||||
hostname = match.group(1)
|
||||
# Remove https:// or wss:// if present
|
||||
hostname = hostname.replace("https://", "").replace(
|
||||
"wss://", ""
|
||||
)
|
||||
return hostname
|
||||
|
||||
# Alternative: Look for trycloudflare.com domain
|
||||
match = re.search(r"([a-z0-9-]+\.trycloudflare\.com)", text)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
logger.warning("Could not find tunnel URL in cloudflared metrics")
|
||||
return None
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning("Timeout connecting to cloudflared metrics endpoint")
|
||||
return None
|
||||
except aiohttp.ClientError as e:
|
||||
logger.warning(f"Error connecting to cloudflared: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error getting cloudflared URL: {e}")
|
||||
return None
|
||||
Loading…
Add table
Add a link
Reference in a new issue