From 1e866406be94744f770486eab1d87e5ee222de03 Mon Sep 17 00:00:00 2001 From: Karol Konkol Date: Tue, 28 Apr 2026 17:01:35 +0200 Subject: [PATCH] Update MoQ token request --- .../api/moq/create_moq_subscriber_token.py | 165 ------------------ ...publisher_token.py => create_moq_token.py} | 56 +++--- fishjam/_openapi_client/models/__init__.py | 2 + .../models/moq_token_config.py | 76 ++++++++ fishjam/api/_fishjam_client.py | 38 ++-- tests/test_room_api.py | 27 +-- 6 files changed, 141 insertions(+), 223 deletions(-) delete mode 100644 fishjam/_openapi_client/api/moq/create_moq_subscriber_token.py rename fishjam/_openapi_client/api/moq/{create_moq_publisher_token.py => create_moq_token.py} (73%) create mode 100644 fishjam/_openapi_client/models/moq_token_config.py diff --git a/fishjam/_openapi_client/api/moq/create_moq_subscriber_token.py b/fishjam/_openapi_client/api/moq/create_moq_subscriber_token.py deleted file mode 100644 index c7089d8..0000000 --- a/fishjam/_openapi_client/api/moq/create_moq_subscriber_token.py +++ /dev/null @@ -1,165 +0,0 @@ -from http import HTTPStatus -from typing import Any -from urllib.parse import quote - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error import Error -from ...models.moq_token import MoqToken -from ...types import Response - - -def _get_kwargs( - stream_id: str, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/moq/{stream_id}/subscriber".format( - stream_id=quote(str(stream_id), safe=""), - ), - } - - return _kwargs - - -def _parse_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Error | MoqToken | None: - if response.status_code == 200: - response_200 = MoqToken.from_dict(response.json()) - - return response_200 - - if response.status_code == 401: - response_401 = Error.from_dict(response.json()) - - return response_401 - - if response.status_code == 503: - response_503 = Error.from_dict(response.json()) - - return response_503 - - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Error | MoqToken]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - stream_id: str, - *, - client: AuthenticatedClient, -) -> Response[Error | MoqToken]: - """Creates a MoQ subscriber token for the given stream - - Args: - stream_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[Error | MoqToken] - """ - - kwargs = _get_kwargs( - stream_id=stream_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - stream_id: str, - *, - client: AuthenticatedClient, -) -> Error | MoqToken | None: - """Creates a MoQ subscriber token for the given stream - - Args: - stream_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: - Error | MoqToken - """ - - return sync_detailed( - stream_id=stream_id, - client=client, - ).parsed - - -async def asyncio_detailed( - stream_id: str, - *, - client: AuthenticatedClient, -) -> Response[Error | MoqToken]: - """Creates a MoQ subscriber token for the given stream - - Args: - stream_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[Error | MoqToken] - """ - - kwargs = _get_kwargs( - stream_id=stream_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - stream_id: str, - *, - client: AuthenticatedClient, -) -> Error | MoqToken | None: - """Creates a MoQ subscriber token for the given stream - - Args: - stream_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: - Error | MoqToken - """ - - return ( - await asyncio_detailed( - stream_id=stream_id, - client=client, - ) - ).parsed diff --git a/fishjam/_openapi_client/api/moq/create_moq_publisher_token.py b/fishjam/_openapi_client/api/moq/create_moq_token.py similarity index 73% rename from fishjam/_openapi_client/api/moq/create_moq_publisher_token.py rename to fishjam/_openapi_client/api/moq/create_moq_token.py index 33c7677..0178dcc 100644 --- a/fishjam/_openapi_client/api/moq/create_moq_publisher_token.py +++ b/fishjam/_openapi_client/api/moq/create_moq_token.py @@ -1,6 +1,5 @@ from http import HTTPStatus from typing import Any -from urllib.parse import quote import httpx @@ -8,19 +7,27 @@ from ...client import AuthenticatedClient, Client from ...models.error import Error from ...models.moq_token import MoqToken -from ...types import Response +from ...models.moq_token_config import MoqTokenConfig +from ...types import UNSET, Response, Unset def _get_kwargs( - stream_id: str, + *, + body: MoqTokenConfig | Unset = UNSET, ) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = { "method": "post", - "url": "/moq/{stream_id}/publisher".format( - stream_id=quote(str(stream_id), safe=""), - ), + "url": "/moq/token", } + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers return _kwargs @@ -32,6 +39,11 @@ def _parse_response( return response_200 + if response.status_code == 400: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == 401: response_401 = Error.from_dict(response.json()) @@ -60,14 +72,14 @@ def _build_response( def sync_detailed( - stream_id: str, *, client: AuthenticatedClient, + body: MoqTokenConfig | Unset = UNSET, ) -> Response[Error | MoqToken]: - """Creates a MoQ publisher token for the given stream + """Creates a MoQ token for the given stream Args: - stream_id (str): + body (MoqTokenConfig | Unset): MoQ token configuration Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -78,7 +90,7 @@ def sync_detailed( """ kwargs = _get_kwargs( - stream_id=stream_id, + body=body, ) response = client.get_httpx_client().request( @@ -89,14 +101,14 @@ def sync_detailed( def sync( - stream_id: str, *, client: AuthenticatedClient, + body: MoqTokenConfig | Unset = UNSET, ) -> Error | MoqToken | None: - """Creates a MoQ publisher token for the given stream + """Creates a MoQ token for the given stream Args: - stream_id (str): + body (MoqTokenConfig | Unset): MoQ token configuration Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -107,20 +119,20 @@ def sync( """ return sync_detailed( - stream_id=stream_id, client=client, + body=body, ).parsed async def asyncio_detailed( - stream_id: str, *, client: AuthenticatedClient, + body: MoqTokenConfig | Unset = UNSET, ) -> Response[Error | MoqToken]: - """Creates a MoQ publisher token for the given stream + """Creates a MoQ token for the given stream Args: - stream_id (str): + body (MoqTokenConfig | Unset): MoQ token configuration Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -131,7 +143,7 @@ async def asyncio_detailed( """ kwargs = _get_kwargs( - stream_id=stream_id, + body=body, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -140,14 +152,14 @@ async def asyncio_detailed( async def asyncio( - stream_id: str, *, client: AuthenticatedClient, + body: MoqTokenConfig | Unset = UNSET, ) -> Error | MoqToken | None: - """Creates a MoQ publisher token for the given stream + """Creates a MoQ token for the given stream Args: - stream_id (str): + body (MoqTokenConfig | Unset): MoQ token configuration Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -159,7 +171,7 @@ async def asyncio( return ( await asyncio_detailed( - stream_id=stream_id, client=client, + body=body, ) ).parsed diff --git a/fishjam/_openapi_client/models/__init__.py b/fishjam/_openapi_client/models/__init__.py index a7ed34e..74df98f 100644 --- a/fishjam/_openapi_client/models/__init__.py +++ b/fishjam/_openapi_client/models/__init__.py @@ -6,6 +6,7 @@ from .composition_info import CompositionInfo from .error import Error from .moq_token import MoqToken +from .moq_token_config import MoqTokenConfig from .peer import Peer from .peer_config import PeerConfig from .peer_details_response import PeerDetailsResponse @@ -54,6 +55,7 @@ "CompositionInfo", "Error", "MoqToken", + "MoqTokenConfig", "Peer", "PeerConfig", "PeerDetailsResponse", diff --git a/fishjam/_openapi_client/models/moq_token_config.py b/fishjam/_openapi_client/models/moq_token_config.py new file mode 100644 index 0000000..fd46900 --- /dev/null +++ b/fishjam/_openapi_client/models/moq_token_config.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MoqTokenConfig") + + +@_attrs_define +class MoqTokenConfig: + """MoQ token configuration + + Attributes: + publish_path (None | str | Unset): Path under the root the token grants publish access to Example: my-stream. + subscribe_path (None | str | Unset): Path under the root the token grants subscribe access to Example: my- + stream. + """ + + publish_path: None | str | Unset = UNSET + subscribe_path: None | str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + publish_path: None | str | Unset + if isinstance(self.publish_path, Unset): + publish_path = UNSET + else: + publish_path = self.publish_path + + subscribe_path: None | str | Unset + if isinstance(self.subscribe_path, Unset): + subscribe_path = UNSET + else: + subscribe_path = self.subscribe_path + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if publish_path is not UNSET: + field_dict["publishPath"] = publish_path + if subscribe_path is not UNSET: + field_dict["subscribePath"] = subscribe_path + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_publish_path(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + publish_path = _parse_publish_path(d.pop("publishPath", UNSET)) + + def _parse_subscribe_path(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + subscribe_path = _parse_subscribe_path(d.pop("subscribePath", UNSET)) + + moq_token_config = cls( + publish_path=publish_path, + subscribe_path=subscribe_path, + ) + + return moq_token_config diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index 79b8a72..c47c98d 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -4,10 +4,7 @@ from typing import Any, Literal, cast from fishjam._openapi_client.api.moq import ( - create_moq_publisher_token as moq_create_publisher_token, -) -from fishjam._openapi_client.api.moq import ( - create_moq_subscriber_token as moq_create_subscriber_token, + create_moq_token as moq_create_token, ) from fishjam._openapi_client.api.room import add_peer as room_add_peer from fishjam._openapi_client.api.room import create_room as room_create_room @@ -29,6 +26,7 @@ AudioFormat, AudioSampleRate, MoqToken, + MoqTokenConfig, Peer, PeerConfig, PeerDetailsResponse, @@ -369,34 +367,26 @@ def create_livestream_streamer_token(self, room_id: str) -> str: return response.token - def create_moq_publisher_token(self, stream_id: str) -> str: - """Generates a MoQ publisher token for the given stream. + def create_moq_token( + self, + publish_path: str | None = None, + subscribe_path: str | None = None, + ) -> str: + """Generates a MoQ token. Args: - stream_id: The name of the MoQ stream. + publish_path: Path the token grants publish access to. + subscribe_path: Path the token grants subscribe access to. Returns: - str: The generated publisher token. + str: The generated token. """ - response = cast( - MoqToken, - self._request(moq_create_publisher_token, stream_id=stream_id), + config = MoqTokenConfig( + publish_path=publish_path, subscribe_path=subscribe_path ) - - return response.token - - def create_moq_subscriber_token(self, stream_id: str) -> str: - """Generates a MoQ subscriber token for the given stream. - - Args: - stream_id: The name of the MoQ stream. - - Returns: - str: The generated subscriber token. - """ response = cast( MoqToken, - self._request(moq_create_subscriber_token, stream_id=stream_id), + self._request(moq_create_token, body=config), ) return response.token diff --git a/tests/test_room_api.py b/tests/test_room_api.py index 6c159fe..2416e34 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -320,22 +320,25 @@ def test_invalid(self, room_api: FishjamClient): room_api.create_livestream_streamer_token(room.id) -class TestCreateMoqPublisherToken: - def test_valid(self, room_api: FishjamClient): - token = room_api.create_moq_publisher_token("test-stream") +class TestCreateMoqToken: + def test_no_params(self, room_api: FishjamClient): + with pytest.raises(BadRequestError): + room_api.create_moq_token() - assert isinstance(token, str) + def test_valid_publish(self, room_api: FishjamClient): + token = room_api.create_moq_token(publish_path="test-stream") - def test_unauthorized(self): - room_api = FishjamClient(FISHJAM_ID, "invalid") + assert isinstance(token, str) - with pytest.raises(UnauthorizedError): - room_api.create_moq_publisher_token("test-stream") + def test_valid_subscribe(self, room_api: FishjamClient): + token = room_api.create_moq_token(subscribe_path="test-stream") + assert isinstance(token, str) -class TestCreateMoqSubscriberToken: - def test_valid(self, room_api: FishjamClient): - token = room_api.create_moq_subscriber_token("test-stream") + def test_valid_both(self, room_api: FishjamClient): + token = room_api.create_moq_token( + publish_path="test-stream", subscribe_path="test-stream" + ) assert isinstance(token, str) @@ -343,4 +346,4 @@ def test_unauthorized(self): room_api = FishjamClient(FISHJAM_ID, "invalid") with pytest.raises(UnauthorizedError): - room_api.create_moq_subscriber_token("test-stream") + room_api.create_moq_token(publish_path="test-stream")