Skip to content

Commit a2f3f61

Browse files
committed
fix(ffi): add methods to make QR login handlers exit cooperatively
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
1 parent 7b2b439 commit a2f3f61

2 files changed

Lines changed: 74 additions & 16 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add methods to make QR login handlers exit cooperatively.

bindings/matrix-sdk-ffi/src/qr_code.rs

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use matrix_sdk::authentication::oauth::{
2323
};
2424
use matrix_sdk_base::crypto::types::qr_login::{self, QrCodeIntent};
2525
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm, stream::StreamExt};
26+
use tokio::sync::Notify;
2627

2728
use crate::{
2829
authentication::OAuthConfiguration, runtime::get_runtime_handle, task_handle::TaskHandle,
@@ -33,11 +34,14 @@ use crate::{
3334
pub struct LoginWithQrCodeHandler {
3435
oauth: OAuth,
3536
oauth_configuration: OAuthConfiguration,
37+
/// Request a the handler to abort cooperatively. This will make the handler
38+
/// tear down its running task and then emit the `Cancelled` update.
39+
cancel: Notify,
3640
}
3741

3842
impl LoginWithQrCodeHandler {
3943
pub(crate) fn new(oauth: OAuth, oauth_configuration: OAuthConfiguration) -> Self {
40-
Self { oauth, oauth_configuration }
44+
Self { oauth, oauth_configuration, cancel: Notify::new() }
4145
}
4246
}
4347

@@ -82,15 +86,25 @@ impl LoginWithQrCodeHandler {
8286

8387
// We create this task, which will get cancelled once it's dropped, just in case
8488
// the progress stream doesn't end.
85-
let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
89+
let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
8690
while let Some(state) = progress.next().await {
8791
progress_listener.on_update(state.into());
8892
}
8993
}));
9094

91-
login.await?;
92-
93-
Ok(())
95+
tokio::select! {
96+
biased;
97+
result = login => {
98+
result?;
99+
Ok(())
100+
}
101+
_ = self.cancel.notified() => {
102+
// Stop forwarding progress to the foreign callback before tearing
103+
// down the handler.
104+
drop(progress_task);
105+
Err(HumanQrLoginError::Cancelled)
106+
}
107+
}
94108
}
95109

96110
/// This method allows you to log in by generating a QR code.
@@ -126,27 +140,44 @@ impl LoginWithQrCodeHandler {
126140

127141
// We create this task, which will get cancelled once it's dropped, just in case
128142
// the progress stream doesn't end.
129-
let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
143+
let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
130144
while let Some(state) = progress.next().await {
131145
progress_listener.on_update(state.into());
132146
}
133147
}));
134148

135-
login.await?;
149+
tokio::select! {
150+
biased;
151+
result = login => {
152+
result?;
153+
Ok(())
154+
}
155+
_ = self.cancel.notified() => {
156+
// Stop forwarding progress to the foreign callback before tearing
157+
// down the handler.
158+
drop(progress_task);
159+
Err(HumanQrLoginError::Cancelled)
160+
}
161+
}
162+
}
136163

137-
Ok(())
164+
/// Request a the handler to abort cooperatively. This will make the handler
165+
/// tear down its running task and then return the `Cancelled` error.
166+
pub fn abort(&self) {
167+
self.cancel.notify_waiters();
138168
}
139169
}
140170

141171
/// Handler for granting login in with a QR code.
142172
#[derive(uniffi::Object)]
143173
pub struct GrantLoginWithQrCodeHandler {
144174
oauth: OAuth,
175+
cancel: Notify,
145176
}
146177

147178
impl GrantLoginWithQrCodeHandler {
148179
pub(crate) fn new(oauth: OAuth) -> Self {
149-
Self { oauth }
180+
Self { oauth, cancel: Notify::new() }
150181
}
151182
}
152183

@@ -182,15 +213,25 @@ impl GrantLoginWithQrCodeHandler {
182213

183214
// We create this task, which will get cancelled once it's dropped, just in case
184215
// the progress stream doesn't end.
185-
let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
216+
let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
186217
while let Some(state) = progress.next().await {
187218
progress_listener.on_update(state.into());
188219
}
189220
}));
190221

191-
grant.await?;
192-
193-
Ok(())
222+
tokio::select! {
223+
biased;
224+
result = grant => {
225+
result?;
226+
Ok(())
227+
}
228+
_ = self.cancel.notified() => {
229+
// Stop forwarding progress to the foreign callback before tearing
230+
// down the handler.
231+
drop(progress_task);
232+
Err(HumanQrGrantLoginError::Cancelled)
233+
}
234+
}
194235
}
195236

196237
/// This method allows you to grant login by generating a QR code.
@@ -220,15 +261,31 @@ impl GrantLoginWithQrCodeHandler {
220261

221262
// We create this task, which will get cancelled once it's dropped, just in case
222263
// the progress stream doesn't end.
223-
let _progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
264+
let progress_task = TaskHandle::new(get_runtime_handle().spawn(async move {
224265
while let Some(state) = progress.next().await {
225266
progress_listener.on_update(state.into());
226267
}
227268
}));
228269

229-
grant.await?;
270+
tokio::select! {
271+
biased;
272+
result = grant => {
273+
result?;
274+
Ok(())
275+
}
276+
_ = self.cancel.notified() => {
277+
// Stop forwarding progress to the foreign callback before tearing
278+
// down the handler.
279+
drop(progress_task);
280+
Err(HumanQrGrantLoginError::Cancelled)
281+
}
282+
}
283+
}
230284

231-
Ok(())
285+
/// Request a the handler to abort cooperatively. This will make the handler
286+
/// tear down its running task and then return the `Cancelled` error.
287+
pub fn abort(&self) {
288+
self.cancel.notify_waiters();
232289
}
233290
}
234291

0 commit comments

Comments
 (0)