From be152c3acf813a26ee699b8499f585bcdbf0d5cf Mon Sep 17 00:00:00 2001 From: miruka Date: Sun, 7 Jul 2019 01:37:13 -0400 Subject: [PATCH] Fix getUser binding loops & coro race conditions --- TODO.md | 1 - src/python/app.py | 19 +++++++++---------- src/python/backend.py | 2 ++ src/python/matrix_client.py | 6 ++++++ src/qml/Models/Users.qml | 10 ++++------ src/qml/Python.qml | 14 +++++++------- src/qml/SidePane/AccountDelegate.qml | 5 ++--- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/TODO.md b/TODO.md index 8ab0c92c..eae32b81 100644 --- a/TODO.md +++ b/TODO.md @@ -25,7 +25,6 @@ OLD - Bug fixes - Past events loading (limit 100) freezes the GUI - need to move upsert func to a WorkerScript - - Past events loading: text binding loop on name request - `MessageDelegate.qml:63: TypeError: 'reloadPreviousItem' not a function` - UI diff --git a/src/python/app.py b/src/python/app.py index 6a34bbcd..9a636a32 100644 --- a/src/python/app.py +++ b/src/python/app.py @@ -37,32 +37,31 @@ class App: return asyncio.run_coroutine_threadsafe(coro, self.loop) - def _call_coro(self, coro: Coroutine) -> str: - uuid = str(uuid4()) - + def _call_coro(self, coro: Coroutine, uuid: str) -> None: self.run_in_loop(coro).add_done_callback( lambda future: CoroutineDone(uuid=uuid, result=future.result()) ) - return uuid def call_backend_coro(self, name: str, + uuid: str, args: Optional[List[str]] = None, - kwargs: Optional[Dict[str, Any]] = None) -> str: - return self._call_coro( - getattr(self.backend, name)(*args or [], **kwargs or {}) + kwargs: Optional[Dict[str, Any]] = None) -> None: + self._call_coro( + getattr(self.backend, name)(*args or [], **kwargs or {}), uuid ) def call_client_coro(self, account_id: str, name: str, + uuid: str, args: Optional[List[str]] = None, - kwargs: Optional[Dict[str, Any]] = None) -> str: + kwargs: Optional[Dict[str, Any]] = None) -> None: client = self.backend.clients[account_id] - return self._call_coro( - getattr(client, name)(*args or [], **kwargs or {}) + self._call_coro( + getattr(client, name)(*args or [], **kwargs or {}), uuid ) diff --git a/src/python/backend.py b/src/python/backend.py index a77dfbd3..193887e1 100644 --- a/src/python/backend.py +++ b/src/python/backend.py @@ -24,6 +24,8 @@ class Backend: self.past_tokens: Dict[str, str] = {} # {room_id: token} self.fully_loaded_rooms: Set[str] = set() # {room_id} + self.pending_profile_requests: Set[str] = set() + def __repr__(self) -> str: return f"{type(self).__name__}(clients={self.clients!r})" diff --git a/src/python/matrix_client.py b/src/python/matrix_client.py index 2c5d93ee..e6e2bb5b 100644 --- a/src/python/matrix_client.py +++ b/src/python/matrix_client.py @@ -110,6 +110,10 @@ class MatrixClient(nio.AsyncClient): async def request_user_update_event(self, user_id: str) -> None: + if user_id in self.backend.pending_profile_requests: + return + self.backend.pending_profile_requests.add(user_id) + print("Requesting user profile:", user_id) response = await self.get_profile(user_id) @@ -123,6 +127,8 @@ class MatrixClient(nio.AsyncClient): status_message = "", # TODO ) + self.backend.pending_profile_requests.discard(user_id) + @property def all_rooms(self) -> Dict[str, MatrixRoom]: diff --git a/src/qml/Models/Users.qml b/src/qml/Models/Users.qml index 4bb58a8f..ac520f4e 100644 --- a/src/qml/Models/Users.qml +++ b/src/qml/Models/Users.qml @@ -7,15 +7,13 @@ HListModel { var found = getWhere({"userId": user_id}, 1) if (found.length > 0) { return found[0] } - append({ + py.callCoro("request_user_update_event", [user_id]) + + return { "userId": user_id, "displayName": "", "avatarUrl": "", "statusMessage": "" - }) - - py.callCoro("request_user_update_event", [user_id]) - - return getWhere({"userId": user_id}, 1)[0] + } } } diff --git a/src/qml/Python.qml b/src/qml/Python.qml index 8cbf8175..c6174baa 100644 --- a/src/qml/Python.qml +++ b/src/qml/Python.qml @@ -17,17 +17,17 @@ Python { } function callCoro(name, args, kwargs, callback) { - call("APP.call_backend_coro", [name, args, kwargs], function(uuid){ - pendingCoroutines[uuid] = callback || function() {} - }) + var uuid = Math.random() + "." + name + + pendingCoroutines[uuid] = callback || function() {} + call("APP.call_backend_coro", [name, uuid, args, kwargs]) } function callClientCoro(account_id, name, args, kwargs, callback) { - var args = [account_id, name, args, kwargs] + var uuid = Math.random() + "." + name - call("APP.call_client_coro", args, function(uuid){ - pendingCoroutines[uuid] = callback || function() {} - }) + pendingCoroutines[uuid] = callback || function() {} + call("APP.call_client_coro", [account_id, name, uuid, args, kwargs]) } Component.onCompleted: { diff --git a/src/qml/SidePane/AccountDelegate.qml b/src/qml/SidePane/AccountDelegate.qml index 3786afe2..4638dc1b 100644 --- a/src/qml/SidePane/AccountDelegate.qml +++ b/src/qml/SidePane/AccountDelegate.qml @@ -6,9 +6,7 @@ Column { id: accountDelegate width: parent.width - // Avoid binding loop by using Component.onCompleted - property var userInfo: null - Component.onCompleted: userInfo = users.getUser(model.userId) + property var userInfo: users.getUser(model.userId) property bool expanded: true @@ -19,6 +17,7 @@ Column { HUserAvatar { id: avatar + // Need to do this because conflict with the model property Component.onCompleted: userId = model.userId }