Fishjam Python Server SDK
Python server SDK for the Fishjam.
Read the docs here
Installation
pip install fishjam-server-sdk
Usage
The SDK exports two main classes for interacting with Fishjam server:
FishjamClient and FishjamNotifier.
FishjamClient wraps http REST api calls, while FishjamNotifier is responsible for receiving real-time updates from the server.
FishjamClient
Create a FishjamClient instance, providing the fishjam server address and api token
from fishjam import FishjamClient
fishjam_client = FishjamClient(fishjam_id="<fishjam_id>", management_token="<management_token>")
You can use it to interact with Fishjam to manage rooms and peers
# Create a room
options = RoomOptions(video_codec="h264", webhook_url="http://localhost:5000/webhook")
room = fishjam_client.create_room(options=options)
# Room(components=[], config=RoomConfig(max_peers=None, video_codec=<RoomConfigVideoCodec.H264: 'h264'>, webhook_url='http://localhost:5000/webhook'), id='1d905478-ccfc-44d6-a6e7-8ccb1b38d955', peers=[])
# Add peer to the room
peer, token = fishjam_client.create_peer(room.id)
# Peer(id='b1232c7e-c969-4450-acdf-ea24f3cdd7f6', status=<PeerStatus.DISCONNECTED: 'disconnected'>, type='webrtc'), 'M8TUGhj-L11KpyG-2zBPIo'
All methods in FishjamClient may raise one of the exceptions deriving from fishjam.errors.HTTPError. They are defined in fishjam.errors.
FishjamNotifier
FishjamNotifier allows for receiving real-time updates from the Fishjam Server.
You can read more about notifications in the Fishjam Docs.
Create FishjamNotifier instance
from fishjam import FishjamNotifier
fishjam_notifier = FishjamNotifier(fishjam_id='<fishjam_id>', management_token='<management_token>')
Then define a handler for incoming messages
@notifier.on_server_notification
def handle_notification(server_notification):
print(f'Received a notification: {server_notification}')
After that you can start the notifier
async def test_notifier():
notifier_task = asyncio.create_task(fishjam_notifier.connect())
# Wait for notifier to be ready to receive messages
await fishjam_notifier.wait_ready()
# Create a room to trigger a server notification
fishjam_client = FishjamClient()
fishjam_client.create_room()
await notifier_task
asyncio.run(test_notifier())
# Received a notification: ServerMessageRoomCreated(room_id='69a3fd1a-6a4d-47bc-ae54-0c72b0d05e29')
License
Licensed under the Apache License, Version 2.0
Fishjam is created by Software Mansion
Since 2012 Software Mansion is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – Hire us.
1""".. include:: ../README.md""" 2 3# pylint: disable=locally-disabled, no-name-in-module, import-error 4 5# Exceptions and Server Messages 6 7# API 8# pylint: disable=locally-disabled, no-name-in-module, import-error 9 10# Exceptions and Server Messages 11from fishjam import agent, errors, events, integrations, peer, room, version 12from fishjam._openapi_client.models import PeerMetadata 13 14# API 15from fishjam._webhook_notifier import ( 16 decode_server_notifications, 17 receive_binary, 18 verify_webhook_signature, 19) 20from fishjam._ws_notifier import FishjamNotifier 21from fishjam.api._fishjam_client import ( 22 AgentOptions, 23 AgentOutputOptions, 24 FishjamClient, 25 MoqAccess, 26 Peer, 27 PeerOptions, 28 PeerOptionsVapi, 29 Room, 30 RoomOptions, 31) 32from fishjam.errors import InvalidFishjamCredentialsError, MissingFishjamIdError 33 34__version__ = version.__version__ 35 36__all__ = [ 37 "FishjamClient", 38 "FishjamNotifier", 39 "decode_server_notifications", 40 "receive_binary", 41 "verify_webhook_signature", 42 "PeerMetadata", 43 "PeerOptions", 44 "PeerOptionsVapi", 45 "RoomOptions", 46 "AgentOptions", 47 "AgentOutputOptions", 48 "Room", 49 "Peer", 50 "MoqAccess", 51 "MissingFishjamIdError", 52 "InvalidFishjamCredentialsError", 53 "events", 54 "errors", 55 "room", 56 "peer", 57 "agent", 58 "integrations", 59] 60 61 62__docformat__ = "restructuredtext"
164class FishjamClient(Client): 165 """Allows for managing rooms.""" 166 167 def __init__( 168 self, 169 fishjam_id: str, 170 management_token: str, 171 ): 172 """Create a FishjamClient instance. 173 174 Does not contact the Fishjam backend — use :meth:`create_and_verify` 175 or :meth:`check_credentials` to verify credentials live. 176 177 Args: 178 fishjam_id: The unique identifier for the Fishjam instance. 179 management_token: The token used for authenticating management operations. 180 """ 181 super().__init__(fishjam_id=fishjam_id, management_token=management_token) 182 183 @classmethod 184 def create_and_verify( 185 cls, *, fishjam_id: str, management_token: str 186 ) -> "FishjamClient": 187 """Construct a FishjamClient and verify its credentials against the backend. 188 189 Args: 190 fishjam_id: The unique identifier for the Fishjam instance. 191 management_token: The token used for authenticating management operations. 192 193 Returns: 194 FishjamClient: A client whose credentials have been verified. 195 196 Raises: 197 InvalidFishjamCredentialsError: If the token is rejected. 198 """ 199 client = cls(fishjam_id=fishjam_id, management_token=management_token) 200 client.check_credentials() 201 return client 202 203 def check_credentials(self) -> None: 204 """Verify the management token via a single ``/validate`` call. 205 206 Raises: 207 InvalidFishjamCredentialsError: If the token is rejected. 208 """ 209 response = credentials_validate_credentials.sync_detailed(client=self.client) 210 self._handle_deprecation_header(response.headers) 211 212 if response.status_code == HTTPStatus.NOT_FOUND: 213 raise InvalidFishjamCredentialsError("Invalid Fishjam credentials") 214 215 def create_peer( 216 self, 217 room_id: str, 218 options: PeerOptions | None = None, 219 ) -> tuple[Peer, str]: 220 """Creates a peer in the room. 221 222 Args: 223 room_id: The ID of the room where the peer will be created. 224 options: Configuration options for the peer. Defaults to None. 225 226 Returns: 227 A tuple containing: 228 - Peer: The created peer object. 229 - str: The peer token needed to authenticate to Fishjam. 230 """ 231 options = options or PeerOptions() 232 233 peer_metadata = self.__parse_peer_metadata(options.metadata) 234 peer_options = PeerOptionsWebRTC( 235 metadata=peer_metadata, 236 subscribe_mode=SubscribeMode(options.subscribe_mode), 237 ) 238 body = PeerConfigWebRTC(type_=PeerConfigWebRTCType.WEBRTC, options=peer_options) 239 240 resp = cast( 241 PeerDetailsResponse, 242 self._request(room_add_peer, room_id=room_id, body=body), 243 ) 244 245 return (resp.data.peer, resp.data.token) 246 247 def create_agent(self, room_id: str, options: AgentOptions | None = None): 248 """Creates an agent in the room. 249 250 Args: 251 room_id: The ID of the room where the agent will be created. 252 options: Configuration options for the agent. Defaults to None. 253 254 Returns: 255 Agent: The created agent instance initialized with peer ID, room ID, token, 256 and Fishjam URL. 257 """ 258 options = options or AgentOptions() 259 body = PeerConfigAgent( 260 type_=PeerConfigAgentType.AGENT, 261 options=PeerOptionsAgent( 262 output=AgentOutput( 263 audio_format=AudioFormat(options.output.audio_format), 264 audio_sample_rate=AudioSampleRate(options.output.audio_sample_rate), 265 ), 266 subscribe_mode=SubscribeMode(options.subscribe_mode), 267 ), 268 ) 269 270 resp = cast( 271 PeerDetailsResponse, 272 self._request(room_add_peer, room_id=room_id, body=body), 273 ) 274 275 socket_base_url = self._peer_socket_base_url(resp.data.peer_websocket_url) 276 return Agent(resp.data.peer.id, room_id, resp.data.token, socket_base_url) 277 278 def _peer_socket_base_url(self, peer_websocket_url: str | Unset) -> str: 279 if isinstance(peer_websocket_url, Unset) or not peer_websocket_url: 280 return self._fishjam_url 281 282 url = peer_websocket_url 283 if "://" not in url: 284 url = f"https://{url}" 285 for suffix in ("/socket/peer/websocket", "/socket/agent/websocket"): 286 url = url.removesuffix(suffix) 287 return url 288 289 def create_vapi_agent( 290 self, 291 room_id: str, 292 options: PeerOptionsVapi, 293 ) -> Peer: 294 """Creates a vapi agent in the room. 295 296 Args: 297 room_id: The ID of the room where the vapi agent will be created. 298 options: Configuration options for the vapi peer. 299 300 Returns: 301 - Peer: The created peer object. 302 """ 303 body = PeerConfigVAPI(type_=PeerConfigVAPIType.VAPI, options=options) 304 305 resp = cast( 306 PeerDetailsResponse, 307 self._request(room_add_peer, room_id=room_id, body=body), 308 ) 309 310 return resp.data.peer 311 312 def create_room(self, options: RoomOptions | None = None) -> Room: 313 """Creates a new room. 314 315 Args: 316 options: Configuration options for the room. Defaults to None. 317 318 Returns: 319 Room: The created Room object. 320 """ 321 options = options or RoomOptions() 322 323 if options.video_codec is None: 324 codec = UNSET 325 else: 326 codec = VideoCodec(options.video_codec) 327 328 config = RoomConfig( 329 max_peers=options.max_peers, 330 video_codec=codec, 331 webhook_url=options.webhook_url, 332 room_type=RoomType(options.room_type), 333 public=options.public, 334 batch_webhook_notifications=options.batch_webhook_notifications, 335 ) 336 337 room = cast( 338 RoomCreateDetailsResponse, self._request(room_create_room, body=config) 339 ).data.room 340 341 return Room(config=room.config, id=room.id, peers=room.peers) 342 343 def get_all_rooms(self) -> list[Room]: 344 """Returns list of all rooms. 345 346 Returns: 347 list[Room]: A list of all available Room objects. 348 """ 349 rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data 350 351 return [ 352 Room(config=room.config, id=room.id, peers=room.peers) for room in rooms 353 ] 354 355 def get_room(self, room_id: str) -> Room: 356 """Returns room with the given id. 357 358 Args: 359 room_id: The ID of the room to retrieve. 360 361 Returns: 362 Room: The Room object corresponding to the given ID. 363 """ 364 room = cast( 365 RoomDetailsResponse, self._request(room_get_room, room_id=room_id) 366 ).data 367 368 return Room(config=room.config, id=room.id, peers=room.peers) 369 370 def delete_peer(self, room_id: str, peer_id: str) -> None: 371 """Deletes a peer from a room. 372 373 Args: 374 room_id: The ID of the room the peer belongs to. 375 peer_id: The ID of the peer to delete. 376 """ 377 return self._request(room_delete_peer, id=peer_id, room_id=room_id) 378 379 def delete_room(self, room_id: str) -> None: 380 """Deletes a room. 381 382 Args: 383 room_id: The ID of the room to delete. 384 """ 385 return self._request(room_delete_room, room_id=room_id) 386 387 def refresh_peer_token(self, room_id: str, peer_id: str) -> str: 388 """Refreshes a peer token. 389 390 Args: 391 room_id: The ID of the room. 392 peer_id: The ID of the peer whose token needs refreshing. 393 394 Returns: 395 str: The new peer token. 396 """ 397 response = cast( 398 PeerRefreshTokenResponse, 399 self._request(room_refresh_token, id=peer_id, room_id=room_id), 400 ) 401 402 return response.data.token 403 404 def create_livestream_viewer_token(self, room_id: str) -> str: 405 """Generates a viewer token for livestream rooms. 406 407 Args: 408 room_id: The ID of the livestream room. 409 410 Returns: 411 str: The generated viewer token. 412 """ 413 response = cast( 414 ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id) 415 ) 416 417 return response.token 418 419 def create_livestream_streamer_token(self, room_id: str) -> str: 420 """Generates a streamer token for livestream rooms. 421 422 Args: 423 room_id: The ID of the livestream room. 424 425 Returns: 426 str: The generated streamer token. 427 """ 428 response = cast( 429 StreamerToken, 430 self._request(streamer_generate_streamer_token, room_id=room_id), 431 ) 432 433 return response.token 434 435 def create_moq_access( 436 self, 437 publish_path: str | None = None, 438 subscribe_path: str | None = None, 439 ) -> MoqAccess: 440 """Generates MoQ relay connection details. 441 442 Args: 443 publish_path: Path the access grants publish access to. 444 subscribe_path: Path the access grants subscribe access to. 445 446 Returns: 447 MoqAccess: The relay connection details, containing the 448 ``connection_url`` (with the JWT embedded as a ``?jwt=`` query 449 parameter) and the ``token`` itself. 450 """ 451 config = MoqAccessConfig( 452 publish_path=publish_path, subscribe_path=subscribe_path 453 ) 454 response = cast( 455 MoqAccess, 456 self._request(moq_create_access, body=config), 457 ) 458 459 return response 460 461 def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): 462 """Subscribes a peer to all tracks of another peer. 463 464 Args: 465 room_id: The ID of the room. 466 peer_id: The ID of the subscribing peer. 467 target_peer_id: The ID of the peer to subscribe to. 468 """ 469 self._request( 470 room_subscribe_peer, 471 room_id=room_id, 472 id=peer_id, 473 peer_id=target_peer_id, 474 ) 475 476 def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]): 477 """Subscribes a peer to specific tracks of another peer. 478 479 Args: 480 room_id: The ID of the room. 481 peer_id: The ID of the subscribing peer. 482 track_ids: A list of track IDs to subscribe to. 483 """ 484 self._request( 485 room_subscribe_tracks, 486 room_id=room_id, 487 id=peer_id, 488 body=SubscribeTracksBody(track_ids=track_ids), 489 ) 490 491 def __parse_peer_metadata(self, metadata: dict | None) -> WebRTCMetadata: 492 peer_metadata = WebRTCMetadata() 493 494 if not metadata: 495 return peer_metadata 496 497 for key, value in metadata.items(): 498 peer_metadata.additional_properties[key] = value 499 500 return peer_metadata
Allows for managing rooms.
167 def __init__( 168 self, 169 fishjam_id: str, 170 management_token: str, 171 ): 172 """Create a FishjamClient instance. 173 174 Does not contact the Fishjam backend — use :meth:`create_and_verify` 175 or :meth:`check_credentials` to verify credentials live. 176 177 Args: 178 fishjam_id: The unique identifier for the Fishjam instance. 179 management_token: The token used for authenticating management operations. 180 """ 181 super().__init__(fishjam_id=fishjam_id, management_token=management_token)
Create a FishjamClient instance.
Does not contact the Fishjam backend — use create_and_verify()
or check_credentials() to verify credentials live.
Args:
- fishjam_id: The unique identifier for the Fishjam instance.
- management_token: The token used for authenticating management operations.
183 @classmethod 184 def create_and_verify( 185 cls, *, fishjam_id: str, management_token: str 186 ) -> "FishjamClient": 187 """Construct a FishjamClient and verify its credentials against the backend. 188 189 Args: 190 fishjam_id: The unique identifier for the Fishjam instance. 191 management_token: The token used for authenticating management operations. 192 193 Returns: 194 FishjamClient: A client whose credentials have been verified. 195 196 Raises: 197 InvalidFishjamCredentialsError: If the token is rejected. 198 """ 199 client = cls(fishjam_id=fishjam_id, management_token=management_token) 200 client.check_credentials() 201 return client
Construct a FishjamClient and verify its credentials against the backend.
Args:
- fishjam_id: The unique identifier for the Fishjam instance.
- management_token: The token used for authenticating management operations.
Returns:
- FishjamClient: A client whose credentials have been verified.
Raises:
- InvalidFishjamCredentialsError: If the token is rejected.
203 def check_credentials(self) -> None: 204 """Verify the management token via a single ``/validate`` call. 205 206 Raises: 207 InvalidFishjamCredentialsError: If the token is rejected. 208 """ 209 response = credentials_validate_credentials.sync_detailed(client=self.client) 210 self._handle_deprecation_header(response.headers) 211 212 if response.status_code == HTTPStatus.NOT_FOUND: 213 raise InvalidFishjamCredentialsError("Invalid Fishjam credentials")
Verify the management token via a single /validate call.
Raises:
- InvalidFishjamCredentialsError: If the token is rejected.
215 def create_peer( 216 self, 217 room_id: str, 218 options: PeerOptions | None = None, 219 ) -> tuple[Peer, str]: 220 """Creates a peer in the room. 221 222 Args: 223 room_id: The ID of the room where the peer will be created. 224 options: Configuration options for the peer. Defaults to None. 225 226 Returns: 227 A tuple containing: 228 - Peer: The created peer object. 229 - str: The peer token needed to authenticate to Fishjam. 230 """ 231 options = options or PeerOptions() 232 233 peer_metadata = self.__parse_peer_metadata(options.metadata) 234 peer_options = PeerOptionsWebRTC( 235 metadata=peer_metadata, 236 subscribe_mode=SubscribeMode(options.subscribe_mode), 237 ) 238 body = PeerConfigWebRTC(type_=PeerConfigWebRTCType.WEBRTC, options=peer_options) 239 240 resp = cast( 241 PeerDetailsResponse, 242 self._request(room_add_peer, room_id=room_id, body=body), 243 ) 244 245 return (resp.data.peer, resp.data.token)
Creates a peer in the room.
Args:
- room_id: The ID of the room where the peer will be created.
- options: Configuration options for the peer. Defaults to None.
Returns:
- A tuple containing:
- Peer: The created peer object.
- str: The peer token needed to authenticate to Fishjam.
247 def create_agent(self, room_id: str, options: AgentOptions | None = None): 248 """Creates an agent in the room. 249 250 Args: 251 room_id: The ID of the room where the agent will be created. 252 options: Configuration options for the agent. Defaults to None. 253 254 Returns: 255 Agent: The created agent instance initialized with peer ID, room ID, token, 256 and Fishjam URL. 257 """ 258 options = options or AgentOptions() 259 body = PeerConfigAgent( 260 type_=PeerConfigAgentType.AGENT, 261 options=PeerOptionsAgent( 262 output=AgentOutput( 263 audio_format=AudioFormat(options.output.audio_format), 264 audio_sample_rate=AudioSampleRate(options.output.audio_sample_rate), 265 ), 266 subscribe_mode=SubscribeMode(options.subscribe_mode), 267 ), 268 ) 269 270 resp = cast( 271 PeerDetailsResponse, 272 self._request(room_add_peer, room_id=room_id, body=body), 273 ) 274 275 socket_base_url = self._peer_socket_base_url(resp.data.peer_websocket_url) 276 return Agent(resp.data.peer.id, room_id, resp.data.token, socket_base_url)
Creates an agent in the room.
Args:
- room_id: The ID of the room where the agent will be created.
- options: Configuration options for the agent. Defaults to None.
Returns:
- Agent: The created agent instance initialized with peer ID, room ID, token, and Fishjam URL.
289 def create_vapi_agent( 290 self, 291 room_id: str, 292 options: PeerOptionsVapi, 293 ) -> Peer: 294 """Creates a vapi agent in the room. 295 296 Args: 297 room_id: The ID of the room where the vapi agent will be created. 298 options: Configuration options for the vapi peer. 299 300 Returns: 301 - Peer: The created peer object. 302 """ 303 body = PeerConfigVAPI(type_=PeerConfigVAPIType.VAPI, options=options) 304 305 resp = cast( 306 PeerDetailsResponse, 307 self._request(room_add_peer, room_id=room_id, body=body), 308 ) 309 310 return resp.data.peer
Creates a vapi agent in the room.
Args:
- room_id: The ID of the room where the vapi agent will be created.
- options: Configuration options for the vapi peer.
- - Peer: The created peer object.
312 def create_room(self, options: RoomOptions | None = None) -> Room: 313 """Creates a new room. 314 315 Args: 316 options: Configuration options for the room. Defaults to None. 317 318 Returns: 319 Room: The created Room object. 320 """ 321 options = options or RoomOptions() 322 323 if options.video_codec is None: 324 codec = UNSET 325 else: 326 codec = VideoCodec(options.video_codec) 327 328 config = RoomConfig( 329 max_peers=options.max_peers, 330 video_codec=codec, 331 webhook_url=options.webhook_url, 332 room_type=RoomType(options.room_type), 333 public=options.public, 334 batch_webhook_notifications=options.batch_webhook_notifications, 335 ) 336 337 room = cast( 338 RoomCreateDetailsResponse, self._request(room_create_room, body=config) 339 ).data.room 340 341 return Room(config=room.config, id=room.id, peers=room.peers)
Creates a new room.
Args:
- options: Configuration options for the room. Defaults to None.
Returns:
- Room: The created Room object.
343 def get_all_rooms(self) -> list[Room]: 344 """Returns list of all rooms. 345 346 Returns: 347 list[Room]: A list of all available Room objects. 348 """ 349 rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data 350 351 return [ 352 Room(config=room.config, id=room.id, peers=room.peers) for room in rooms 353 ]
Returns list of all rooms.
Returns:
- list[Room]: A list of all available Room objects.
355 def get_room(self, room_id: str) -> Room: 356 """Returns room with the given id. 357 358 Args: 359 room_id: The ID of the room to retrieve. 360 361 Returns: 362 Room: The Room object corresponding to the given ID. 363 """ 364 room = cast( 365 RoomDetailsResponse, self._request(room_get_room, room_id=room_id) 366 ).data 367 368 return Room(config=room.config, id=room.id, peers=room.peers)
Returns room with the given id.
Args:
- room_id: The ID of the room to retrieve.
Returns:
- Room: The Room object corresponding to the given ID.
370 def delete_peer(self, room_id: str, peer_id: str) -> None: 371 """Deletes a peer from a room. 372 373 Args: 374 room_id: The ID of the room the peer belongs to. 375 peer_id: The ID of the peer to delete. 376 """ 377 return self._request(room_delete_peer, id=peer_id, room_id=room_id)
Deletes a peer from a room.
Args:
- room_id: The ID of the room the peer belongs to.
- peer_id: The ID of the peer to delete.
379 def delete_room(self, room_id: str) -> None: 380 """Deletes a room. 381 382 Args: 383 room_id: The ID of the room to delete. 384 """ 385 return self._request(room_delete_room, room_id=room_id)
Deletes a room.
Args:
- room_id: The ID of the room to delete.
387 def refresh_peer_token(self, room_id: str, peer_id: str) -> str: 388 """Refreshes a peer token. 389 390 Args: 391 room_id: The ID of the room. 392 peer_id: The ID of the peer whose token needs refreshing. 393 394 Returns: 395 str: The new peer token. 396 """ 397 response = cast( 398 PeerRefreshTokenResponse, 399 self._request(room_refresh_token, id=peer_id, room_id=room_id), 400 ) 401 402 return response.data.token
Refreshes a peer token.
Args:
- room_id: The ID of the room.
- peer_id: The ID of the peer whose token needs refreshing.
Returns:
- str: The new peer token.
404 def create_livestream_viewer_token(self, room_id: str) -> str: 405 """Generates a viewer token for livestream rooms. 406 407 Args: 408 room_id: The ID of the livestream room. 409 410 Returns: 411 str: The generated viewer token. 412 """ 413 response = cast( 414 ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id) 415 ) 416 417 return response.token
Generates a viewer token for livestream rooms.
Args:
- room_id: The ID of the livestream room.
Returns:
- str: The generated viewer token.
419 def create_livestream_streamer_token(self, room_id: str) -> str: 420 """Generates a streamer token for livestream rooms. 421 422 Args: 423 room_id: The ID of the livestream room. 424 425 Returns: 426 str: The generated streamer token. 427 """ 428 response = cast( 429 StreamerToken, 430 self._request(streamer_generate_streamer_token, room_id=room_id), 431 ) 432 433 return response.token
Generates a streamer token for livestream rooms.
Args:
- room_id: The ID of the livestream room.
Returns:
- str: The generated streamer token.
435 def create_moq_access( 436 self, 437 publish_path: str | None = None, 438 subscribe_path: str | None = None, 439 ) -> MoqAccess: 440 """Generates MoQ relay connection details. 441 442 Args: 443 publish_path: Path the access grants publish access to. 444 subscribe_path: Path the access grants subscribe access to. 445 446 Returns: 447 MoqAccess: The relay connection details, containing the 448 ``connection_url`` (with the JWT embedded as a ``?jwt=`` query 449 parameter) and the ``token`` itself. 450 """ 451 config = MoqAccessConfig( 452 publish_path=publish_path, subscribe_path=subscribe_path 453 ) 454 response = cast( 455 MoqAccess, 456 self._request(moq_create_access, body=config), 457 ) 458 459 return response
Generates MoQ relay connection details.
Args:
- publish_path: Path the access grants publish access to.
- subscribe_path: Path the access grants subscribe access to.
Returns:
- MoqAccess: The relay connection details, containing the
connection_url(with the JWT embedded as a?jwt=query- parameter) and the
tokenitself.
461 def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): 462 """Subscribes a peer to all tracks of another peer. 463 464 Args: 465 room_id: The ID of the room. 466 peer_id: The ID of the subscribing peer. 467 target_peer_id: The ID of the peer to subscribe to. 468 """ 469 self._request( 470 room_subscribe_peer, 471 room_id=room_id, 472 id=peer_id, 473 peer_id=target_peer_id, 474 )
Subscribes a peer to all tracks of another peer.
Args:
- room_id: The ID of the room.
- peer_id: The ID of the subscribing peer.
- target_peer_id: The ID of the peer to subscribe to.
476 def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]): 477 """Subscribes a peer to specific tracks of another peer. 478 479 Args: 480 room_id: The ID of the room. 481 peer_id: The ID of the subscribing peer. 482 track_ids: A list of track IDs to subscribe to. 483 """ 484 self._request( 485 room_subscribe_tracks, 486 room_id=room_id, 487 id=peer_id, 488 body=SubscribeTracksBody(track_ids=track_ids), 489 )
Subscribes a peer to specific tracks of another peer.
Args:
- room_id: The ID of the room.
- peer_id: The ID of the subscribing peer.
- track_ids: A list of track IDs to subscribe to.
Inherited Members
- fishjam.api._client.Client
- client
- warnings_shown
33class FishjamNotifier: 34 """Allows for receiving WebSocket messages from Fishjam.""" 35 36 def __init__( 37 self, 38 fishjam_id: str, 39 management_token: str, 40 ): 41 """Create a FishjamNotifier instance with an ID and management token.""" 42 websocket_url = get_fishjam_url(fishjam_id).replace("http", "ws") 43 self._fishjam_url = f"{websocket_url}/socket/server/websocket" 44 self._management_token: str = management_token 45 self._websocket: client.ClientConnection | None = None 46 self._ready: bool = False 47 48 self._ready_event: asyncio.Event | None = None 49 50 self._notification_handler: NotificationHandler | None = None 51 52 def on_server_notification(self, handler: NotificationHandler): 53 """Decorator for defining a handler for Fishjam notifications. 54 55 Args: 56 handler: The function to be registered as the notification handler. 57 58 Returns: 59 NotificationHandler: The original handler function (unmodified). 60 """ 61 self._notification_handler = handler 62 return handler 63 64 async def connect(self): 65 """Connects to Fishjam and listens for all incoming messages. 66 67 It runs until the connection isn't closed. 68 69 The incoming messages are handled by the functions defined using the 70 `on_server_notification` decorator. 71 72 The handler have to be defined before calling `connect`, 73 otherwise the messages won't be received. 74 """ 75 async with client.connect(self._fishjam_url) as websocket: 76 try: 77 self._websocket = websocket 78 await self._authenticate() 79 80 if self._notification_handler: 81 await self._subscribe_event( 82 event=ServerMessageEventType.EVENT_TYPE_SERVER_NOTIFICATION 83 ) 84 85 self._ready = True 86 if self._ready_event: 87 self._ready_event.set() 88 89 await self._receive_loop() 90 finally: 91 self._websocket = None 92 93 async def wait_ready(self) -> None: 94 """Waits until the notifier is connected and authenticated to Fishjam. 95 96 If already connected, returns immediately. 97 """ 98 if self._ready: 99 return 100 101 if self._ready_event is None: 102 self._ready_event = asyncio.Event() 103 104 await self._ready_event.wait() 105 106 async def _authenticate(self): 107 if not self._websocket: 108 raise RuntimeError("Websocket is not connected") 109 110 msg = ServerMessage( 111 auth_request=ServerMessageAuthRequest(token=self._management_token) 112 ) 113 await self._websocket.send(bytes(msg)) 114 115 try: 116 message = await self._websocket.recv(decode=False) 117 except ConnectionClosed as exception: 118 if "invalid token" in str(exception): 119 raise RuntimeError("Invalid management token") from exception 120 raise 121 122 message = ServerMessage().parse(message) 123 124 _type, message = betterproto.which_one_of(message, "content") 125 assert isinstance(message, ServerMessageAuthenticated) 126 127 async def _receive_loop(self): 128 if not self._websocket: 129 raise RuntimeError("Websocket is not connected") 130 if not self._notification_handler: 131 raise RuntimeError("Notification handler is not defined") 132 133 while True: 134 message = await self._websocket.recv(decode=False) 135 message = ServerMessage().parse(message) 136 _which, message = betterproto.which_one_of(message, "content") 137 138 if isinstance(message, ALLOWED_NOTIFICATIONS): 139 res = self._notification_handler(message) 140 if inspect.isawaitable(res): 141 await res 142 143 async def _subscribe_event(self, event: ServerMessageEventType): 144 if not self._websocket: 145 raise RuntimeError("Websocket is not connected") 146 147 request = ServerMessage(subscribe_request=ServerMessageSubscribeRequest(event)) 148 149 await self._websocket.send(bytes(request)) 150 message = cast(bytes, await self._websocket.recv()) 151 message = ServerMessage().parse(message) 152 _which, message = betterproto.which_one_of(message, "content") 153 assert isinstance(message, ServerMessageSubscribeResponse)
Allows for receiving WebSocket messages from Fishjam.
36 def __init__( 37 self, 38 fishjam_id: str, 39 management_token: str, 40 ): 41 """Create a FishjamNotifier instance with an ID and management token.""" 42 websocket_url = get_fishjam_url(fishjam_id).replace("http", "ws") 43 self._fishjam_url = f"{websocket_url}/socket/server/websocket" 44 self._management_token: str = management_token 45 self._websocket: client.ClientConnection | None = None 46 self._ready: bool = False 47 48 self._ready_event: asyncio.Event | None = None 49 50 self._notification_handler: NotificationHandler | None = None
Create a FishjamNotifier instance with an ID and management token.
52 def on_server_notification(self, handler: NotificationHandler): 53 """Decorator for defining a handler for Fishjam notifications. 54 55 Args: 56 handler: The function to be registered as the notification handler. 57 58 Returns: 59 NotificationHandler: The original handler function (unmodified). 60 """ 61 self._notification_handler = handler 62 return handler
Decorator for defining a handler for Fishjam notifications.
Args:
- handler: The function to be registered as the notification handler.
Returns:
- NotificationHandler: The original handler function (unmodified).
64 async def connect(self): 65 """Connects to Fishjam and listens for all incoming messages. 66 67 It runs until the connection isn't closed. 68 69 The incoming messages are handled by the functions defined using the 70 `on_server_notification` decorator. 71 72 The handler have to be defined before calling `connect`, 73 otherwise the messages won't be received. 74 """ 75 async with client.connect(self._fishjam_url) as websocket: 76 try: 77 self._websocket = websocket 78 await self._authenticate() 79 80 if self._notification_handler: 81 await self._subscribe_event( 82 event=ServerMessageEventType.EVENT_TYPE_SERVER_NOTIFICATION 83 ) 84 85 self._ready = True 86 if self._ready_event: 87 self._ready_event.set() 88 89 await self._receive_loop() 90 finally: 91 self._websocket = None
Connects to Fishjam and listens for all incoming messages.
It runs until the connection isn't closed.
The incoming messages are handled by the functions defined using the
on_server_notification decorator.
The handler have to be defined before calling connect,
otherwise the messages won't be received.
93 async def wait_ready(self) -> None: 94 """Waits until the notifier is connected and authenticated to Fishjam. 95 96 If already connected, returns immediately. 97 """ 98 if self._ready: 99 return 100 101 if self._ready_event is None: 102 self._ready_event = asyncio.Event() 103 104 await self._ready_event.wait()
Waits until the notifier is connected and authenticated to Fishjam.
If already connected, returns immediately.
46def decode_server_notifications(binary: bytes) -> List[AllowedNotification]: 47 """Decode a received protobuf payload into a list of notifications. 48 49 Handles both single notifications and batches transparently: a single 50 notification is returned as a one-element list, a batch is unpacked into 51 its members (in order), and anything unsupported yields an empty list. 52 53 The available notifications are listed in the `fishjam.events` module. 54 55 Args: 56 binary: The raw binary data received from the webhook. 57 58 Returns: 59 list[AllowedNotification]: The decoded notifications, in order. Empty 60 when the payload carries no supported notification. 61 """ 62 message = ServerMessage().parse(binary) 63 _which, content = betterproto.which_one_of(message, "content") 64 65 if isinstance(content, ServerMessageNotificationBatch): 66 return _unpack_batch(content) 67 68 if isinstance(content, ALLOWED_NOTIFICATIONS): 69 return [content] 70 71 return []
Decode a received protobuf payload into a list of notifications.
Handles both single notifications and batches transparently: a single notification is returned as a one-element list, a batch is unpacked into its members (in order), and anything unsupported yields an empty list.
The available notifications are listed in the fishjam.events module.
Args:
- binary: The raw binary data received from the webhook.
Returns:
- list[AllowedNotification]: The decoded notifications, in order. Empty when the payload carries no supported notification.
94def receive_binary( 95 binary: bytes, 96) -> Union[AllowedNotification, List[AllowedNotification], None]: 97 """Transforms a received protobuf notification into a notification instance. 98 99 .. deprecated:: 100 Use `decode_server_notifications` instead, which always returns a list 101 and handles batched payloads with a single, consistent return type. 102 103 The available notifications are listed in `fishjam.events` module. 104 105 Args: 106 binary: The raw binary data received from the webhook. 107 108 Returns: 109 AllowedNotification: A single notification when the payload carries one. 110 list[AllowedNotification]: The unpacked notifications, in order, when the 111 payload is a batch (webhook batching enabled). 112 None: When the payload is not a supported notification. 113 """ 114 warnings.warn( 115 "receive_binary is deprecated; use decode_server_notifications instead.", 116 DeprecationWarning, 117 stacklevel=2, 118 ) 119 120 message = ServerMessage().parse(binary) 121 _which, content = betterproto.which_one_of(message, "content") 122 123 if isinstance(content, ServerMessageNotificationBatch): 124 return _unpack_batch(content) 125 126 if isinstance(content, ALLOWED_NOTIFICATIONS): 127 return content 128 129 return None
Transforms a received protobuf notification into a notification instance.
Deprecated since version .
- Use
decode_server_notificationsinstead, which always returns a list - and handles batched payloads with a single, consistent return type.
The available notifications are listed in fishjam.events module.
Args:
- binary: The raw binary data received from the webhook.
Returns:
- AllowedNotification: A single notification when the payload carries one.
- list[AllowedNotification]: The unpacked notifications, in order, when the payload is a batch (webhook batching enabled).
- None: When the payload is not a supported notification.
74def verify_webhook_signature(body: bytes, signature: str, secret: str) -> bool: 75 """Verify the `x-fishjam-signature-256` header of a raw webhook body. 76 77 Accepts the `sha256=<hex>` format sent by Fishjam (the prefix is 78 optional) and compares in constant time. Call this with the raw request 79 body before passing it to `decode_server_notifications`. 80 81 Args: 82 body: The raw binary body of the webhook request. 83 signature: The value of the `x-fishjam-signature-256` header. 84 secret: The webhook secret configured in Fishjam. 85 86 Returns: 87 bool: True when the signature matches the body, False otherwise. 88 """ 89 expected = hmac.new(secret.encode(), body, "sha256").hexdigest() 90 provided = signature.strip().removeprefix("sha256=") 91 return hmac.compare_digest(provided, expected)
Verify the x-fishjam-signature-256 header of a raw webhook body.
Accepts the sha256=<hex> format sent by Fishjam (the prefix is
optional) and compares in constant time. Call this with the raw request
body before passing it to decode_server_notifications.
Args:
- body: The raw binary body of the webhook request.
- signature: The value of the
x-fishjam-signature-256header. - secret: The webhook secret configured in Fishjam.
Returns:
- bool: True when the signature matches the body, False otherwise.
13@_attrs_define 14class PeerMetadata: 15 """Custom metadata set by the peer 16 17 Example: 18 {'name': 'FishjamUser'} 19 20 """ 21 22 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 23 24 def to_dict(self) -> dict[str, Any]: 25 field_dict: dict[str, Any] = {} 26 field_dict.update(self.additional_properties) 27 28 return field_dict 29 30 @classmethod 31 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 32 d = dict(src_dict) 33 peer_metadata = cls() 34 35 peer_metadata.additional_properties = d 36 return peer_metadata 37 38 @property 39 def additional_keys(self) -> list[str]: 40 return list(self.additional_properties.keys()) 41 42 def __getitem__(self, key: str) -> Any: 43 return self.additional_properties[key] 44 45 def __setitem__(self, key: str, value: Any) -> None: 46 self.additional_properties[key] = value 47 48 def __delitem__(self, key: str) -> None: 49 del self.additional_properties[key] 50 51 def __contains__(self, key: str) -> bool: 52 return key in self.additional_properties
Custom metadata set by the peer
Example:
- {'name': 'FishjamUser'}
122@dataclass 123class PeerOptions: 124 """Options specific to a WebRTC Peer. 125 126 Attributes: 127 metadata: Peer metadata. 128 subscribe_mode: Configuration of peer's subscribing policy. 129 """ 130 131 metadata: dict[str, Any] | None = None 132 """Peer metadata""" 133 subscribe_mode: Literal["auto", "manual"] = "auto" 134 """Configuration of peer's subscribing policy"""
Options specific to a WebRTC Peer.
Attributes:
- metadata: Peer metadata.
- subscribe_mode: Configuration of peer's subscribing policy.
15@_attrs_define 16class PeerOptionsVapi: 17 """Options specific to the VAPI peer 18 19 Attributes: 20 api_key (str): VAPI API key 21 call_id (str): VAPI call ID 22 subscribe_mode (SubscribeMode | Unset): Configuration of peer's subscribing policy 23 """ 24 25 api_key: str 26 call_id: str 27 subscribe_mode: SubscribeMode | Unset = UNSET 28 29 def to_dict(self) -> dict[str, Any]: 30 api_key = self.api_key 31 32 call_id = self.call_id 33 34 subscribe_mode: str | Unset = UNSET 35 if not isinstance(self.subscribe_mode, Unset): 36 subscribe_mode = self.subscribe_mode.value 37 38 field_dict: dict[str, Any] = {} 39 40 field_dict.update({ 41 "apiKey": api_key, 42 "callId": call_id, 43 }) 44 if subscribe_mode is not UNSET: 45 field_dict["subscribeMode"] = subscribe_mode 46 47 return field_dict 48 49 @classmethod 50 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 51 d = dict(src_dict) 52 api_key = d.pop("apiKey") 53 54 call_id = d.pop("callId") 55 56 _subscribe_mode = d.pop("subscribeMode", UNSET) 57 subscribe_mode: SubscribeMode | Unset 58 if isinstance(_subscribe_mode, Unset): 59 subscribe_mode = UNSET 60 else: 61 subscribe_mode = SubscribeMode(_subscribe_mode) 62 63 peer_options_vapi = cls( 64 api_key=api_key, 65 call_id=call_id, 66 subscribe_mode=subscribe_mode, 67 ) 68 69 return peer_options_vapi
Options specific to the VAPI peer
Attributes:
- api_key (str): VAPI API key
- call_id (str): VAPI call ID
- subscribe_mode (SubscribeMode | Unset): Configuration of peer's subscribing policy
25def __init__(self, api_key, call_id, subscribe_mode=attr_dict['subscribe_mode'].default): 26 self.api_key = api_key 27 self.call_id = call_id 28 self.subscribe_mode = subscribe_mode
Method generated by attrs for class PeerOptionsVapi.
29 def to_dict(self) -> dict[str, Any]: 30 api_key = self.api_key 31 32 call_id = self.call_id 33 34 subscribe_mode: str | Unset = UNSET 35 if not isinstance(self.subscribe_mode, Unset): 36 subscribe_mode = self.subscribe_mode.value 37 38 field_dict: dict[str, Any] = {} 39 40 field_dict.update({ 41 "apiKey": api_key, 42 "callId": call_id, 43 }) 44 if subscribe_mode is not UNSET: 45 field_dict["subscribeMode"] = subscribe_mode 46 47 return field_dict
49 @classmethod 50 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 51 d = dict(src_dict) 52 api_key = d.pop("apiKey") 53 54 call_id = d.pop("callId") 55 56 _subscribe_mode = d.pop("subscribeMode", UNSET) 57 subscribe_mode: SubscribeMode | Unset 58 if isinstance(_subscribe_mode, Unset): 59 subscribe_mode = UNSET 60 else: 61 subscribe_mode = SubscribeMode(_subscribe_mode) 62 63 peer_options_vapi = cls( 64 api_key=api_key, 65 call_id=call_id, 66 subscribe_mode=subscribe_mode, 67 ) 68 69 return peer_options_vapi
85@dataclass 86class RoomOptions: 87 """Description of a room options. 88 89 Attributes: 90 max_peers: Maximum amount of peers allowed into the room. 91 video_codec: Enforces video codec for each peer in the room. 92 webhook_url: URL where Fishjam notifications will be sent. 93 room_type: The use-case of the room. If not provided, this defaults 94 to conference. 95 public: True if livestream viewers can omit specifying a token. 96 batch_webhook_notifications: If true, webhook notifications for this room 97 are coalesced into a single NotificationBatch per HTTP send instead 98 of one request per notification. 99 """ 100 101 max_peers: int | None = None 102 """Maximum amount of peers allowed into the room""" 103 video_codec: Literal["h264", "vp8"] | None = None 104 """Enforces video codec for each peer in the room""" 105 webhook_url: str | None = None 106 """URL where Fishjam notifications will be sent""" 107 room_type: Literal[ 108 "conference", 109 "audio_only", 110 "livestream", 111 "full_feature", 112 "broadcaster", 113 "audio_only_livestream", 114 ] = "conference" 115 """The use-case of the room. If not provided, this defaults to conference.""" 116 public: bool = False 117 """True if livestream viewers can omit specifying a token.""" 118 batch_webhook_notifications: bool = False 119 """Coalesce webhook notifications into a single NotificationBatch per send."""
Description of a room options.
Attributes:
- max_peers: Maximum amount of peers allowed into the room.
- video_codec: Enforces video codec for each peer in the room.
- webhook_url: URL where Fishjam notifications will be sent.
- room_type: The use-case of the room. If not provided, this defaults to conference.
- public: True if livestream viewers can omit specifying a token.
- batch_webhook_notifications: If true, webhook notifications for this room are coalesced into a single NotificationBatch per HTTP send instead of one request per notification.
150@dataclass 151class AgentOptions: 152 """Options specific to an Agent Peer. 153 154 Attributes: 155 output: Configuration for the agent's output options. 156 subscribe_mode: Configuration of peer's subscribing policy. 157 """ 158 159 output: AgentOutputOptions = field(default_factory=AgentOutputOptions) 160 161 subscribe_mode: Literal["auto", "manual"] = "auto"
Options specific to an Agent Peer.
Attributes:
- output: Configuration for the agent's output options.
- subscribe_mode: Configuration of peer's subscribing policy.
137@dataclass 138class AgentOutputOptions: 139 """Options of the desired format of audio tracks going from Fishjam to the agent. 140 141 Attributes: 142 audio_format: The format of the audio stream (e.g., 'pcm16'). 143 audio_sample_rate: The sample rate of the audio stream. 144 """ 145 146 audio_format: Literal["pcm16"] = "pcm16" 147 audio_sample_rate: Literal[16000, 24000] = 16000
Options of the desired format of audio tracks going from Fishjam to the agent.
Attributes:
- audio_format: The format of the audio stream (e.g., 'pcm16').
- audio_sample_rate: The sample rate of the audio stream.
67@dataclass 68class Room: 69 """Description of the room state. 70 71 Attributes: 72 config: Room configuration. 73 id: Room ID. 74 peers: List of all peers. 75 """ 76 77 config: RoomConfig 78 """Room configuration""" 79 id: str 80 """Room ID""" 81 peers: list[Peer] 82 """List of all peers"""
Description of the room state.
Attributes:
- config: Room configuration.
- id: Room ID.
- peers: List of all peers.
23@_attrs_define 24class Peer: 25 """Describes peer status 26 27 Attributes: 28 id (str): Assigned peer id Example: 4a1c1164-5fb7-425d-89d7-24cdb8fff1cf. 29 metadata (None | PeerMetadata): Custom metadata set by the peer Example: {'name': 'FishjamUser'}. 30 status (PeerStatus): Informs about the peer status Example: disconnected. 31 subscribe_mode (SubscribeMode): Configuration of peer's subscribing policy 32 subscriptions (Subscriptions): Describes peer's subscriptions in manual mode 33 tracks (list[Track]): List of all peer's tracks 34 type_ (PeerType): Peer type Example: webrtc. 35 """ 36 37 id: str 38 metadata: None | PeerMetadata 39 status: PeerStatus 40 subscribe_mode: SubscribeMode 41 subscriptions: Subscriptions 42 tracks: list[Track] 43 type_: PeerType 44 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 45 46 def to_dict(self) -> dict[str, Any]: 47 from ..models.peer_metadata import PeerMetadata 48 49 id = self.id 50 51 metadata: dict[str, Any] | None 52 if isinstance(self.metadata, PeerMetadata): 53 metadata = self.metadata.to_dict() 54 else: 55 metadata = self.metadata 56 57 status = self.status.value 58 59 subscribe_mode = self.subscribe_mode.value 60 61 subscriptions = self.subscriptions.to_dict() 62 63 tracks = [] 64 for tracks_item_data in self.tracks: 65 tracks_item = tracks_item_data.to_dict() 66 tracks.append(tracks_item) 67 68 type_ = self.type_.value 69 70 field_dict: dict[str, Any] = {} 71 field_dict.update(self.additional_properties) 72 field_dict.update({ 73 "id": id, 74 "metadata": metadata, 75 "status": status, 76 "subscribeMode": subscribe_mode, 77 "subscriptions": subscriptions, 78 "tracks": tracks, 79 "type": type_, 80 }) 81 82 return field_dict 83 84 @classmethod 85 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 86 from ..models.peer_metadata import PeerMetadata 87 from ..models.subscriptions import Subscriptions 88 from ..models.track import Track 89 90 d = dict(src_dict) 91 id = d.pop("id") 92 93 def _parse_metadata(data: object) -> None | PeerMetadata: 94 if data is None: 95 return data 96 try: 97 if not isinstance(data, dict): 98 raise TypeError() 99 componentsschemas_peer_metadata_type_0 = PeerMetadata.from_dict(data) 100 101 return componentsschemas_peer_metadata_type_0 102 except (TypeError, ValueError, AttributeError, KeyError): 103 pass 104 return cast(None | PeerMetadata, data) 105 106 metadata = _parse_metadata(d.pop("metadata")) 107 108 status = PeerStatus(d.pop("status")) 109 110 subscribe_mode = SubscribeMode(d.pop("subscribeMode")) 111 112 subscriptions = Subscriptions.from_dict(d.pop("subscriptions")) 113 114 tracks = [] 115 _tracks = d.pop("tracks") 116 for tracks_item_data in _tracks: 117 tracks_item = Track.from_dict(tracks_item_data) 118 119 tracks.append(tracks_item) 120 121 type_ = PeerType(d.pop("type")) 122 123 peer = cls( 124 id=id, 125 metadata=metadata, 126 status=status, 127 subscribe_mode=subscribe_mode, 128 subscriptions=subscriptions, 129 tracks=tracks, 130 type_=type_, 131 ) 132 133 peer.additional_properties = d 134 return peer 135 136 @property 137 def additional_keys(self) -> list[str]: 138 return list(self.additional_properties.keys()) 139 140 def __getitem__(self, key: str) -> Any: 141 return self.additional_properties[key] 142 143 def __setitem__(self, key: str, value: Any) -> None: 144 self.additional_properties[key] = value 145 146 def __delitem__(self, key: str) -> None: 147 del self.additional_properties[key] 148 149 def __contains__(self, key: str) -> bool: 150 return key in self.additional_properties
Describes peer status
Attributes:
- id (str): Assigned peer id Example: 4a1c1164-5fb7-425d-89d7-24cdb8fff1cf.
- metadata (None | PeerMetadata): Custom metadata set by the peer Example: {'name': 'FishjamUser'}.
- status (PeerStatus): Informs about the peer status Example: disconnected.
- subscribe_mode (SubscribeMode): Configuration of peer's subscribing policy
- subscriptions (Subscriptions): Describes peer's subscriptions in manual mode
- tracks (list[Track]): List of all peer's tracks
- type_ (PeerType): Peer type Example: webrtc.
30def __init__(self, id, metadata, status, subscribe_mode, subscriptions, tracks, type_): 31 self.id = id 32 self.metadata = metadata 33 self.status = status 34 self.subscribe_mode = subscribe_mode 35 self.subscriptions = subscriptions 36 self.tracks = tracks 37 self.type_ = type_ 38 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class Peer.
46 def to_dict(self) -> dict[str, Any]: 47 from ..models.peer_metadata import PeerMetadata 48 49 id = self.id 50 51 metadata: dict[str, Any] | None 52 if isinstance(self.metadata, PeerMetadata): 53 metadata = self.metadata.to_dict() 54 else: 55 metadata = self.metadata 56 57 status = self.status.value 58 59 subscribe_mode = self.subscribe_mode.value 60 61 subscriptions = self.subscriptions.to_dict() 62 63 tracks = [] 64 for tracks_item_data in self.tracks: 65 tracks_item = tracks_item_data.to_dict() 66 tracks.append(tracks_item) 67 68 type_ = self.type_.value 69 70 field_dict: dict[str, Any] = {} 71 field_dict.update(self.additional_properties) 72 field_dict.update({ 73 "id": id, 74 "metadata": metadata, 75 "status": status, 76 "subscribeMode": subscribe_mode, 77 "subscriptions": subscriptions, 78 "tracks": tracks, 79 "type": type_, 80 }) 81 82 return field_dict
84 @classmethod 85 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 86 from ..models.peer_metadata import PeerMetadata 87 from ..models.subscriptions import Subscriptions 88 from ..models.track import Track 89 90 d = dict(src_dict) 91 id = d.pop("id") 92 93 def _parse_metadata(data: object) -> None | PeerMetadata: 94 if data is None: 95 return data 96 try: 97 if not isinstance(data, dict): 98 raise TypeError() 99 componentsschemas_peer_metadata_type_0 = PeerMetadata.from_dict(data) 100 101 return componentsschemas_peer_metadata_type_0 102 except (TypeError, ValueError, AttributeError, KeyError): 103 pass 104 return cast(None | PeerMetadata, data) 105 106 metadata = _parse_metadata(d.pop("metadata")) 107 108 status = PeerStatus(d.pop("status")) 109 110 subscribe_mode = SubscribeMode(d.pop("subscribeMode")) 111 112 subscriptions = Subscriptions.from_dict(d.pop("subscriptions")) 113 114 tracks = [] 115 _tracks = d.pop("tracks") 116 for tracks_item_data in _tracks: 117 tracks_item = Track.from_dict(tracks_item_data) 118 119 tracks.append(tracks_item) 120 121 type_ = PeerType(d.pop("type")) 122 123 peer = cls( 124 id=id, 125 metadata=metadata, 126 status=status, 127 subscribe_mode=subscribe_mode, 128 subscriptions=subscriptions, 129 tracks=tracks, 130 type_=type_, 131 ) 132 133 peer.additional_properties = d 134 return peer
13@_attrs_define 14class MoqAccess: 15 """Connection details for a MoQ relay client 16 17 Attributes: 18 connection_url (str): Relay connection URL with the JWT embedded as a `?jwt=` query parameter. Pass directly to 19 a MoQ client SDK. Example: https://relay.fishjam.io/abc123?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.... 20 token (str): JWT authorizing the MoQ relay connection, also embedded in `connection_url` Example: eyJhbGciOiJIUz 21 I1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1dCI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJle 22 HAiOjE3MTMzNjM2MDB9.abc123. 23 """ 24 25 connection_url: str 26 token: str 27 additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) 28 29 def to_dict(self) -> dict[str, Any]: 30 connection_url = self.connection_url 31 32 token = self.token 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update({ 37 "connection_url": connection_url, 38 "token": token, 39 }) 40 41 return field_dict 42 43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 connection_url = d.pop("connection_url") 47 48 token = d.pop("token") 49 50 moq_access = cls( 51 connection_url=connection_url, 52 token=token, 53 ) 54 55 moq_access.additional_properties = d 56 return moq_access 57 58 @property 59 def additional_keys(self) -> list[str]: 60 return list(self.additional_properties.keys()) 61 62 def __getitem__(self, key: str) -> Any: 63 return self.additional_properties[key] 64 65 def __setitem__(self, key: str, value: Any) -> None: 66 self.additional_properties[key] = value 67 68 def __delitem__(self, key: str) -> None: 69 del self.additional_properties[key] 70 71 def __contains__(self, key: str) -> bool: 72 return key in self.additional_properties
Connection details for a MoQ relay client
Attributes:
- 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_urlExample: eyJhbGciOiJIUz I1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1dCI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJle HAiOjE3MTMzNjM2MDB9.abc123.
25def __init__(self, connection_url, token): 26 self.connection_url = connection_url 27 self.token = token 28 self.additional_properties = __attr_factory_additional_properties()
Method generated by attrs for class MoqAccess.
29 def to_dict(self) -> dict[str, Any]: 30 connection_url = self.connection_url 31 32 token = self.token 33 34 field_dict: dict[str, Any] = {} 35 field_dict.update(self.additional_properties) 36 field_dict.update({ 37 "connection_url": connection_url, 38 "token": token, 39 }) 40 41 return field_dict
43 @classmethod 44 def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: 45 d = dict(src_dict) 46 connection_url = d.pop("connection_url") 47 48 token = d.pop("token") 49 50 moq_access = cls( 51 connection_url=connection_url, 52 token=token, 53 ) 54 55 moq_access.additional_properties = d 56 return moq_access
8class MissingFishjamIdError(ValueError): 9 def __init__(self) -> None: 10 super().__init__("Fishjam ID is required")
Inappropriate argument value (of correct type).
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args
80class InvalidFishjamCredentialsError(HTTPError): 81 def __init__(self, errors): 82 """@private""" 83 super().__init__(errors)
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args