From a2f3f6180ef4a277c7808f2d35ea1fa6602fb4d8 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Fri, 19 Jun 2026 17:53:53 +0200 Subject: [PATCH 1/4] fix(ffi): add methods to make QR login handlers exit cooperatively Signed-off-by: Johannes Marbach --- .../matrix-sdk-ffi/changelog.d/6677.fixed.md | 1 + bindings/matrix-sdk-ffi/src/qr_code.rs | 89 +++++++++++++++---- 2 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 bindings/matrix-sdk-ffi/changelog.d/6677.fixed.md diff --git a/bindings/matrix-sdk-ffi/changelog.d/6677.fixed.md b/bindings/matrix-sdk-ffi/changelog.d/6677.fixed.md new file mode 100644 index 00000000000..3686e965983 --- /dev/null +++ b/bindings/matrix-sdk-ffi/changelog.d/6677.fixed.md @@ -0,0 +1 @@ +Add methods to make QR login handlers exit cooperatively. diff --git a/bindings/matrix-sdk-ffi/src/qr_code.rs b/bindings/matrix-sdk-ffi/src/qr_code.rs index 96ffc4cef10..c8485ffbe2d 100644 --- a/bindings/matrix-sdk-ffi/src/qr_code.rs +++ b/bindings/matrix-sdk-ffi/src/qr_code.rs @@ -23,6 +23,7 @@ use matrix_sdk::authentication::oauth::{ }; use matrix_sdk_base::crypto::types::qr_login::{self, QrCodeIntent}; use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm, stream::StreamExt}; +use tokio::sync::Notify; use crate::{ authentication::OAuthConfiguration, runtime::get_runtime_handle, task_handle::TaskHandle, @@ -33,11 +34,14 @@ use crate::{ pub struct LoginWithQrCodeHandler { oauth: OAuth, oauth_configuration: OAuthConfiguration, + /// Request a the handler to abort cooperatively. This will make the handler + /// tear down its running task and then emit the `Cancelled` update. + cancel: Notify, } impl LoginWithQrCodeHandler { pub(crate) fn new(oauth: OAuth, oauth_configuration: OAuthConfiguration) -> Self { - Self { oauth, oauth_configuration } + Self { oauth, oauth_configuration, cancel: Notify::new() } } } @@ -82,15 +86,25 @@ impl LoginWithQrCodeHandler { // We create this task, which will get cancelled once it's dropped, just in case // the progress stream doesn't end. - let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { + let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { while let Some(state) = progress.next().await { progress_listener.on_update(state.into()); } })); - login.await?; - - Ok(()) + tokio::select! { + biased; + result = login => { + result?; + Ok(()) + } + _ = self.cancel.notified() => { + // Stop forwarding progress to the foreign callback before tearing + // down the handler. + drop(progress_task); + Err(HumanQrLoginError::Cancelled) + } + } } /// This method allows you to log in by generating a QR code. @@ -126,15 +140,31 @@ impl LoginWithQrCodeHandler { // We create this task, which will get cancelled once it's dropped, just in case // the progress stream doesn't end. - let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { + let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { while let Some(state) = progress.next().await { progress_listener.on_update(state.into()); } })); - login.await?; + tokio::select! { + biased; + result = login => { + result?; + Ok(()) + } + _ = self.cancel.notified() => { + // Stop forwarding progress to the foreign callback before tearing + // down the handler. + drop(progress_task); + Err(HumanQrLoginError::Cancelled) + } + } + } - Ok(()) + /// Request a the handler to abort cooperatively. This will make the handler + /// tear down its running task and then return the `Cancelled` error. + pub fn abort(&self) { + self.cancel.notify_waiters(); } } @@ -142,11 +172,12 @@ impl LoginWithQrCodeHandler { #[derive(uniffi::Object)] pub struct GrantLoginWithQrCodeHandler { oauth: OAuth, + cancel: Notify, } impl GrantLoginWithQrCodeHandler { pub(crate) fn new(oauth: OAuth) -> Self { - Self { oauth } + Self { oauth, cancel: Notify::new() } } } @@ -182,15 +213,25 @@ impl GrantLoginWithQrCodeHandler { // We create this task, which will get cancelled once it's dropped, just in case // the progress stream doesn't end. - let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { + let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { while let Some(state) = progress.next().await { progress_listener.on_update(state.into()); } })); - grant.await?; - - Ok(()) + tokio::select! { + biased; + result = grant => { + result?; + Ok(()) + } + _ = self.cancel.notified() => { + // Stop forwarding progress to the foreign callback before tearing + // down the handler. + drop(progress_task); + Err(HumanQrGrantLoginError::Cancelled) + } + } } /// This method allows you to grant login by generating a QR code. @@ -220,15 +261,31 @@ impl GrantLoginWithQrCodeHandler { // We create this task, which will get cancelled once it's dropped, just in case // the progress stream doesn't end. - let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { + let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move { while let Some(state) = progress.next().await { progress_listener.on_update(state.into()); } })); - grant.await?; + tokio::select! { + biased; + result = grant => { + result?; + Ok(()) + } + _ = self.cancel.notified() => { + // Stop forwarding progress to the foreign callback before tearing + // down the handler. + drop(progress_task); + Err(HumanQrGrantLoginError::Cancelled) + } + } + } - Ok(()) + /// Request a the handler to abort cooperatively. This will make the handler + /// tear down its running task and then return the `Cancelled` error. + pub fn abort(&self) { + self.cancel.notify_waiters(); } } From f8a853955e9dc2b6f15a765abe69620dd238c8cc Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 23 Jun 2026 20:34:20 +0200 Subject: [PATCH 2/4] fixup! fix(ffi): add methods to make QR login handlers exit cooperatively Fix doc comments Signed-off-by: Johannes Marbach --- bindings/matrix-sdk-ffi/src/qr_code.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/qr_code.rs b/bindings/matrix-sdk-ffi/src/qr_code.rs index c8485ffbe2d..c76fab873e0 100644 --- a/bindings/matrix-sdk-ffi/src/qr_code.rs +++ b/bindings/matrix-sdk-ffi/src/qr_code.rs @@ -34,8 +34,6 @@ use crate::{ pub struct LoginWithQrCodeHandler { oauth: OAuth, oauth_configuration: OAuthConfiguration, - /// Request a the handler to abort cooperatively. This will make the handler - /// tear down its running task and then emit the `Cancelled` update. cancel: Notify, } @@ -161,7 +159,7 @@ impl LoginWithQrCodeHandler { } } - /// Request a the handler to abort cooperatively. This will make the handler + /// Request the handler to abort cooperatively. This will make the handler /// tear down its running task and then return the `Cancelled` error. pub fn abort(&self) { self.cancel.notify_waiters(); @@ -282,7 +280,7 @@ impl GrantLoginWithQrCodeHandler { } } - /// Request a the handler to abort cooperatively. This will make the handler + /// Request the handler to abort cooperatively. This will make the handler /// tear down its running task and then return the `Cancelled` error. pub fn abort(&self) { self.cancel.notify_waiters(); From e9a461d78803379b745f5b0f6320587d9d989baa Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Tue, 23 Jun 2026 20:43:35 +0200 Subject: [PATCH 3/4] fixup! fix(ffi): add methods to make QR login handlers exit cooperatively Remove biasing Signed-off-by: Johannes Marbach --- bindings/matrix-sdk-ffi/src/qr_code.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/qr_code.rs b/bindings/matrix-sdk-ffi/src/qr_code.rs index c76fab873e0..3e855b62e58 100644 --- a/bindings/matrix-sdk-ffi/src/qr_code.rs +++ b/bindings/matrix-sdk-ffi/src/qr_code.rs @@ -91,7 +91,6 @@ impl LoginWithQrCodeHandler { })); tokio::select! { - biased; result = login => { result?; Ok(()) @@ -145,7 +144,6 @@ impl LoginWithQrCodeHandler { })); tokio::select! { - biased; result = login => { result?; Ok(()) @@ -218,7 +216,6 @@ impl GrantLoginWithQrCodeHandler { })); tokio::select! { - biased; result = grant => { result?; Ok(()) @@ -266,7 +263,6 @@ impl GrantLoginWithQrCodeHandler { })); tokio::select! { - biased; result = grant => { result?; Ok(()) From 551a2b6fdb31913e5eecffc980f05b390f5e7351 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Thu, 25 Jun 2026 20:54:38 +0200 Subject: [PATCH 4/4] fixup! fix(ffi): add methods to make QR login handlers exit cooperatively Revert back to biased and document why its needed Signed-off-by: Johannes Marbach --- bindings/matrix-sdk-ffi/src/qr_code.rs | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/qr_code.rs b/bindings/matrix-sdk-ffi/src/qr_code.rs index 3e855b62e58..e2c7df2c63e 100644 --- a/bindings/matrix-sdk-ffi/src/qr_code.rs +++ b/bindings/matrix-sdk-ffi/src/qr_code.rs @@ -91,16 +91,18 @@ impl LoginWithQrCodeHandler { })); tokio::select! { - result = login => { - result?; - Ok(()) - } + // Give priority to cancellation if both updates occur at the same time. + biased; _ = self.cancel.notified() => { // Stop forwarding progress to the foreign callback before tearing // down the handler. drop(progress_task); Err(HumanQrLoginError::Cancelled) } + result = login => { + result?; + Ok(()) + } } } @@ -144,16 +146,18 @@ impl LoginWithQrCodeHandler { })); tokio::select! { - result = login => { - result?; - Ok(()) - } + // Give priority to cancellation if both updates occur at the same time. + biased; _ = self.cancel.notified() => { // Stop forwarding progress to the foreign callback before tearing // down the handler. drop(progress_task); Err(HumanQrLoginError::Cancelled) } + result = login => { + result?; + Ok(()) + } } } @@ -216,16 +220,18 @@ impl GrantLoginWithQrCodeHandler { })); tokio::select! { - result = grant => { - result?; - Ok(()) - } + // Give priority to cancellation if both updates occur at the same time. + biased; _ = self.cancel.notified() => { // Stop forwarding progress to the foreign callback before tearing // down the handler. drop(progress_task); Err(HumanQrGrantLoginError::Cancelled) } + result = grant => { + result?; + Ok(()) + } } } @@ -263,16 +269,18 @@ impl GrantLoginWithQrCodeHandler { })); tokio::select! { - result = grant => { - result?; - Ok(()) - } + // Give priority to cancellation if both updates occur at the same time. + biased; _ = self.cancel.notified() => { // Stop forwarding progress to the foreign callback before tearing // down the handler. drop(progress_task); Err(HumanQrGrantLoginError::Cancelled) } + result = grant => { + result?; + Ok(()) + } } }