uchill/backend/apps/video/services/sfu_client.py

225 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Python клиент для взаимодействия с sfu-server (ion-sfu).
"""
import logging
import requests
from typing import Optional, Dict, List, Any
from django.conf import settings
logger = logging.getLogger(__name__)
class SFUClientError(Exception):
"""Ошибка при работе с SFU сервером."""
pass
class SFUClient:
"""
Клиент для взаимодействия с sfu-server через HTTP API.
Используется для управления видеокомнатами на стороне Django.
"""
def __init__(self, base_url: Optional[str] = None):
"""
Инициализация клиента.
Args:
base_url: Базовый URL sfu-server (по умолчанию из настроек)
"""
self.base_url = base_url or getattr(
settings,
'SFU_SERVER_URL',
'http://sfu-server:7001'
)
self.timeout = getattr(settings, 'SFU_CLIENT_TIMEOUT', 10)
def _request(
self,
method: str,
endpoint: str,
data: Optional[Dict] = None,
params: Optional[Dict] = None
) -> Dict[str, Any]:
"""
Выполнение HTTP запроса к sfu-server.
Args:
method: HTTP метод (GET, POST, DELETE)
endpoint: Endpoint API
data: Данные для отправки
params: Query параметры
Returns:
Ответ от сервера в виде словаря
Raises:
SFUClientError: При ошибке запроса
"""
url = f"{self.base_url}{endpoint}"
try:
response = requests.request(
method=method,
url=url,
json=data,
params=params,
timeout=self.timeout,
headers={'Content-Type': 'application/json'}
)
# Проверка статуса ответа
if not response.ok:
error_msg = f"SFU server error: {response.status_code}"
try:
error_data = response.json()
error_msg = error_data.get('error', error_msg)
except:
error_msg = f"{error_msg} - {response.text}"
logger.error(f"SFU request failed: {method} {url} - {error_msg}")
raise SFUClientError(error_msg)
# Парсинг ответа
try:
return response.json()
except ValueError:
return {'status': 'ok'}
except requests.exceptions.RequestException as e:
error_msg = f"Failed to connect to SFU server: {str(e)}"
logger.error(f"SFU connection error: {error_msg}")
raise SFUClientError(error_msg)
def create_room(self, room_id: str) -> Dict[str, Any]:
"""
Создать видеокомнату в sfu-server.
Args:
room_id: Уникальный ID комнаты (обычно UUID из VideoRoom)
Returns:
Информация о созданной комнате
Example:
>>> client = SFUClient()
>>> result = client.create_room('123e4567-e89b-12d3-a456-426614174000')
>>> print(result)
{'room_id': '123e4567-e89b-12d3-a456-426614174000', 'status': 'created'}
"""
try:
response = self._request('POST', f'/api/rooms/{room_id}/create')
logger.info(f"Room {room_id} created in SFU server")
return response
except SFUClientError:
raise
except Exception as e:
logger.error(f"Unexpected error creating room {room_id}: {e}")
raise SFUClientError(f"Failed to create room: {str(e)}")
def get_room(self, room_id: str) -> Dict[str, Any]:
"""
Получить информацию о видеокомнате.
Args:
room_id: ID комнаты
Returns:
Информация о комнате (room_id, peers_count, status)
Example:
>>> client = SFUClient()
>>> room = client.get_room('123e4567-e89b-12d3-a456-426614174000')
>>> print(room)
{'room_id': '...', 'peers_count': 2, 'status': 'active'}
"""
try:
response = self._request('GET', f'/api/rooms/{room_id}')
return response
except SFUClientError:
raise
except Exception as e:
logger.error(f"Unexpected error getting room {room_id}: {e}")
raise SFUClientError(f"Failed to get room: {str(e)}")
def delete_room(self, room_id: str) -> Dict[str, Any]:
"""
Удалить видеокомнату из sfu-server.
Args:
room_id: ID комнаты
Returns:
Подтверждение удаления
Example:
>>> client = SFUClient()
>>> result = client.delete_room('123e4567-e89b-12d3-a456-426614174000')
>>> print(result)
{'room_id': '...', 'status': 'deleted'}
"""
try:
response = self._request('DELETE', f'/api/rooms/{room_id}')
logger.info(f"Room {room_id} deleted from SFU server")
return response
except SFUClientError:
raise
except Exception as e:
logger.error(f"Unexpected error deleting room {room_id}: {e}")
raise SFUClientError(f"Failed to delete room: {str(e)}")
def list_rooms(self) -> List[Dict[str, Any]]:
"""
Получить список всех активных комнат.
Returns:
Список комнат с информацией о каждой
Example:
>>> client = SFUClient()
>>> rooms = client.list_rooms()
>>> print(rooms)
[{'room_id': '...', 'peers_count': 2, 'status': 'active'}, ...]
"""
try:
response = self._request('GET', '/api/rooms')
return response.get('rooms', [])
except SFUClientError:
raise
except Exception as e:
logger.error(f"Unexpected error listing rooms: {e}")
raise SFUClientError(f"Failed to list rooms: {str(e)}")
def health_check(self) -> bool:
"""
Проверить доступность sfu-server.
Returns:
True если сервер доступен, False иначе
"""
try:
response = self._request('GET', '/health')
return response.get('status') == 'ok'
except Exception as e:
logger.warning(f"SFU health check failed: {e}")
return False
# Singleton экземпляр клиента
_sfu_client: Optional[SFUClient] = None
def get_sfu_client() -> SFUClient:
"""
Получить singleton экземпляр SFU клиента.
Returns:
Экземпляр SFUClient
"""
global _sfu_client
if _sfu_client is None:
_sfu_client = SFUClient()
return _sfu_client