diff --git a/fishjam/__init__.py b/fishjam/__init__.py index f1e1a71..f55fdc4 100644 --- a/fishjam/__init__.py +++ b/fishjam/__init__.py @@ -18,6 +18,7 @@ AgentOptions, AgentOutputOptions, FishjamClient, + MoqAccess, Peer, PeerOptions, PeerOptionsVapi, @@ -41,6 +42,7 @@ "AgentOutputOptions", "Room", "Peer", + "MoqAccess", "MissingFishjamIdError", "InvalidFishjamCredentialsError", "events", diff --git a/fishjam/_openapi_client/api/mo_q/create_moq_token.py b/fishjam/_openapi_client/api/mo_q/create_moq_access.py similarity index 76% rename from fishjam/_openapi_client/api/mo_q/create_moq_token.py rename to fishjam/_openapi_client/api/mo_q/create_moq_access.py index 0b148cb..be0b70d 100644 --- a/fishjam/_openapi_client/api/mo_q/create_moq_token.py +++ b/fishjam/_openapi_client/api/mo_q/create_moq_access.py @@ -6,20 +6,20 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.error import Error -from ...models.moq_token import MoqToken -from ...models.moq_token_config import MoqTokenConfig +from ...models.moq_access import MoqAccess +from ...models.moq_access_config import MoqAccessConfig from ...types import UNSET, Response, Unset def _get_kwargs( *, - body: MoqTokenConfig | Unset = UNSET, + body: MoqAccessConfig | Unset = UNSET, ) -> dict[str, Any]: headers: dict[str, Any] = {} _kwargs: dict[str, Any] = { "method": "post", - "url": "/moq/token", + "url": "/moq/access", } if not isinstance(body, Unset): @@ -33,9 +33,9 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Error | MoqToken | None: +) -> Error | MoqAccess | None: if response.status_code == 200: - response_200 = MoqToken.from_dict(response.json()) + response_200 = MoqAccess.from_dict(response.json()) return response_200 @@ -62,7 +62,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Error | MoqToken]: +) -> Response[Error | MoqAccess]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -74,21 +74,21 @@ def _build_response( def sync_detailed( *, client: AuthenticatedClient, - body: MoqTokenConfig | Unset = UNSET, -) -> Response[Error | MoqToken]: - """Create a MoQ token + body: MoqAccessConfig | Unset = UNSET, +) -> Response[Error | MoqAccess]: + """Create MoQ access Issue a short-lived JWT for a Media over QUIC client. Args: - body (MoqTokenConfig | Unset): MoQ token configuration + body (MoqAccessConfig | Unset): MoQ access configuration 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] + Response[Error | MoqAccess] """ kwargs = _get_kwargs( @@ -105,21 +105,21 @@ def sync_detailed( def sync( *, client: AuthenticatedClient, - body: MoqTokenConfig | Unset = UNSET, -) -> Error | MoqToken | None: - """Create a MoQ token + body: MoqAccessConfig | Unset = UNSET, +) -> Error | MoqAccess | None: + """Create MoQ access Issue a short-lived JWT for a Media over QUIC client. Args: - body (MoqTokenConfig | Unset): MoQ token configuration + body (MoqAccessConfig | Unset): MoQ access configuration 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 + Error | MoqAccess """ return sync_detailed( @@ -131,21 +131,21 @@ def sync( async def asyncio_detailed( *, client: AuthenticatedClient, - body: MoqTokenConfig | Unset = UNSET, -) -> Response[Error | MoqToken]: - """Create a MoQ token + body: MoqAccessConfig | Unset = UNSET, +) -> Response[Error | MoqAccess]: + """Create MoQ access Issue a short-lived JWT for a Media over QUIC client. Args: - body (MoqTokenConfig | Unset): MoQ token configuration + body (MoqAccessConfig | Unset): MoQ access configuration 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] + Response[Error | MoqAccess] """ kwargs = _get_kwargs( @@ -160,21 +160,21 @@ async def asyncio_detailed( async def asyncio( *, client: AuthenticatedClient, - body: MoqTokenConfig | Unset = UNSET, -) -> Error | MoqToken | None: - """Create a MoQ token + body: MoqAccessConfig | Unset = UNSET, +) -> Error | MoqAccess | None: + """Create MoQ access Issue a short-lived JWT for a Media over QUIC client. Args: - body (MoqTokenConfig | Unset): MoQ token configuration + body (MoqAccessConfig | Unset): MoQ access configuration 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 + Error | MoqAccess """ return ( diff --git a/fishjam/_openapi_client/models/__init__.py b/fishjam/_openapi_client/models/__init__.py index 74df98f..622e2a5 100644 --- a/fishjam/_openapi_client/models/__init__.py +++ b/fishjam/_openapi_client/models/__init__.py @@ -5,8 +5,8 @@ from .audio_sample_rate import AudioSampleRate from .composition_info import CompositionInfo from .error import Error -from .moq_token import MoqToken -from .moq_token_config import MoqTokenConfig +from .moq_access import MoqAccess +from .moq_access_config import MoqAccessConfig from .peer import Peer from .peer_config import PeerConfig from .peer_details_response import PeerDetailsResponse @@ -54,8 +54,8 @@ "AudioSampleRate", "CompositionInfo", "Error", - "MoqToken", - "MoqTokenConfig", + "MoqAccess", + "MoqAccessConfig", "Peer", "PeerConfig", "PeerDetailsResponse", diff --git a/fishjam/_openapi_client/models/moq_token.py b/fishjam/_openapi_client/models/moq_access.py similarity index 57% rename from fishjam/_openapi_client/models/moq_token.py rename to fishjam/_openapi_client/models/moq_access.py index d1f04d9..bcdfda4 100644 --- a/fishjam/_openapi_client/models/moq_token.py +++ b/fishjam/_openapi_client/models/moq_access.py @@ -6,27 +6,34 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="MoqToken") +T = TypeVar("T", bound="MoqAccess") @_attrs_define -class MoqToken: - """Token for authorizing a MoQ relay connection +class MoqAccess: + """Connection details for a MoQ relay client Attributes: - token (str): JWT token for MoQ relay Example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1d - CI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJleHAiOjE3MTMzNjM2MDB9.abc123. + connection_url (str): Relay connection URL with the JWT embedded as a `?jwt=` query parameter. Pass directly to + a MoQ client SDK. Example: https://relay.fishjam.io/abc123?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.... + token (str): JWT authorizing the MoQ relay connection, also embedded in `connection_url` Example: eyJhbGciOiJIUz + I1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1dCI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJle + HAiOjE3MTMzNjM2MDB9.abc123. """ + connection_url: str token: str additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + connection_url = self.connection_url + token = self.token field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({ + "connection_url": connection_url, "token": token, }) @@ -35,14 +42,17 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) + connection_url = d.pop("connection_url") + token = d.pop("token") - moq_token = cls( + moq_access = cls( + connection_url=connection_url, token=token, ) - moq_token.additional_properties = d - return moq_token + moq_access.additional_properties = d + return moq_access @property def additional_keys(self) -> list[str]: diff --git a/fishjam/_openapi_client/models/moq_token_config.py b/fishjam/_openapi_client/models/moq_access_config.py similarity index 92% rename from fishjam/_openapi_client/models/moq_token_config.py rename to fishjam/_openapi_client/models/moq_access_config.py index fd46900..ee64e4e 100644 --- a/fishjam/_openapi_client/models/moq_token_config.py +++ b/fishjam/_openapi_client/models/moq_access_config.py @@ -7,12 +7,12 @@ from ..types import UNSET, Unset -T = TypeVar("T", bound="MoqTokenConfig") +T = TypeVar("T", bound="MoqAccessConfig") @_attrs_define -class MoqTokenConfig: - """MoQ token configuration +class MoqAccessConfig: + """MoQ access configuration Attributes: publish_path (None | str | Unset): Path under the root the token grants publish access to Example: my-stream. @@ -68,9 +68,9 @@ def _parse_subscribe_path(data: object) -> None | str | Unset: subscribe_path = _parse_subscribe_path(d.pop("subscribePath", UNSET)) - moq_token_config = cls( + moq_access_config = cls( publish_path=publish_path, subscribe_path=subscribe_path, ) - return moq_token_config + return moq_access_config diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index a2f612f..5f165cb 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -8,7 +8,7 @@ validate_credentials as credentials_validate_credentials, ) from fishjam._openapi_client.api.mo_q import ( - create_moq_token as moq_create_token, + create_moq_access as moq_create_access, ) from fishjam._openapi_client.api.rooms import add_peer as room_add_peer from fishjam._openapi_client.api.rooms import create_room as room_create_room @@ -29,8 +29,8 @@ AgentOutput, AudioFormat, AudioSampleRate, - MoqToken, - MoqTokenConfig, + MoqAccess, + MoqAccessConfig, Peer, PeerConfig, PeerDetailsResponse, @@ -415,29 +415,31 @@ def create_livestream_streamer_token(self, room_id: str) -> str: return response.token - def create_moq_token( + def create_moq_access( self, publish_path: str | None = None, subscribe_path: str | None = None, - ) -> str: - """Generates a MoQ token. + ) -> MoqAccess: + """Generates MoQ relay connection details. Args: - publish_path: Path the token grants publish access to. - subscribe_path: Path the token grants subscribe access to. + publish_path: Path the access grants publish access to. + subscribe_path: Path the access grants subscribe access to. Returns: - str: The generated token. + MoqAccess: The relay connection details, containing the + ``connection_url`` (with the JWT embedded as a ``?jwt=`` query + parameter) and the ``token`` itself. """ - config = MoqTokenConfig( + config = MoqAccessConfig( publish_path=publish_path, subscribe_path=subscribe_path ) response = cast( - MoqToken, - self._request(moq_create_token, body=config), + MoqAccess, + self._request(moq_create_access, body=config), ) - return response.token + return response def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): """Subscribes a peer to all tracks of another peer. diff --git a/pyproject.toml b/pyproject.toml index 0aaf55c..e3d3a7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "fishjam-server-sdk" -version = "0.28.0" +version = "0.28.1" description = "Python server SDK for the Fishjam" authors = [{ name = "Fishjam Team", email = "contact@fishjam.io" }] requires-python = ">=3.10" diff --git a/tests/test_room_api.py b/tests/test_room_api.py index d010e2f..186b902 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -5,6 +5,7 @@ from fishjam import ( FishjamClient, + MoqAccess, Peer, PeerOptions, PeerOptionsVapi, @@ -313,30 +314,36 @@ def test_invalid(self, room_api: FishjamClient): room_api.create_livestream_streamer_token(room.id) -class TestCreateMoqToken: +class TestCreateMoqAccess: def test_no_params(self, room_api: FishjamClient): with pytest.raises(BadRequestError): - room_api.create_moq_token() + room_api.create_moq_access() def test_valid_publish(self, room_api: FishjamClient): - token = room_api.create_moq_token(publish_path="test-stream") + access = room_api.create_moq_access(publish_path="test-stream") - assert isinstance(token, str) + assert isinstance(access, MoqAccess) + assert isinstance(access.connection_url, str) + assert isinstance(access.token, str) def test_valid_subscribe(self, room_api: FishjamClient): - token = room_api.create_moq_token(subscribe_path="test-stream") + access = room_api.create_moq_access(subscribe_path="test-stream") - assert isinstance(token, str) + assert isinstance(access, MoqAccess) + assert isinstance(access.connection_url, str) + assert isinstance(access.token, str) def test_valid_both(self, room_api: FishjamClient): - token = room_api.create_moq_token( + access = room_api.create_moq_access( publish_path="test-stream", subscribe_path="test-stream" ) - assert isinstance(token, str) + assert isinstance(access, MoqAccess) + assert isinstance(access.connection_url, str) + assert isinstance(access.token, str) def test_unauthorized(self): room_api = FishjamClient(FISHJAM_ID, "invalid") with pytest.raises(UnauthorizedError): - room_api.create_moq_token(publish_path="test-stream") + room_api.create_moq_access(publish_path="test-stream") diff --git a/uv.lock b/uv.lock index 799e891..906df31 100644 --- a/uv.lock +++ b/uv.lock @@ -679,7 +679,7 @@ wheels = [ [[package]] name = "fishjam-server-sdk" -version = "0.28.0" +version = "0.28.1" source = { editable = "." } dependencies = [ { name = "aenum" },