From c5e1a08c54151962393bb91d733f3f4bcb234590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 20 Feb 2025 17:17:19 +0100 Subject: [PATCH 1/4] client: adds X-Client-Id header to pydase.Client --- src/pydase/client/client.py | 7 ++++++- tests/client/test_client.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pydase/client/client.py b/src/pydase/client/client.py index fdb4df9..2c963d8 100644 --- a/src/pydase/client/client.py +++ b/src/pydase/client/client.py @@ -84,6 +84,7 @@ class Client: url: str, block_until_connected: bool = True, sio_client_kwargs: dict[str, Any] = {}, + client_id: str = "pydase_client", ): # Parse the URL to separate base URL and path prefix parsed_url = urllib.parse.urlparse(url) @@ -98,6 +99,7 @@ class Client: self._url = url self._sio = socketio.AsyncClient(**sio_client_kwargs) self._loop = asyncio.new_event_loop() + self._client_id = client_id self.proxy = ProxyClass( sio_client=self._sio, loop=self._loop, reconnect=self.connect ) @@ -137,7 +139,10 @@ class Client: logger.debug("Connecting to server '%s' ...", self._url) await self._setup_events() await self._sio.connect( - self._base_url, + url=self._base_url, + headers={ + "X-Client-Id": self._client_id, + }, socketio_path=f"{self._path_prefix}/ws/socket.io", transports=["websocket"], retry=True, diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 40e7a80..970a93f 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -161,3 +161,15 @@ def test_context_manager(pydase_client: pydase.Client) -> None: assert client.proxy.my_property == 1337.01 assert not client.proxy.connected + + +def test_client_id( + pydase_client: pydase.Client, caplog: pytest.LogCaptureFixture +) -> None: + pydase.Client(url="ws://localhost:9999") + + assert "Client [id=pydase_client] connected" in caplog.text + caplog.clear() + + pydase.Client(url="ws://localhost:9999", client_id="my_service") + assert "Client [id=my_service] connected" in caplog.text From 60287fef95dfad5d4406aa49aeea588953d89a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 20 Feb 2025 17:27:55 +0100 Subject: [PATCH 2/4] client: client_id arg defaults to None --- src/pydase/client/client.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pydase/client/client.py b/src/pydase/client/client.py index 2c963d8..59d23d0 100644 --- a/src/pydase/client/client.py +++ b/src/pydase/client/client.py @@ -84,7 +84,7 @@ class Client: url: str, block_until_connected: bool = True, sio_client_kwargs: dict[str, Any] = {}, - client_id: str = "pydase_client", + client_id: str | None = None, ): # Parse the URL to separate base URL and path prefix parsed_url = urllib.parse.urlparse(url) @@ -138,11 +138,14 @@ class Client: async def _connect(self) -> None: logger.debug("Connecting to server '%s' ...", self._url) await self._setup_events() + + headers = {} + if self._client_id is not None: + headers["X-Client-Id"] = self._client_id + await self._sio.connect( url=self._base_url, - headers={ - "X-Client-Id": self._client_id, - }, + headers=headers, socketio_path=f"{self._path_prefix}/ws/socket.io", transports=["websocket"], retry=True, From 2d39c56e3d7db44e5a0a2fe1ac0d8c64c4ba71de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 20 Feb 2025 17:28:07 +0100 Subject: [PATCH 3/4] updates docs --- docs/user-guide/interaction/Python Client.md | 7 +++++-- src/pydase/client/client.py | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/interaction/Python Client.md b/docs/user-guide/interaction/Python Client.md index 2878ce4..34e575f 100644 --- a/docs/user-guide/interaction/Python Client.md +++ b/docs/user-guide/interaction/Python Client.md @@ -50,12 +50,14 @@ import pydase class MyService(pydase.DataService): proxy = pydase.Client( url="ws://:", - block_until_connected=False + block_until_connected=False, + client_id="my_pydase_client_id", ).proxy # For SSL-encrypted services, use the wss protocol # proxy = pydase.Client( # url="wss://your-domain.ch", - # block_until_connected=False + # block_until_connected=False, + # client_id="my_pydase_client_id", # ).proxy if __name__ == "__main__": @@ -67,6 +69,7 @@ if __name__ == "__main__": In this example: - The `MyService` class has a `proxy` attribute that connects to a `pydase` service at `:`. - By setting `block_until_connected=False`, the service can start without waiting for the connection to succeed, which is particularly useful in distributed systems where services may initialize in any order. +- By setting `client_id`, the server will provide more accurate logs of the connecting client. If set, this ID is sent as `X-Client-Id` header in the HTTP(s) request. ## Custom `socketio.AsyncClient` Connection Parameters diff --git a/src/pydase/client/client.py b/src/pydase/client/client.py index 59d23d0..c429331 100644 --- a/src/pydase/client/client.py +++ b/src/pydase/client/client.py @@ -56,6 +56,9 @@ class Client: [`AsyncClient`][socketio.AsyncClient]. This allows fine-tuning of the client's behaviour (e.g., reconnection attempts or reconnection delay). Default is an empty dictionary. + client_id: Client identification that will be shown in the server logs this + client is connecting to. This ID is passed as a `X-Client-Id` header in the + HTTP(s) request. Defaults to None. Example: The following example demonstrates a `Client` instance that connects to another From c76b0b0b6e982914184ba8454c81a311e2fbbe69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 20 Feb 2025 17:28:53 +0100 Subject: [PATCH 4/4] updates test --- tests/client/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 970a93f..cbc01de 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -168,7 +168,7 @@ def test_client_id( ) -> None: pydase.Client(url="ws://localhost:9999") - assert "Client [id=pydase_client] connected" in caplog.text + assert "Client [sid=" in caplog.text caplog.clear() pydase.Client(url="ws://localhost:9999", client_id="my_service")