mirror of
https://github.com/tiqi-group/pydase.git
synced 2026-02-03 09:18:40 +01:00
client: updates proxy.serialize logic
The proxy needs to properly handle serialization requests. If such a requests comes from the asyncio loop used by the socketio client, this would result in a deadlock. This happens, for example, when the observer is notified of a change triggered within a socketio event. To prevent this, I am checking the current loop against the socketio client loop. If it's the same, return the _service_representation value, which is set when pydase.Client connects to the server. I do the same when the client is not connected (to prevent BadNamespaceErrors). Every other invokation of serialize results in an API call to the server.
This commit is contained in:
@@ -65,19 +65,31 @@ class ProxyClass(ProxyClassMixin, pydase.components.DeviceConnection):
|
|||||||
self.reconnect = reconnect
|
self.reconnect = reconnect
|
||||||
|
|
||||||
def serialize(self) -> SerializedObject:
|
def serialize(self) -> SerializedObject:
|
||||||
if self._service_representation is None:
|
current_loop = asyncio.get_event_loop()
|
||||||
serialization_future = cast(
|
|
||||||
|
if not self.connected or current_loop == self._loop:
|
||||||
|
logger.debug(
|
||||||
|
"Client not connected, or called from within client event loop - using "
|
||||||
|
"fallback serialization"
|
||||||
|
)
|
||||||
|
if self._service_representation is None:
|
||||||
|
serialized_service = pydase.components.DeviceConnection().serialize()
|
||||||
|
else:
|
||||||
|
serialized_service = self._service_representation
|
||||||
|
|
||||||
|
else:
|
||||||
|
future = cast(
|
||||||
"asyncio.Future[SerializedDataService]",
|
"asyncio.Future[SerializedDataService]",
|
||||||
asyncio.run_coroutine_threadsafe(
|
asyncio.run_coroutine_threadsafe(
|
||||||
self._sio.call("service_serialization"), self._loop
|
self._sio.call("service_serialization"), self._loop
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
result = future.result()
|
||||||
# need to use object.__setattr__ to not trigger an observer notification
|
# need to use object.__setattr__ to not trigger an observer notification
|
||||||
object.__setattr__(
|
object.__setattr__(self, "_service_representation", result)
|
||||||
self, "_service_representation", serialization_future.result()
|
|
||||||
)
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
self._service_representation = serialization_future.result()
|
self._service_representation = result
|
||||||
|
serialized_service = result
|
||||||
|
|
||||||
device_connection_value = cast(
|
device_connection_value = cast(
|
||||||
"dict[str, SerializedObject]",
|
"dict[str, SerializedObject]",
|
||||||
@@ -93,7 +105,7 @@ class ProxyClass(ProxyClassMixin, pydase.components.DeviceConnection):
|
|||||||
"dict[str, SerializedObject]",
|
"dict[str, SerializedObject]",
|
||||||
# need to deepcopy to not overwrite the _service_representation dict
|
# need to deepcopy to not overwrite the _service_representation dict
|
||||||
# when adding a prefix with add_prefix_to_full_access_path
|
# when adding a prefix with add_prefix_to_full_access_path
|
||||||
deepcopy(self._service_representation["value"]),
|
deepcopy(serialized_service["value"]),
|
||||||
),
|
),
|
||||||
**device_connection_value,
|
**device_connection_value,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user