From c7985e53347e8eedefc199734a8b90c5edefa27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Szuma?= Date: Tue, 13 Feb 2024 11:58:54 +0100 Subject: [PATCH 1/5] Add tests for SIP Component --- jellyfish/__init__.py | 10 +- jellyfish/_openapi_client/api/sip/__init__.py | 0 jellyfish/_openapi_client/api/sip/dial.py | 189 ++++++++++++++++++ jellyfish/_openapi_client/api/sip/end_call.py | 171 ++++++++++++++++ jellyfish/_openapi_client/models/__init__.py | 10 + .../models/add_component_json_body.py | 32 ++- .../models/component_details_response.py | 22 +- .../models/component_options_sip.py | 66 ++++++ .../models/component_properties_sip.py | 66 ++++++ .../_openapi_client/models/component_sip.py | 90 +++++++++ .../_openapi_client/models/credentials.py | 74 +++++++ .../_openapi_client/models/dial_config.py | 60 ++++++ jellyfish/_openapi_client/models/room.py | 26 ++- jellyfish/api/_room_api.py | 46 ++++- tests/test_room_api.py | 31 +++ 15 files changed, 874 insertions(+), 19 deletions(-) create mode 100644 jellyfish/_openapi_client/api/sip/__init__.py create mode 100644 jellyfish/_openapi_client/api/sip/dial.py create mode 100644 jellyfish/_openapi_client/api/sip/end_call.py create mode 100644 jellyfish/_openapi_client/models/component_options_sip.py create mode 100644 jellyfish/_openapi_client/models/component_properties_sip.py create mode 100644 jellyfish/_openapi_client/models/component_sip.py create mode 100644 jellyfish/_openapi_client/models/credentials.py create mode 100644 jellyfish/_openapi_client/models/dial_config.py diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index fbba6e4..81f1845 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -11,15 +11,19 @@ from jellyfish._openapi_client.models import ( ComponentFile, ComponentHLS, + ComponentSIP, + ComponentRTSP, ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsHLSSubscribeMode, + ComponentOptionsSIP, ComponentOptionsRTSP, ComponentPropertiesFile, ComponentPropertiesHLS, ComponentPropertiesHLSSubscribeMode, + ComponentPropertiesSIP, ComponentPropertiesRTSP, - ComponentRTSP, + Credentials, Peer, PeerOptionsWebRTC, PeerStatus, @@ -50,6 +54,10 @@ "ComponentOptionsHLSSubscribeMode", "ComponentPropertiesHLS", "ComponentPropertiesHLSSubscribeMode", + "ComponentSIP", + "ComponentOptionsSIP", + "ComponentPropertiesSIP", + "ComponentFile", "ComponentRTSP", "ComponentOptionsRTSP", "ComponentPropertiesRTSP", diff --git a/jellyfish/_openapi_client/api/sip/__init__.py b/jellyfish/_openapi_client/api/sip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jellyfish/_openapi_client/api/sip/dial.py b/jellyfish/_openapi_client/api/sip/dial.py new file mode 100644 index 0000000..bcf7224 --- /dev/null +++ b/jellyfish/_openapi_client/api/sip/dial.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dial_config import DialConfig +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, + component_id: str, + *, + json_body: DialConfig, +) -> Dict[str, Any]: + json_json_body = json_body.to_dict() + + return { + "method": "post", + "url": "/sip/{room_id}/{component_id}/call".format( + room_id=room_id, + component_id=component_id, + ), + "json": json_json_body, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = cast(Any, None) + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: DialConfig, +) -> Response[Union[Any, Error]]: + """Making a call from the SIP component to the provided phone number + + Args: + room_id (str): + component_id (str): + json_body (DialConfig): Dial config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + component_id=component_id, + json_body=json_body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: DialConfig, +) -> Optional[Union[Any, Error]]: + """Making a call from the SIP component to the provided phone number + + Args: + room_id (str): + component_id (str): + json_body (DialConfig): Dial config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + component_id=component_id, + client=client, + json_body=json_body, + ).parsed + + +async def asyncio_detailed( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: DialConfig, +) -> Response[Union[Any, Error]]: + """Making a call from the SIP component to the provided phone number + + Args: + room_id (str): + component_id (str): + json_body (DialConfig): Dial config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + component_id=component_id, + json_body=json_body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: DialConfig, +) -> Optional[Union[Any, Error]]: + """Making a call from the SIP component to the provided phone number + + Args: + room_id (str): + component_id (str): + json_body (DialConfig): Dial config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + component_id=component_id, + client=client, + json_body=json_body, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/sip/end_call.py b/jellyfish/_openapi_client/api/sip/end_call.py new file mode 100644 index 0000000..c68e51a --- /dev/null +++ b/jellyfish/_openapi_client/api/sip/end_call.py @@ -0,0 +1,171 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, + component_id: str, +) -> Dict[str, Any]: + return { + "method": "delete", + "url": "/sip/{room_id}/{component_id}/call".format( + room_id=room_id, + component_id=component_id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = cast(Any, None) + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Finish call made by SIP component + + Args: + room_id (str): + component_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + component_id=component_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Finish call made by SIP component + + Args: + room_id (str): + component_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + component_id=component_id, + client=client, + ).parsed + + +async def asyncio_detailed( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Finish call made by SIP component + + Args: + room_id (str): + component_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + component_id=component_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + component_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Finish call made by SIP component + + Args: + room_id (str): + component_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + component_id=component_id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/models/__init__.py b/jellyfish/_openapi_client/models/__init__.py index a7de09e..969d2a5 100644 --- a/jellyfish/_openapi_client/models/__init__.py +++ b/jellyfish/_openapi_client/models/__init__.py @@ -9,11 +9,16 @@ from .component_options_hls import ComponentOptionsHLS from .component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode from .component_options_rtsp import ComponentOptionsRTSP +from .component_options_sip import ComponentOptionsSIP from .component_properties_file import ComponentPropertiesFile from .component_properties_hls import ComponentPropertiesHLS from .component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode from .component_properties_rtsp import ComponentPropertiesRTSP +from .component_properties_sip import ComponentPropertiesSIP from .component_rtsp import ComponentRTSP +from .component_sip import ComponentSIP +from .credentials import Credentials +from .dial_config import DialConfig from .error import Error from .health_report import HealthReport from .health_report_distribution import HealthReportDistribution @@ -47,11 +52,16 @@ "ComponentOptionsHLS", "ComponentOptionsHLSSubscribeMode", "ComponentOptionsRTSP", + "ComponentOptionsSIP", "ComponentPropertiesFile", "ComponentPropertiesHLS", "ComponentPropertiesHLSSubscribeMode", "ComponentPropertiesRTSP", + "ComponentPropertiesSIP", "ComponentRTSP", + "ComponentSIP", + "Credentials", + "DialConfig", "Error", "HealthcheckResponse", "HealthReport", diff --git a/jellyfish/_openapi_client/models/add_component_json_body.py b/jellyfish/_openapi_client/models/add_component_json_body.py index 82c7699..c3e0408 100644 --- a/jellyfish/_openapi_client/models/add_component_json_body.py +++ b/jellyfish/_openapi_client/models/add_component_json_body.py @@ -9,6 +9,7 @@ from ..models.component_options_file import ComponentOptionsFile from ..models.component_options_hls import ComponentOptionsHLS from ..models.component_options_rtsp import ComponentOptionsRTSP + from ..models.component_options_sip import ComponentOptionsSIP T = TypeVar("T", bound="AddComponentJsonBody") @@ -21,7 +22,11 @@ class AddComponentJsonBody: type: str """Component type""" options: Union[ - "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset + "ComponentOptionsFile", + "ComponentOptionsHLS", + "ComponentOptionsRTSP", + "ComponentOptionsSIP", + Unset, ] = UNSET """Component-specific options""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -29,6 +34,7 @@ class AddComponentJsonBody: def to_dict(self) -> Dict[str, Any]: """@private""" + from ..models.component_options_file import ComponentOptionsFile from ..models.component_options_hls import ComponentOptionsHLS from ..models.component_options_rtsp import ComponentOptionsRTSP @@ -43,6 +49,9 @@ def to_dict(self) -> Dict[str, Any]: elif isinstance(self.options, ComponentOptionsRTSP): options = self.options.to_dict() + elif isinstance(self.options, ComponentOptionsFile): + options = self.options.to_dict() + else: options = self.options.to_dict() @@ -64,6 +73,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: from ..models.component_options_file import ComponentOptionsFile from ..models.component_options_hls import ComponentOptionsHLS from ..models.component_options_rtsp import ComponentOptionsRTSP + from ..models.component_options_sip import ComponentOptionsSIP d = src_dict.copy() type = d.pop("type") @@ -71,7 +81,11 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: def _parse_options( data: object, ) -> Union[ - "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset + "ComponentOptionsFile", + "ComponentOptionsHLS", + "ComponentOptionsRTSP", + "ComponentOptionsSIP", + Unset, ]: if isinstance(data, Unset): return data @@ -95,13 +109,23 @@ def _parse_options( return componentsschemas_component_options_type_1 except: # noqa: E722 pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_options_type_2 = ( + ComponentOptionsFile.from_dict(data) + ) + + return componentsschemas_component_options_type_2 + except: # noqa: E722 + pass if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict( + componentsschemas_component_options_type_3 = ComponentOptionsSIP.from_dict( data ) - return componentsschemas_component_options_type_2 + return componentsschemas_component_options_type_3 options = _parse_options(d.pop("options", UNSET)) diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 959e0bc..91de1a9 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -7,6 +7,7 @@ from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP + from ..models.component_sip import ComponentSIP T = TypeVar("T", bound="ComponentDetailsResponse") @@ -16,13 +17,14 @@ class ComponentDetailsResponse: """Response containing component details""" - data: Union["ComponentFile", "ComponentHLS", "ComponentRTSP"] + data: Union["ComponentFile", "ComponentHLS", "ComponentRTSP", "ComponentSIP"] """Describes component""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) """@private""" def to_dict(self) -> Dict[str, Any]: """@private""" + from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -34,6 +36,9 @@ def to_dict(self) -> Dict[str, Any]: elif isinstance(self.data, ComponentRTSP): data = self.data.to_dict() + elif isinstance(self.data, ComponentFile): + data = self.data.to_dict() + else: data = self.data.to_dict() @@ -53,12 +58,13 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP + from ..models.component_sip import ComponentSIP d = src_dict.copy() def _parse_data( data: object, - ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP", "ComponentSIP"]: try: if not isinstance(data, dict): raise TypeError() @@ -75,11 +81,19 @@ def _parse_data( return componentsschemas_component_type_1 except: # noqa: E722 pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_2 = ComponentFile.from_dict(data) + + return componentsschemas_component_type_2 + except: # noqa: E722 + pass if not isinstance(data, dict): raise TypeError() - componentsschemas_component_type_2 = ComponentFile.from_dict(data) + componentsschemas_component_type_3 = ComponentSIP.from_dict(data) - return componentsschemas_component_type_2 + return componentsschemas_component_type_3 data = _parse_data(d.pop("data")) diff --git a/jellyfish/_openapi_client/models/component_options_sip.py b/jellyfish/_openapi_client/models/component_options_sip.py new file mode 100644 index 0000000..903dcb5 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_options_sip.py @@ -0,0 +1,66 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.credentials import Credentials + + +T = TypeVar("T", bound="ComponentOptionsSIP") + + +@_attrs_define +class ComponentOptionsSIP: + """Options specific to the SIP component""" + + registrar_credentials: "Credentials" + """Credentials used to authorize in SIP Provider service""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + registrar_credentials = self.registrar_credentials.to_dict() + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "registrarCredentials": registrar_credentials, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + from ..models.credentials import Credentials + + d = src_dict.copy() + registrar_credentials = Credentials.from_dict(d.pop("registrarCredentials")) + + component_options_sip = cls( + registrar_credentials=registrar_credentials, + ) + + component_options_sip.additional_properties = d + return component_options_sip + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_properties_sip.py b/jellyfish/_openapi_client/models/component_properties_sip.py new file mode 100644 index 0000000..7017ab0 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_properties_sip.py @@ -0,0 +1,66 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.credentials import Credentials + + +T = TypeVar("T", bound="ComponentPropertiesSIP") + + +@_attrs_define +class ComponentPropertiesSIP: + """Properties specific to the SIP component""" + + registrar_credentials: "Credentials" + """Credentials used to authorize in SIP Provider service""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + registrar_credentials = self.registrar_credentials.to_dict() + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "registrarCredentials": registrar_credentials, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + from ..models.credentials import Credentials + + d = src_dict.copy() + registrar_credentials = Credentials.from_dict(d.pop("registrarCredentials")) + + component_properties_sip = cls( + registrar_credentials=registrar_credentials, + ) + + component_properties_sip.additional_properties = d + return component_properties_sip + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_sip.py b/jellyfish/_openapi_client/models/component_sip.py new file mode 100644 index 0000000..74e58ce --- /dev/null +++ b/jellyfish/_openapi_client/models/component_sip.py @@ -0,0 +1,90 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.component_properties_sip import ComponentPropertiesSIP + + +T = TypeVar("T", bound="ComponentSIP") + + +@_attrs_define +class ComponentSIP: + """Describes the SIP component""" + + id: str + """Assigned component ID""" + type: str + """Component type""" + properties: Union[Unset, "ComponentPropertiesSIP"] = UNSET + """Properties specific to the SIP component""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + id = self.id + type = self.type + properties: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(self.properties, Unset): + properties = self.properties.to_dict() + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "type": type, + } + ) + if properties is not UNSET: + field_dict["properties"] = properties + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + from ..models.component_properties_sip import ComponentPropertiesSIP + + d = src_dict.copy() + id = d.pop("id") + + type = d.pop("type") + + _properties = d.pop("properties", UNSET) + properties: Union[Unset, ComponentPropertiesSIP] + if isinstance(_properties, Unset): + properties = UNSET + else: + properties = ComponentPropertiesSIP.from_dict(_properties) + + component_sip = cls( + id=id, + type=type, + properties=properties, + ) + + component_sip.additional_properties = d + return component_sip + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/credentials.py b/jellyfish/_openapi_client/models/credentials.py new file mode 100644 index 0000000..52df5dc --- /dev/null +++ b/jellyfish/_openapi_client/models/credentials.py @@ -0,0 +1,74 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="Credentials") + + +@_attrs_define +class Credentials: + """Credentials used to authorize in SIP Provider service""" + + address: str + """SIP provider address. Can be in the form of FQDN (my-sip-registrar.net) or IPv4 (1.2.3.4). Port can be specified e.g: 5.6.7.8:9999. If not given, the default SIP port `5060` will be assumed""" + password: str + """Password in SIP service provider""" + username: str + """Username in SIP service provider""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + address = self.address + password = self.password + username = self.username + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "address": address, + "password": password, + "username": username, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + d = src_dict.copy() + address = d.pop("address") + + password = d.pop("password") + + username = d.pop("username") + + credentials = cls( + address=address, + password=password, + username=username, + ) + + credentials.additional_properties = d + return credentials + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/dial_config.py b/jellyfish/_openapi_client/models/dial_config.py new file mode 100644 index 0000000..4b6b021 --- /dev/null +++ b/jellyfish/_openapi_client/models/dial_config.py @@ -0,0 +1,60 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DialConfig") + + +@_attrs_define +class DialConfig: + """Dial config""" + + phone_number: Union[Unset, str] = UNSET + """Phone number on which SIP Component will call""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + phone_number = self.phone_number + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if phone_number is not UNSET: + field_dict["phoneNumber"] = phone_number + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + d = src_dict.copy() + phone_number = d.pop("phoneNumber", UNSET) + + dial_config = cls( + phone_number=phone_number, + ) + + dial_config.additional_properties = d + return dial_config + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room.py b/jellyfish/_openapi_client/models/room.py index 62fcbae..4b73ad6 100644 --- a/jellyfish/_openapi_client/models/room.py +++ b/jellyfish/_openapi_client/models/room.py @@ -7,6 +7,7 @@ from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP + from ..models.component_sip import ComponentSIP from ..models.peer import Peer from ..models.room_config import RoomConfig @@ -18,7 +19,9 @@ class Room: """Description of the room state""" - components: List[Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]] + components: List[ + Union["ComponentFile", "ComponentHLS", "ComponentRTSP", "ComponentSIP"] + ] """List of all components""" config: "RoomConfig" """Room configuration""" @@ -31,6 +34,7 @@ class Room: def to_dict(self) -> Dict[str, Any]: """@private""" + from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -44,6 +48,9 @@ def to_dict(self) -> Dict[str, Any]: elif isinstance(components_item_data, ComponentRTSP): components_item = components_item_data.to_dict() + elif isinstance(components_item_data, ComponentFile): + components_item = components_item_data.to_dict() + else: components_item = components_item_data.to_dict() @@ -77,6 +84,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP + from ..models.component_sip import ComponentSIP from ..models.peer import Peer from ..models.room_config import RoomConfig @@ -87,7 +95,9 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: def _parse_components_item( data: object, - ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + ) -> Union[ + "ComponentFile", "ComponentHLS", "ComponentRTSP", "ComponentSIP" + ]: try: if not isinstance(data, dict): raise TypeError() @@ -104,11 +114,19 @@ def _parse_components_item( return componentsschemas_component_type_1 except: # noqa: E722 pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_2 = ComponentFile.from_dict(data) + + return componentsschemas_component_type_2 + except: # noqa: E722 + pass if not isinstance(data, dict): raise TypeError() - componentsschemas_component_type_2 = ComponentFile.from_dict(data) + componentsschemas_component_type_3 = ComponentSIP.from_dict(data) - return componentsschemas_component_type_2 + return componentsschemas_component_type_3 components_item = _parse_components_item(components_item_data) diff --git a/jellyfish/api/_room_api.py b/jellyfish/api/_room_api.py index 9ab1b72..fc53a42 100644 --- a/jellyfish/api/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -5,6 +5,8 @@ from typing import Literal, Union from jellyfish._openapi_client.api.hls import subscribe_hls_to as hls_subscribe_hls_to +from jellyfish._openapi_client.api.sip import dial as sip_dial +from jellyfish._openapi_client.api.sip import end_call as sip_end_call from jellyfish._openapi_client.api.room import add_component as room_add_component from jellyfish._openapi_client.api.room import add_peer as room_add_peer from jellyfish._openapi_client.api.room import create_room as room_create_room @@ -17,11 +19,13 @@ AddComponentJsonBody, AddPeerJsonBody, ComponentFile, - ComponentHLS, ComponentOptionsFile, + ComponentSIP, + ComponentOptionsSIP, + ComponentHLS, ComponentOptionsHLS, - ComponentOptionsRTSP, ComponentRTSP, + ComponentOptionsRTSP, Peer, PeerOptionsWebRTC, Room, @@ -123,8 +127,8 @@ def delete_peer(self, room_id: str, peer_id: str) -> None: def add_component( self, room_id: str, - options: Union[ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsRTSP], - ) -> Union[ComponentFile, ComponentHLS, ComponentRTSP]: + options: Union[ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsRTSP, ComponentOptionsSIP], + ) -> Union[ComponentFile, ComponentHLS, ComponentRTSP, ComponentSIP]: """Creates component in the room""" if isinstance(options, ComponentOptionsFile): @@ -133,10 +137,12 @@ def add_component( component_type = "hls" elif isinstance(options, ComponentOptionsRTSP): component_type = "rtsp" + elif isinstance(options, ComponentOptionsSIP): + component_type = "sip" else: raise ValueError( - "options must be ComponentFile, ComponentOptionsHLS" - "or ComponentOptionsRTSP" + "options must be ComponentFile, ComponentOptionsHLS," + "ComponentOptionsRTSP or ComponentOptionsSIP" ) json_body = AddComponentJsonBody(type=component_type, options=options) @@ -166,3 +172,31 @@ def hls_subscribe(self, room_id: str, origins: [str]): room_id=room_id, json_body=SubscriptionConfig(origins=origins), ) + + def sip_dial(self, room_id: str, component_id: str, phone_number: str): + """ + Starts a phone call from a specified component to a provided phone number. + + This is asynchronous operation. + In case of providing incorrect phone number you will receive a notification `ComponentCrashed`. + """ + + return self._request( + sip_dial, + room_id=room_id, + component_id=component_id, + json_body={"phoneNumber": phone_number}, + ) + + def sip_end_call(self, room_id: str, component_id: str): + """ + End a phone call on a specified SIP component. + + This is asynchronous operation. + """ + + return self._request( + sip_end_call, + room_id=room_id, + component_id=component_id, + ) diff --git a/tests/test_room_api.py b/tests/test_room_api.py index 21ff8df..fa1b72a 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -19,6 +19,10 @@ ComponentPropertiesHLSSubscribeMode, ComponentPropertiesRTSP, ComponentRTSP, + ComponentOptionsSIP, + ComponentPropertiesSIP, + ComponentSIP, + Credentials, Peer, PeerOptionsWebRTC, PeerStatus, @@ -62,6 +66,17 @@ pierce_nat=True, ) +SIP_PHONE_NUMBER="1234" + +SIP_CREDENTIALS=Credentials(address="my-sip-registrar.net",username="user-name",password="pass-word") + +SIP_OPTIONS = ComponentOptionsSIP( + registrar_credentials=SIP_CREDENTIALS +) +SIP_PROPERTIES = ComponentPropertiesSIP( + registrar_credentials=SIP_CREDENTIALS +) + FILE_OPTIONS = ComponentOptionsFile(file_path="video.h264") FILE_PROPERTIES = ComponentPropertiesFile( file_path=FILE_OPTIONS.file_path, framerate=30 @@ -230,6 +245,10 @@ def test_with_options_rtsp(self, room_api): data = ComponentTestData(ComponentRTSP, "rtsp", RTSP_OPTIONS, RTSP_PROPERTIES) self._test_component(room_api, data) + def test_with_options_sip(self, room_api): + data = ComponentTestData(ComponentSIP, "sip", SIP_OPTIONS, SIP_PROPERTIES) + self._test_component(room_api, data) + @pytest.mark.file_component_sources def test_with_options_file(self, room_api): data = ComponentTestData(ComponentFile, "file", FILE_OPTIONS, FILE_PROPERTIES) @@ -295,6 +314,18 @@ def test_invalid_subscription_in_auto_mode(self, room_api: RoomApi): == "HLS component option `subscribe_mode` is set to :auto" ) +class TestSIPCall: + def test_happy_path(self, room_api: RoomApi): + _, room = room_api.create_room(video_codec=CODEC_H264) + component = room_api.add_component( + room.id, + options=ComponentOptionsSIP( + registrar_credentials=SIP_CREDENTIALS + ), + ) + assert room_api.sip_dial(room.id, component.id, SIP_PHONE_NUMBER) is None + + assert room_api.sip_end_call(room.id, component.id) is None class TestAddPeer: def _assert_peer_created(self, room_api, webrtc_peer, room_id): From 7b831dfcf6f096891c86e0de0a2fe4321f748b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Szuma?= Date: Tue, 13 Feb 2024 12:01:41 +0100 Subject: [PATCH 2/5] Fix lint issues --- jellyfish/__init__.py | 9 ++++----- jellyfish/api/_room_api.py | 24 +++++++++++++++--------- tests/test_room_api.py | 24 +++++++++++------------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 81f1845..6b408c2 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -11,19 +11,18 @@ from jellyfish._openapi_client.models import ( ComponentFile, ComponentHLS, - ComponentSIP, - ComponentRTSP, ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsHLSSubscribeMode, - ComponentOptionsSIP, ComponentOptionsRTSP, + ComponentOptionsSIP, ComponentPropertiesFile, ComponentPropertiesHLS, ComponentPropertiesHLSSubscribeMode, - ComponentPropertiesSIP, ComponentPropertiesRTSP, - Credentials, + ComponentPropertiesSIP, + ComponentRTSP, + ComponentSIP, Peer, PeerOptionsWebRTC, PeerStatus, diff --git a/jellyfish/api/_room_api.py b/jellyfish/api/_room_api.py index fc53a42..562a763 100644 --- a/jellyfish/api/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -5,8 +5,6 @@ from typing import Literal, Union from jellyfish._openapi_client.api.hls import subscribe_hls_to as hls_subscribe_hls_to -from jellyfish._openapi_client.api.sip import dial as sip_dial -from jellyfish._openapi_client.api.sip import end_call as sip_end_call from jellyfish._openapi_client.api.room import add_component as room_add_component from jellyfish._openapi_client.api.room import add_peer as room_add_peer from jellyfish._openapi_client.api.room import create_room as room_create_room @@ -15,17 +13,19 @@ from jellyfish._openapi_client.api.room import delete_room as room_delete_room from jellyfish._openapi_client.api.room import get_all_rooms as room_get_all_rooms from jellyfish._openapi_client.api.room import get_room as room_get_room +from jellyfish._openapi_client.api.sip import dial as sip_dial +from jellyfish._openapi_client.api.sip import end_call as sip_end_call from jellyfish._openapi_client.models import ( AddComponentJsonBody, AddPeerJsonBody, ComponentFile, - ComponentOptionsFile, - ComponentSIP, - ComponentOptionsSIP, ComponentHLS, + ComponentOptionsFile, ComponentOptionsHLS, - ComponentRTSP, ComponentOptionsRTSP, + ComponentOptionsSIP, + ComponentRTSP, + ComponentSIP, Peer, PeerOptionsWebRTC, Room, @@ -127,7 +127,12 @@ def delete_peer(self, room_id: str, peer_id: str) -> None: def add_component( self, room_id: str, - options: Union[ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsRTSP, ComponentOptionsSIP], + options: Union[ + ComponentOptionsFile, + ComponentOptionsHLS, + ComponentOptionsRTSP, + ComponentOptionsSIP, + ], ) -> Union[ComponentFile, ComponentHLS, ComponentRTSP, ComponentSIP]: """Creates component in the room""" @@ -177,8 +182,9 @@ def sip_dial(self, room_id: str, component_id: str, phone_number: str): """ Starts a phone call from a specified component to a provided phone number. - This is asynchronous operation. - In case of providing incorrect phone number you will receive a notification `ComponentCrashed`. + This is asynchronous operation. + In case of providing incorrect phone number you will receive + notification `ComponentCrashed`. """ return self._request( diff --git a/tests/test_room_api.py b/tests/test_room_api.py index fa1b72a..6b6e2ca 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -14,13 +14,13 @@ ComponentOptionsHLS, ComponentOptionsHLSSubscribeMode, ComponentOptionsRTSP, + ComponentOptionsSIP, ComponentPropertiesFile, ComponentPropertiesHLS, ComponentPropertiesHLSSubscribeMode, ComponentPropertiesRTSP, - ComponentRTSP, - ComponentOptionsSIP, ComponentPropertiesSIP, + ComponentRTSP, ComponentSIP, Credentials, Peer, @@ -66,17 +66,15 @@ pierce_nat=True, ) -SIP_PHONE_NUMBER="1234" - -SIP_CREDENTIALS=Credentials(address="my-sip-registrar.net",username="user-name",password="pass-word") +SIP_PHONE_NUMBER = "1234" -SIP_OPTIONS = ComponentOptionsSIP( - registrar_credentials=SIP_CREDENTIALS -) -SIP_PROPERTIES = ComponentPropertiesSIP( - registrar_credentials=SIP_CREDENTIALS +SIP_CREDENTIALS = Credentials( + address="my-sip-registrar.net", username="user-name", password="pass-word" ) +SIP_OPTIONS = ComponentOptionsSIP(registrar_credentials=SIP_CREDENTIALS) +SIP_PROPERTIES = ComponentPropertiesSIP(registrar_credentials=SIP_CREDENTIALS) + FILE_OPTIONS = ComponentOptionsFile(file_path="video.h264") FILE_PROPERTIES = ComponentPropertiesFile( file_path=FILE_OPTIONS.file_path, framerate=30 @@ -314,19 +312,19 @@ def test_invalid_subscription_in_auto_mode(self, room_api: RoomApi): == "HLS component option `subscribe_mode` is set to :auto" ) + class TestSIPCall: def test_happy_path(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) component = room_api.add_component( room.id, - options=ComponentOptionsSIP( - registrar_credentials=SIP_CREDENTIALS - ), + options=ComponentOptionsSIP(registrar_credentials=SIP_CREDENTIALS), ) assert room_api.sip_dial(room.id, component.id, SIP_PHONE_NUMBER) is None assert room_api.sip_end_call(room.id, component.id) is None + class TestAddPeer: def _assert_peer_created(self, room_api, webrtc_peer, room_id): peer = Peer( From b6c7a25dca447ee378c613e92e56bb69ca27b1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Szuma?= Date: Fri, 16 Feb 2024 12:25:22 +0100 Subject: [PATCH 3/5] Update openapi client --- jellyfish/__init__.py | 4 + .../api/{default => health}/__init__.py | 0 .../api/{default => health}/healthcheck.py | 27 +++---- .../api/hls/subscribe_hls_to.py | 4 + .../api/recording/delete_recording.py | 4 + .../api/recording/get_recordings.py | 4 + jellyfish/_openapi_client/api/sip/dial.py | 13 +++- jellyfish/_openapi_client/models/__init__.py | 10 ++- .../models/component_options_sip.py | 14 +++- .../component_options_sipsip_credentials.py | 74 +++++++++++++++++++ .../models/component_properties_sip.py | 14 +++- ...component_properties_sipsip_credentials.py | 74 +++++++++++++++++++ .../_openapi_client/models/component_sip.py | 46 +++++++----- .../_openapi_client/models/room_config.py | 8 ++ .../{credentials.py => sip_credentials.py} | 10 +-- jellyfish/api/_room_api.py | 3 +- tests/test_room_api.py | 14 ++-- 17 files changed, 267 insertions(+), 56 deletions(-) rename jellyfish/_openapi_client/api/{default => health}/__init__.py (100%) rename jellyfish/_openapi_client/api/{default => health}/healthcheck.py (81%) create mode 100644 jellyfish/_openapi_client/models/component_options_sipsip_credentials.py create mode 100644 jellyfish/_openapi_client/models/component_properties_sipsip_credentials.py rename jellyfish/_openapi_client/models/{credentials.py => sip_credentials.py} (91%) diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 6b408c2..57d9a3f 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -21,6 +21,7 @@ ComponentPropertiesHLSSubscribeMode, ComponentPropertiesRTSP, ComponentPropertiesSIP, + ComponentPropertiesSIPSIPCredentials, ComponentRTSP, ComponentSIP, Peer, @@ -29,6 +30,7 @@ Room, RoomConfig, RoomConfigVideoCodec, + SIPCredentials, ) # API @@ -56,6 +58,7 @@ "ComponentSIP", "ComponentOptionsSIP", "ComponentPropertiesSIP", + "ComponentPropertiesSIPSIPCredentials", "ComponentFile", "ComponentRTSP", "ComponentOptionsRTSP", @@ -65,5 +68,6 @@ "ComponentPropertiesFile", "events", "errors", + "SIPCredentials", ] __docformat__ = "restructuredtext" diff --git a/jellyfish/_openapi_client/api/default/__init__.py b/jellyfish/_openapi_client/api/health/__init__.py similarity index 100% rename from jellyfish/_openapi_client/api/default/__init__.py rename to jellyfish/_openapi_client/api/health/__init__.py diff --git a/jellyfish/_openapi_client/api/default/healthcheck.py b/jellyfish/_openapi_client/api/health/healthcheck.py similarity index 81% rename from jellyfish/_openapi_client/api/default/healthcheck.py rename to jellyfish/_openapi_client/api/health/healthcheck.py index 2cef558..c66453b 100644 --- a/jellyfish/_openapi_client/api/default/healthcheck.py +++ b/jellyfish/_openapi_client/api/health/healthcheck.py @@ -5,6 +5,7 @@ from ... import errors from ...client import AuthenticatedClient, Client +from ...models.error import Error from ...models.healthcheck_response import HealthcheckResponse from ...types import Response @@ -18,15 +19,15 @@ def _get_kwargs() -> Dict[str, Any]: def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[HealthcheckResponse]: +) -> Optional[Union[Error, HealthcheckResponse]]: if response.status_code == HTTPStatus.OK: response_200 = HealthcheckResponse.from_dict(response.json()) return response_200 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = HealthcheckResponse.from_dict(response.json()) + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) - return response_500 + return response_401 if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: @@ -35,7 +36,7 @@ def _parse_response( def _build_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[HealthcheckResponse]: +) -> Response[Union[Error, HealthcheckResponse]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -47,7 +48,7 @@ def _build_response( def sync_detailed( *, client: Union[AuthenticatedClient, Client], -) -> Response[HealthcheckResponse]: +) -> Response[Union[Error, HealthcheckResponse]]: """Describes the health of Jellyfish Raises: @@ -55,7 +56,7 @@ def sync_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[HealthcheckResponse] + Response[Union[Error, HealthcheckResponse]] """ kwargs = _get_kwargs() @@ -70,7 +71,7 @@ def sync_detailed( def sync( *, client: Union[AuthenticatedClient, Client], -) -> Optional[HealthcheckResponse]: +) -> Optional[Union[Error, HealthcheckResponse]]: """Describes the health of Jellyfish Raises: @@ -78,7 +79,7 @@ def sync( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - HealthcheckResponse + Union[Error, HealthcheckResponse] """ return sync_detailed( @@ -89,7 +90,7 @@ def sync( async def asyncio_detailed( *, client: Union[AuthenticatedClient, Client], -) -> Response[HealthcheckResponse]: +) -> Response[Union[Error, HealthcheckResponse]]: """Describes the health of Jellyfish Raises: @@ -97,7 +98,7 @@ async def asyncio_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[HealthcheckResponse] + Response[Union[Error, HealthcheckResponse]] """ kwargs = _get_kwargs() @@ -110,7 +111,7 @@ async def asyncio_detailed( async def asyncio( *, client: Union[AuthenticatedClient, Client], -) -> Optional[HealthcheckResponse]: +) -> Optional[Union[Error, HealthcheckResponse]]: """Describes the health of Jellyfish Raises: @@ -118,7 +119,7 @@ async def asyncio( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - HealthcheckResponse + Union[Error, HealthcheckResponse] """ return ( diff --git a/jellyfish/_openapi_client/api/hls/subscribe_hls_to.py b/jellyfish/_openapi_client/api/hls/subscribe_hls_to.py index 1f00bde..ea1b7e9 100644 --- a/jellyfish/_openapi_client/api/hls/subscribe_hls_to.py +++ b/jellyfish/_openapi_client/api/hls/subscribe_hls_to.py @@ -36,6 +36,10 @@ def _parse_response( response_400 = Error.from_dict(response.json()) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 if response.status_code == HTTPStatus.NOT_FOUND: response_404 = Error.from_dict(response.json()) diff --git a/jellyfish/_openapi_client/api/recording/delete_recording.py b/jellyfish/_openapi_client/api/recording/delete_recording.py index ae6ba21..ea03030 100644 --- a/jellyfish/_openapi_client/api/recording/delete_recording.py +++ b/jellyfish/_openapi_client/api/recording/delete_recording.py @@ -30,6 +30,10 @@ def _parse_response( response_400 = Error.from_dict(response.json()) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 if response.status_code == HTTPStatus.NOT_FOUND: response_404 = Error.from_dict(response.json()) diff --git a/jellyfish/_openapi_client/api/recording/get_recordings.py b/jellyfish/_openapi_client/api/recording/get_recordings.py index 8855ab9..8174071 100644 --- a/jellyfish/_openapi_client/api/recording/get_recordings.py +++ b/jellyfish/_openapi_client/api/recording/get_recordings.py @@ -24,6 +24,10 @@ def _parse_response( response_200 = RecordingListResponse.from_dict(response.json()) return response_200 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 if response.status_code == HTTPStatus.NOT_FOUND: response_404 = Error.from_dict(response.json()) diff --git a/jellyfish/_openapi_client/api/sip/dial.py b/jellyfish/_openapi_client/api/sip/dial.py index bcf7224..140db1c 100644 --- a/jellyfish/_openapi_client/api/sip/dial.py +++ b/jellyfish/_openapi_client/api/sip/dial.py @@ -16,6 +16,7 @@ def _get_kwargs( *, json_body: DialConfig, ) -> Dict[str, Any]: + json_json_body = json_body.to_dict() return { @@ -38,6 +39,10 @@ def _parse_response( response_400 = Error.from_dict(response.json()) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 if response.status_code == HTTPStatus.NOT_FOUND: response_404 = Error.from_dict(response.json()) @@ -66,7 +71,7 @@ def sync_detailed( client: Union[AuthenticatedClient, Client], json_body: DialConfig, ) -> Response[Union[Any, Error]]: - """Making a call from the SIP component to the provided phone number + """Make a call from the SIP component to the provided phone number Args: room_id (str): @@ -101,7 +106,7 @@ def sync( client: Union[AuthenticatedClient, Client], json_body: DialConfig, ) -> Optional[Union[Any, Error]]: - """Making a call from the SIP component to the provided phone number + """Make a call from the SIP component to the provided phone number Args: room_id (str): @@ -131,7 +136,7 @@ async def asyncio_detailed( client: Union[AuthenticatedClient, Client], json_body: DialConfig, ) -> Response[Union[Any, Error]]: - """Making a call from the SIP component to the provided phone number + """Make a call from the SIP component to the provided phone number Args: room_id (str): @@ -164,7 +169,7 @@ async def asyncio( client: Union[AuthenticatedClient, Client], json_body: DialConfig, ) -> Optional[Union[Any, Error]]: - """Making a call from the SIP component to the provided phone number + """Make a call from the SIP component to the provided phone number Args: room_id (str): diff --git a/jellyfish/_openapi_client/models/__init__.py b/jellyfish/_openapi_client/models/__init__.py index 969d2a5..de23bcb 100644 --- a/jellyfish/_openapi_client/models/__init__.py +++ b/jellyfish/_openapi_client/models/__init__.py @@ -10,14 +10,17 @@ from .component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode from .component_options_rtsp import ComponentOptionsRTSP from .component_options_sip import ComponentOptionsSIP +from .component_options_sipsip_credentials import ComponentOptionsSIPSIPCredentials from .component_properties_file import ComponentPropertiesFile from .component_properties_hls import ComponentPropertiesHLS from .component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode from .component_properties_rtsp import ComponentPropertiesRTSP from .component_properties_sip import ComponentPropertiesSIP +from .component_properties_sipsip_credentials import ( + ComponentPropertiesSIPSIPCredentials, +) from .component_rtsp import ComponentRTSP from .component_sip import ComponentSIP -from .credentials import Credentials from .dial_config import DialConfig from .error import Error from .health_report import HealthReport @@ -38,6 +41,7 @@ from .room_details_response import RoomDetailsResponse from .rooms_listing_response import RoomsListingResponse from .s3_credentials import S3Credentials +from .sip_credentials import SIPCredentials from .subscription_config import SubscriptionConfig from .track import Track from .track_type import TrackType @@ -53,14 +57,15 @@ "ComponentOptionsHLSSubscribeMode", "ComponentOptionsRTSP", "ComponentOptionsSIP", + "ComponentOptionsSIPSIPCredentials", "ComponentPropertiesFile", "ComponentPropertiesHLS", "ComponentPropertiesHLSSubscribeMode", "ComponentPropertiesRTSP", "ComponentPropertiesSIP", + "ComponentPropertiesSIPSIPCredentials", "ComponentRTSP", "ComponentSIP", - "Credentials", "DialConfig", "Error", "HealthcheckResponse", @@ -81,6 +86,7 @@ "RoomDetailsResponse", "RoomsListingResponse", "S3Credentials", + "SIPCredentials", "SubscriptionConfig", "Track", "TrackType", diff --git a/jellyfish/_openapi_client/models/component_options_sip.py b/jellyfish/_openapi_client/models/component_options_sip.py index 903dcb5..9bdc819 100644 --- a/jellyfish/_openapi_client/models/component_options_sip.py +++ b/jellyfish/_openapi_client/models/component_options_sip.py @@ -4,7 +4,9 @@ from attrs import field as _attrs_field if TYPE_CHECKING: - from ..models.credentials import Credentials + from ..models.component_options_sipsip_credentials import ( + ComponentOptionsSIPSIPCredentials, + ) T = TypeVar("T", bound="ComponentOptionsSIP") @@ -14,7 +16,7 @@ class ComponentOptionsSIP: """Options specific to the SIP component""" - registrar_credentials: "Credentials" + registrar_credentials: "ComponentOptionsSIPSIPCredentials" """Credentials used to authorize in SIP Provider service""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) """@private""" @@ -36,10 +38,14 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: """@private""" - from ..models.credentials import Credentials + from ..models.component_options_sipsip_credentials import ( + ComponentOptionsSIPSIPCredentials, + ) d = src_dict.copy() - registrar_credentials = Credentials.from_dict(d.pop("registrarCredentials")) + registrar_credentials = ComponentOptionsSIPSIPCredentials.from_dict( + d.pop("registrarCredentials") + ) component_options_sip = cls( registrar_credentials=registrar_credentials, diff --git a/jellyfish/_openapi_client/models/component_options_sipsip_credentials.py b/jellyfish/_openapi_client/models/component_options_sipsip_credentials.py new file mode 100644 index 0000000..4cf83a3 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_options_sipsip_credentials.py @@ -0,0 +1,74 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ComponentOptionsSIPSIPCredentials") + + +@_attrs_define +class ComponentOptionsSIPSIPCredentials: + """Credentials used to authorize in SIP Provider service""" + + address: str + """SIP provider address. Can be in the form of FQDN (my-sip-registrar.net) or IPv4 (1.2.3.4). Port can be specified e.g: 5.6.7.8:9999. If not given, the default SIP port `5060` will be assumed""" + password: str + """Password in SIP service provider""" + username: str + """Username in SIP service provider""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + address = self.address + password = self.password + username = self.username + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "address": address, + "password": password, + "username": username, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + d = src_dict.copy() + address = d.pop("address") + + password = d.pop("password") + + username = d.pop("username") + + component_options_sipsip_credentials = cls( + address=address, + password=password, + username=username, + ) + + component_options_sipsip_credentials.additional_properties = d + return component_options_sipsip_credentials + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_properties_sip.py b/jellyfish/_openapi_client/models/component_properties_sip.py index 7017ab0..adb6b1c 100644 --- a/jellyfish/_openapi_client/models/component_properties_sip.py +++ b/jellyfish/_openapi_client/models/component_properties_sip.py @@ -4,7 +4,9 @@ from attrs import field as _attrs_field if TYPE_CHECKING: - from ..models.credentials import Credentials + from ..models.component_properties_sipsip_credentials import ( + ComponentPropertiesSIPSIPCredentials, + ) T = TypeVar("T", bound="ComponentPropertiesSIP") @@ -14,7 +16,7 @@ class ComponentPropertiesSIP: """Properties specific to the SIP component""" - registrar_credentials: "Credentials" + registrar_credentials: "ComponentPropertiesSIPSIPCredentials" """Credentials used to authorize in SIP Provider service""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) """@private""" @@ -36,10 +38,14 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: """@private""" - from ..models.credentials import Credentials + from ..models.component_properties_sipsip_credentials import ( + ComponentPropertiesSIPSIPCredentials, + ) d = src_dict.copy() - registrar_credentials = Credentials.from_dict(d.pop("registrarCredentials")) + registrar_credentials = ComponentPropertiesSIPSIPCredentials.from_dict( + d.pop("registrarCredentials") + ) component_properties_sip = cls( registrar_credentials=registrar_credentials, diff --git a/jellyfish/_openapi_client/models/component_properties_sipsip_credentials.py b/jellyfish/_openapi_client/models/component_properties_sipsip_credentials.py new file mode 100644 index 0000000..2757aea --- /dev/null +++ b/jellyfish/_openapi_client/models/component_properties_sipsip_credentials.py @@ -0,0 +1,74 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ComponentPropertiesSIPSIPCredentials") + + +@_attrs_define +class ComponentPropertiesSIPSIPCredentials: + """Credentials used to authorize in SIP Provider service""" + + address: str + """SIP provider address. Can be in the form of FQDN (my-sip-registrar.net) or IPv4 (1.2.3.4). Port can be specified e.g: 5.6.7.8:9999. If not given, the default SIP port `5060` will be assumed""" + password: str + """Password in SIP service provider""" + username: str + """Username in SIP service provider""" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" + + def to_dict(self) -> Dict[str, Any]: + """@private""" + address = self.address + password = self.password + username = self.username + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "address": address, + "password": password, + "username": username, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" + d = src_dict.copy() + address = d.pop("address") + + password = d.pop("password") + + username = d.pop("username") + + component_properties_sipsip_credentials = cls( + address=address, + password=password, + username=username, + ) + + component_properties_sipsip_credentials.additional_properties = d + return component_properties_sipsip_credentials + + @property + def additional_keys(self) -> List[str]: + """@private""" + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_sip.py b/jellyfish/_openapi_client/models/component_sip.py index 74e58ce..7cbab9d 100644 --- a/jellyfish/_openapi_client/models/component_sip.py +++ b/jellyfish/_openapi_client/models/component_sip.py @@ -1,12 +1,11 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field -from ..types import UNSET, Unset - if TYPE_CHECKING: from ..models.component_properties_sip import ComponentPropertiesSIP + from ..models.track import Track T = TypeVar("T", bound="ComponentSIP") @@ -18,31 +17,38 @@ class ComponentSIP: id: str """Assigned component ID""" + properties: "ComponentPropertiesSIP" + """Properties specific to the SIP component""" + tracks: List["Track"] + """List of all component's tracks""" type: str """Component type""" - properties: Union[Unset, "ComponentPropertiesSIP"] = UNSET - """Properties specific to the SIP component""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) """@private""" def to_dict(self) -> Dict[str, Any]: """@private""" id = self.id + properties = self.properties.to_dict() + + tracks = [] + for tracks_item_data in self.tracks: + tracks_item = tracks_item_data.to_dict() + + tracks.append(tracks_item) + type = self.type - properties: Union[Unset, Dict[str, Any]] = UNSET - if not isinstance(self.properties, Unset): - properties = self.properties.to_dict() field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { "id": id, + "properties": properties, + "tracks": tracks, "type": type, } ) - if properties is not UNSET: - field_dict["properties"] = properties return field_dict @@ -50,23 +56,27 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: """@private""" from ..models.component_properties_sip import ComponentPropertiesSIP + from ..models.track import Track d = src_dict.copy() id = d.pop("id") - type = d.pop("type") + properties = ComponentPropertiesSIP.from_dict(d.pop("properties")) + + tracks = [] + _tracks = d.pop("tracks") + for tracks_item_data in _tracks: + tracks_item = Track.from_dict(tracks_item_data) + + tracks.append(tracks_item) - _properties = d.pop("properties", UNSET) - properties: Union[Unset, ComponentPropertiesSIP] - if isinstance(_properties, Unset): - properties = UNSET - else: - properties = ComponentPropertiesSIP.from_dict(_properties) + type = d.pop("type") component_sip = cls( id=id, - type=type, properties=properties, + tracks=tracks, + type=type, ) component_sip.additional_properties = d diff --git a/jellyfish/_openapi_client/models/room_config.py b/jellyfish/_openapi_client/models/room_config.py index 8a940ec..6f0985e 100644 --- a/jellyfish/_openapi_client/models/room_config.py +++ b/jellyfish/_openapi_client/models/room_config.py @@ -15,6 +15,8 @@ class RoomConfig: max_peers: Union[Unset, None, int] = UNSET """Maximum amount of peers allowed into the room""" + peerless_purge_timeout: Union[Unset, None, int] = UNSET + """Duration (in seconds) after which the room will be removed if no peers are connected. If not provided, this feature is disabled.""" room_id: Union[Unset, None, str] = UNSET """Custom id used for identifying room within Jellyfish. Must be unique across all rooms. If not provided, random UUID is generated.""" video_codec: Union[Unset, None, RoomConfigVideoCodec] = UNSET @@ -27,6 +29,7 @@ class RoomConfig: def to_dict(self) -> Dict[str, Any]: """@private""" max_peers = self.max_peers + peerless_purge_timeout = self.peerless_purge_timeout room_id = self.room_id video_codec: Union[Unset, None, str] = UNSET if not isinstance(self.video_codec, Unset): @@ -39,6 +42,8 @@ def to_dict(self) -> Dict[str, Any]: field_dict.update({}) if max_peers is not UNSET: field_dict["maxPeers"] = max_peers + if peerless_purge_timeout is not UNSET: + field_dict["peerlessPurgeTimeout"] = peerless_purge_timeout if room_id is not UNSET: field_dict["roomId"] = room_id if video_codec is not UNSET: @@ -54,6 +59,8 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() max_peers = d.pop("maxPeers", UNSET) + peerless_purge_timeout = d.pop("peerlessPurgeTimeout", UNSET) + room_id = d.pop("roomId", UNSET) _video_codec = d.pop("videoCodec", UNSET) @@ -69,6 +76,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: room_config = cls( max_peers=max_peers, + peerless_purge_timeout=peerless_purge_timeout, room_id=room_id, video_codec=video_codec, webhook_url=webhook_url, diff --git a/jellyfish/_openapi_client/models/credentials.py b/jellyfish/_openapi_client/models/sip_credentials.py similarity index 91% rename from jellyfish/_openapi_client/models/credentials.py rename to jellyfish/_openapi_client/models/sip_credentials.py index 52df5dc..9b8678c 100644 --- a/jellyfish/_openapi_client/models/credentials.py +++ b/jellyfish/_openapi_client/models/sip_credentials.py @@ -3,11 +3,11 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="Credentials") +T = TypeVar("T", bound="SIPCredentials") @_attrs_define -class Credentials: +class SIPCredentials: """Credentials used to authorize in SIP Provider service""" address: str @@ -47,14 +47,14 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: username = d.pop("username") - credentials = cls( + sip_credentials = cls( address=address, password=password, username=username, ) - credentials.additional_properties = d - return credentials + sip_credentials.additional_properties = d + return sip_credentials @property def additional_keys(self) -> List[str]: diff --git a/jellyfish/api/_room_api.py b/jellyfish/api/_room_api.py index 562a763..e01be67 100644 --- a/jellyfish/api/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -32,6 +32,7 @@ RoomConfig, RoomConfigVideoCodec, SubscriptionConfig, + DialConfig ) from jellyfish.api._base_api import BaseApi @@ -191,7 +192,7 @@ def sip_dial(self, room_id: str, component_id: str, phone_number: str): sip_dial, room_id=room_id, component_id=component_id, - json_body={"phoneNumber": phone_number}, + json_body=DialConfig(phone_number=phone_number), ) def sip_end_call(self, room_id: str, component_id: str): diff --git a/tests/test_room_api.py b/tests/test_room_api.py index 6b6e2ca..ee5086f 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -22,7 +22,8 @@ ComponentPropertiesSIP, ComponentRTSP, ComponentSIP, - Credentials, + SIPCredentials, + ComponentPropertiesSIPSIPCredentials, Peer, PeerOptionsWebRTC, PeerStatus, @@ -68,12 +69,13 @@ SIP_PHONE_NUMBER = "1234" -SIP_CREDENTIALS = Credentials( +SIP_CREDENTIALS = SIPCredentials( address="my-sip-registrar.net", username="user-name", password="pass-word" ) SIP_OPTIONS = ComponentOptionsSIP(registrar_credentials=SIP_CREDENTIALS) -SIP_PROPERTIES = ComponentPropertiesSIP(registrar_credentials=SIP_CREDENTIALS) + +SIP_PROPERTIES = ComponentPropertiesSIP(registrar_credentials=ComponentPropertiesSIPSIPCredentials(address="my-sip-registrar.net", username="user-name", password="pass-word")) FILE_OPTIONS = ComponentOptionsFile(file_path="video.h264") FILE_PROPERTIES = ComponentPropertiesFile( @@ -121,7 +123,7 @@ def test_no_params(self, room_api): assert room == Room( components=[], config=RoomConfig( - room_id=room.id, max_peers=None, video_codec=None, webhook_url=None + room_id=room.id, max_peers=None, video_codec=None, webhook_url=None, peerless_purge_timeout=None ), id=room.id, peers=[], @@ -141,6 +143,7 @@ def test_valid_params(self, room_api): max_peers=MAX_PEERS, video_codec=RoomConfigVideoCodec(CODEC_H264), webhook_url=None, + peerless_purge_timeout=None ), id=room.id, peers=[], @@ -168,6 +171,7 @@ def test_valid_room_id(self, room_api): max_peers=None, video_codec=None, webhook_url=None, + peerless_purge_timeout=None ), id=room_id, peers=[], @@ -217,7 +221,7 @@ def test_valid(self, room_api: RoomApi): peers=[], id=room.id, config=RoomConfig( - room_id=room.id, max_peers=None, video_codec=None, webhook_url=None + room_id=room.id, max_peers=None, video_codec=None, webhook_url=None, peerless_purge_timeout=None ), ) == room_api.get_room(room.id) From 7625d736debbfc373a8cb3ad875992a0e800f106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Szuma?= Date: Mon, 19 Feb 2024 14:17:22 +0100 Subject: [PATCH 4/5] Fix lint and format issues --- jellyfish/_openapi_client/api/sip/dial.py | 1 - jellyfish/api/_room_api.py | 2 +- tests/test_room_api.py | 26 +++++++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/jellyfish/_openapi_client/api/sip/dial.py b/jellyfish/_openapi_client/api/sip/dial.py index 140db1c..c7c9edb 100644 --- a/jellyfish/_openapi_client/api/sip/dial.py +++ b/jellyfish/_openapi_client/api/sip/dial.py @@ -16,7 +16,6 @@ def _get_kwargs( *, json_body: DialConfig, ) -> Dict[str, Any]: - json_json_body = json_body.to_dict() return { diff --git a/jellyfish/api/_room_api.py b/jellyfish/api/_room_api.py index e01be67..4f4f4fb 100644 --- a/jellyfish/api/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -26,13 +26,13 @@ ComponentOptionsSIP, ComponentRTSP, ComponentSIP, + DialConfig, Peer, PeerOptionsWebRTC, Room, RoomConfig, RoomConfigVideoCodec, SubscriptionConfig, - DialConfig ) from jellyfish.api._base_api import BaseApi diff --git a/tests/test_room_api.py b/tests/test_room_api.py index ee5086f..0bb4cff 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -20,10 +20,9 @@ ComponentPropertiesHLSSubscribeMode, ComponentPropertiesRTSP, ComponentPropertiesSIP, + ComponentPropertiesSIPSIPCredentials, ComponentRTSP, ComponentSIP, - SIPCredentials, - ComponentPropertiesSIPSIPCredentials, Peer, PeerOptionsWebRTC, PeerStatus, @@ -31,6 +30,7 @@ RoomApi, RoomConfig, RoomConfigVideoCodec, + SIPCredentials, ) from jellyfish.errors import ( BadRequestError, @@ -75,7 +75,11 @@ SIP_OPTIONS = ComponentOptionsSIP(registrar_credentials=SIP_CREDENTIALS) -SIP_PROPERTIES = ComponentPropertiesSIP(registrar_credentials=ComponentPropertiesSIPSIPCredentials(address="my-sip-registrar.net", username="user-name", password="pass-word")) +SIP_PROPERTIES = ComponentPropertiesSIP( + registrar_credentials=ComponentPropertiesSIPSIPCredentials( + address="my-sip-registrar.net", username="user-name", password="pass-word" + ) +) FILE_OPTIONS = ComponentOptionsFile(file_path="video.h264") FILE_PROPERTIES = ComponentPropertiesFile( @@ -123,7 +127,11 @@ def test_no_params(self, room_api): assert room == Room( components=[], config=RoomConfig( - room_id=room.id, max_peers=None, video_codec=None, webhook_url=None, peerless_purge_timeout=None + room_id=room.id, + max_peers=None, + video_codec=None, + webhook_url=None, + peerless_purge_timeout=None, ), id=room.id, peers=[], @@ -143,7 +151,7 @@ def test_valid_params(self, room_api): max_peers=MAX_PEERS, video_codec=RoomConfigVideoCodec(CODEC_H264), webhook_url=None, - peerless_purge_timeout=None + peerless_purge_timeout=None, ), id=room.id, peers=[], @@ -171,7 +179,7 @@ def test_valid_room_id(self, room_api): max_peers=None, video_codec=None, webhook_url=None, - peerless_purge_timeout=None + peerless_purge_timeout=None, ), id=room_id, peers=[], @@ -221,7 +229,11 @@ def test_valid(self, room_api: RoomApi): peers=[], id=room.id, config=RoomConfig( - room_id=room.id, max_peers=None, video_codec=None, webhook_url=None, peerless_purge_timeout=None + room_id=room.id, + max_peers=None, + video_codec=None, + webhook_url=None, + peerless_purge_timeout=None, ), ) == room_api.get_room(room.id) From 43680fd2ebf6ddba7fc0db54d75841e6ab6c7f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Szuma?= Date: Mon, 19 Feb 2024 14:48:44 +0100 Subject: [PATCH 5/5] Add missing envs in docker-compose --- docker-compose-test.yaml | 2 ++ jellyfish/_openapi_client/api/sip/end_call.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/docker-compose-test.yaml b/docker-compose-test.yaml index 407856a..ae1619f 100644 --- a/docker-compose-test.yaml +++ b/docker-compose-test.yaml @@ -21,6 +21,8 @@ services: JF_SERVER_API_TOKEN: "development" JF_PORT: 5002 JF_SECRET_KEY_BASE: "super-secret-key" + JF_SIP_USED: "true" + JF_SIP_IP: "127.0.0.1" ports: - "5002:5002" - "49999:49999" diff --git a/jellyfish/_openapi_client/api/sip/end_call.py b/jellyfish/_openapi_client/api/sip/end_call.py index c68e51a..772fc0f 100644 --- a/jellyfish/_openapi_client/api/sip/end_call.py +++ b/jellyfish/_openapi_client/api/sip/end_call.py @@ -32,6 +32,10 @@ def _parse_response( response_400 = Error.from_dict(response.json()) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 if response.status_code == HTTPStatus.NOT_FOUND: response_404 = Error.from_dict(response.json())