Implement cancelling python coros from QML

This was needed to implement the cancel button featue on the login
screen
This commit is contained in:
miruka 2019-12-07 18:33:33 -04:00
parent 4a93a24f74
commit 6f589dbda5
3 changed files with 66 additions and 15 deletions

View File

@ -54,7 +54,7 @@ class App:
return asyncio.run_coroutine_threadsafe(coro, self.loop)
def _call_coro(self, coro: Coroutine, uuid: str) -> None:
def _call_coro(self, coro: Coroutine, uuid: str) -> Future:
def on_done(future: Future) -> None:
result = exception = trace = None
@ -66,21 +66,23 @@ class App:
CoroutineDone(uuid, result, exception, trace)
self.run_in_loop(coro).add_done_callback(on_done)
future = self.run_in_loop(coro)
future.add_done_callback(on_done)
return future
def call_backend_coro(self, name: str, uuid: str, args: Sequence[str] = (),
) -> None:
self._call_coro(attrgetter(name)(self.backend)(*args), uuid)
) -> Future:
return self._call_coro(attrgetter(name)(self.backend)(*args), uuid)
def call_client_coro(self,
account_id: str,
name: str,
uuid: str,
args: Sequence[str] = ()) -> None:
args: Sequence[str] = ()) -> Future:
client = self.backend.clients[account_id]
self._call_coro(attrgetter(name)(client)(*args), uuid)
return self._call_coro(attrgetter(name)(client)(*args), uuid)
def pdb(self, additional_data: Sequence = ()) -> None:

View File

@ -31,7 +31,7 @@ HBox {
signInTimeout.restart()
py.callCoro("login_client", args, userId => {
loginFuture = py.callCoro("login_client", args, userId => {
signInTimeout.stop()
errorMessage.text = ""
button.loading = false
@ -48,9 +48,14 @@ HBox {
)
}, type => {
if (type === "CancelledError") return
signInTimeout.stop()
if (type === "CancelledError") {
loginFuture = null
button.loading = false
return
}
let txt = qsTr("Invalid request or login type")
if (type === "MatrixForbidden")
@ -64,11 +69,14 @@ HBox {
})
},
cancel: button => {}
cancel: button => { if (loginFuture) loginFuture.cancel() }
})
property var loginFuture: null
property string signInWith: "username"
readonly property bool canSignIn:
serverField.text && idField.text && passwordField.text &&
! serverField.error

View File

@ -1,15 +1,40 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import io.thp.pyotherside 1.5
import "event_handlers.js" as EventHandlers
Python {
id: py
property bool ready: false
property bool startupAnyAccountsSaved: false
property var pendingCoroutines: ({})
function newQmlFuture() {
return {
_pyFuture: null,
get pyFuture() { return this._pyFuture },
set pyFuture(value) {
this._pyFuture = value
if (this.cancelPending) this.cancel()
},
cancelPending: false,
cancel: function() {
if (! this.pyFuture) {
this.cancelPending = true
return
}
py.call(py.getattr(this.pyFuture, "cancel"))
},
}
}
function setattr(obj, attr, value, callback=null) {
py.call(py.getattr(obj, "__setattr__"), [attr, value], callback)
}
@ -22,27 +47,43 @@ Python {
let uuid = name + "." + CppUtils.uuid()
pendingCoroutines[uuid] = {onSuccess, onError}
call("APP.call_backend_coro", [name, uuid, args])
let qmlFuture = py.newQmlFuture()
call("APP.call_backend_coro", [name, uuid, args], pyFuture => {
qmlFuture.pyFuture = pyFuture
})
return qmlFuture
}
function callClientCoro(
accountId, name, args=[], onSuccess=null, onError=null
) {
let qmlFuture = py.newQmlFuture()
callCoro("wait_until_client_exists", [accountId], () => {
let uuid = accountId + "." + name + "." + CppUtils.uuid()
pendingCoroutines[uuid] = {onSuccess, onError}
call("APP.call_client_coro", [accountId, name, uuid, args])
let call_args = [accountId, name, uuid, args]
call("APP.call_client_coro", call_args, pyFuture => {
qmlFuture.pyFuture = pyFuture
})
})
return qmlFuture
}
function saveConfig(backend_attribute, data, callback=null) {
if (! py.ready) { return } // config not loaded yet
callCoro(backend_attribute + ".write", [data], callback)
return callCoro(backend_attribute + ".write", [data], callback)
}
function loadSettings(callback=null) {
callCoro("load_settings", [], ([settings, uiState, theme]) => {
return callCoro("load_settings", [], ([settings, uiState, theme]) => {
window.settings = settings
window.uiState = uiState
window.theme = Qt.createQmlObject(theme, window, "theme")