dograh/api/services/telephony/factory.py

109 lines
3.6 KiB
Python
Raw Permalink Normal View History

2025-10-13 17:55:10 +05:30
"""
Factory for creating telephony providers.
Handles configuration loading from environment (OSS) or database (SaaS).
The providers themselves don't know or care where config comes from.
"""
import os
from typing import Any, Dict, Optional
from loguru import logger
from api.db import db_client
from api.enums import OrganizationConfigurationKey
from api.services.telephony.base import TelephonyProvider
from api.services.telephony.providers.twilio_provider import TwilioProvider
2025-10-24 09:28:11 +05:30
from api.services.telephony.providers.vonage_provider import VonageProvider
2025-10-13 17:55:10 +05:30
2025-10-24 09:28:11 +05:30
async def load_telephony_config(organization_id: int) -> Dict[str, Any]:
2025-10-13 17:55:10 +05:30
"""
2025-10-24 09:28:11 +05:30
Load telephony configuration from database.
2025-10-13 17:55:10 +05:30
Args:
2025-10-24 09:28:11 +05:30
organization_id: Organization ID for database config
2025-10-13 17:55:10 +05:30
Returns:
Configuration dictionary with provider type and credentials
2025-10-24 09:28:11 +05:30
Raises:
ValueError: If no configuration found for the organization
2025-10-13 17:55:10 +05:30
"""
2025-10-24 09:28:11 +05:30
if not organization_id:
raise ValueError("Organization ID is required to load telephony configuration")
logger.debug(f"Loading telephony config from database for org {organization_id}")
# Try new key first
config = await db_client.get_configuration(
organization_id,
OrganizationConfigurationKey.TELEPHONY_CONFIGURATION.value,
)
# Fallback to old key for backward compatibility
if not config:
config = await db_client.get_configuration(
2025-10-13 17:55:10 +05:30
organization_id,
OrganizationConfigurationKey.TWILIO_CONFIGURATION.value,
)
2025-10-24 09:28:11 +05:30
if config and config.value:
# Simple single-provider format
provider = config.value.get("provider", "twilio")
2025-10-13 17:55:10 +05:30
if provider == "twilio":
return {
"provider": "twilio",
2025-10-24 09:28:11 +05:30
"account_sid": config.value.get("account_sid"),
"auth_token": config.value.get("auth_token"),
"from_numbers": config.value.get("from_numbers", [])
}
elif provider == "vonage":
return {
"provider": "vonage",
"application_id": config.value.get("application_id"),
"private_key": config.value.get("private_key"),
"api_key": config.value.get("api_key"),
"api_secret": config.value.get("api_secret"),
"from_numbers": config.value.get("from_numbers", [])
2025-10-13 17:55:10 +05:30
}
else:
2025-10-24 09:28:11 +05:30
raise ValueError(f"Unknown provider in config: {provider}")
raise ValueError(f"No telephony configuration found for organization {organization_id}")
2025-10-13 17:55:10 +05:30
async def get_telephony_provider(
2025-10-24 09:28:11 +05:30
organization_id: int
2025-10-13 17:55:10 +05:30
) -> TelephonyProvider:
"""
Factory function to create telephony providers.
Args:
2025-10-24 09:28:11 +05:30
organization_id: Organization ID (required)
2025-10-13 17:55:10 +05:30
Returns:
Configured telephony provider instance
Raises:
ValueError: If provider type is unknown or configuration is invalid
"""
# Load configuration from appropriate source
config = await load_telephony_config(organization_id)
provider_type = config.get("provider", "twilio")
logger.info(f"Creating {provider_type} telephony provider")
# Create provider instance with configuration
# Provider doesn't know or care if config came from env or database
if provider_type == "twilio":
return TwilioProvider(config)
2025-10-24 09:28:11 +05:30
elif provider_type == "vonage":
return VonageProvider(config)
2025-10-13 17:55:10 +05:30
# Future providers can be added here
# elif provider_type == "plivo":
# return PlivoProvider(config)
else:
raise ValueError(f"Unknown telephony provider: {provider_type}")