diff --git a/src/pysignalr/client.py b/src/pysignalr/client.py index 9b2967d..5f7a7b1 100644 --- a/src/pysignalr/client.py +++ b/src/pysignalr/client.py @@ -1,6 +1,7 @@ from __future__ import annotations import uuid +import ssl from collections import defaultdict from contextlib import asynccontextmanager from typing import TYPE_CHECKING @@ -102,11 +103,13 @@ def __init__( connection_timeout: int = DEFAULT_CONNECTION_TIMEOUT, max_size: int | None = DEFAULT_MAX_SIZE, access_token_factory: Callable[[], str] | None = None, + ssl: ssl.SSLContext | None = None, ) -> None: self._url = url self._protocol = protocol or JSONProtocol() self._headers = headers or {} self._access_token_factory = access_token_factory + self._ssl = ssl self._message_handlers: defaultdict[str, list[MessageCallback | None]] = defaultdict(list) self._stream_handlers: dict[ @@ -123,6 +126,7 @@ def __init__( connection_timeout=connection_timeout, max_size=max_size, access_token_factory=access_token_factory, + ssl=ssl, ) self._error_callback: CompletionMessageCallback | None = None diff --git a/src/pysignalr/transport/websocket.py b/src/pysignalr/transport/websocket.py index df08f1c..c2fa319 100644 --- a/src/pysignalr/transport/websocket.py +++ b/src/pysignalr/transport/websocket.py @@ -2,6 +2,7 @@ import asyncio import logging +import ssl from contextlib import suppress from http import HTTPStatus from typing import TYPE_CHECKING @@ -65,6 +66,7 @@ def __init__( connection_timeout: int = DEFAULT_CONNECTION_TIMEOUT, max_size: int | None = DEFAULT_MAX_SIZE, access_token_factory: Callable[[], str] | None = None, + ssl: ssl.SSLContext | None = None, ): """ Initializes the WebSocket transport with the provided parameters. @@ -90,6 +92,7 @@ def __init__( self._connection_timeout = connection_timeout self._max_size = max_size self._access_token_factory = access_token_factory + self._ssl = ssl self._state = ConnectionState.disconnected self._connected = asyncio.Event() @@ -155,14 +158,27 @@ async def _loop(self) -> None: except ServerConnectionError as e: raise NegotiationTimeout from e - connection_loop = connect( - self._url, - extra_headers=self._headers, - ping_interval=self._ping_interval, - open_timeout=self._connection_timeout, - max_size=self._max_size, - logger=_logger, - ) + # Since websockets interprets the presence of the ssl option as something different than providing None, + # the call needs to be made with or without ssl option to work properly + if self._ssl is None: + connection_loop = connect( + self._url, + extra_headers=self._headers, + ping_interval=self._ping_interval, + open_timeout=self._connection_timeout, + max_size=self._max_size, + logger=_logger, + ) + else: + connection_loop = connect( + self._url, + extra_headers=self._headers, + ping_interval=self._ping_interval, + open_timeout=self._connection_timeout, + max_size=self._max_size, + logger=_logger, + ssl=self._ssl, + ) async for conn in connection_loop: try: