Merge pull request #208 from tiqi-group/feat/add_client_id_header

client: adds X-Client-Id header to pydase.Client
This commit is contained in:
Mose Müller 2025-02-20 17:30:31 +01:00 committed by GitHub
commit 247113f1db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 3 deletions

View File

@ -50,12 +50,14 @@ import pydase
class MyService(pydase.DataService):
proxy = pydase.Client(
url="ws://<ip_addr>:<service_port>",
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 `<ip_addr>:<service_port>`.
- 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

View File

@ -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
@ -84,6 +87,7 @@ class Client:
url: str,
block_until_connected: bool = True,
sio_client_kwargs: dict[str, Any] = {},
client_id: str | None = None,
):
# Parse the URL to separate base URL and path prefix
parsed_url = urllib.parse.urlparse(url)
@ -98,6 +102,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
)
@ -136,8 +141,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(
self._base_url,
url=self._base_url,
headers=headers,
socketio_path=f"{self._path_prefix}/ws/socket.io",
transports=["websocket"],
retry=True,

View File

@ -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 [sid=" in caplog.text
caplog.clear()
pydase.Client(url="ws://localhost:9999", client_id="my_service")
assert "Client [id=my_service] connected" in caplog.text