Broadcast UnknownToken API client errors, handle them on the FFI client side and send a did_receive_auth_error delegate call

This commit is contained in:
Stefan Ceriu
2023-03-03 13:13:26 +02:00
committed by GitHub
parent 0da29057f8
commit e550c16c14
4 changed files with 65 additions and 14 deletions
+27 -11
View File
@@ -19,7 +19,7 @@ use matrix_sdk::{
},
Client as MatrixClient, Error, LoopCtrl,
};
use tokio::sync::broadcast;
use tokio::sync::broadcast::{self, error::RecvError};
use tracing::{debug, warn};
use super::{
@@ -73,14 +73,31 @@ impl Client {
let (sliding_sync_reset_broadcast_tx, _) = broadcast::channel(1);
Client {
let client = Client {
client,
state: Arc::new(RwLock::new(state)),
delegate: Arc::new(RwLock::new(None)),
session_verification_controller,
sliding_sync_proxy: Arc::new(RwLock::new(None)),
sliding_sync_reset_broadcast_tx,
}
};
let mut unknown_token_error_receiver = client.subscribe_to_unknown_token_errors();
let client_clone = client.clone();
RUNTIME.spawn(async move {
loop {
match unknown_token_error_receiver.recv().await {
Ok(unknown_token) => client_clone.process_unknown_token_error(unknown_token),
Err(receive_error) => {
if let RecvError::Closed = receive_error {
break;
}
}
}
}
});
client
}
/// Login using a username and password.
@@ -347,14 +364,6 @@ impl Client {
pub(crate) fn process_sync_error(&self, sync_error: Error) -> LoopCtrl {
let client_api_error_kind = sync_error.client_api_error_kind();
match client_api_error_kind {
Some(ErrorKind::UnknownToken { soft_logout }) => {
self.state.write().unwrap().is_soft_logout = *soft_logout;
if let Some(delegate) = &*self.delegate.read().unwrap() {
delegate.did_update_restore_token();
delegate.did_receive_auth_error(*soft_logout);
}
LoopCtrl::Break
}
Some(ErrorKind::UnknownPos) => {
let _ = self.sliding_sync_reset_broadcast_tx.send(());
LoopCtrl::Continue
@@ -365,6 +374,13 @@ impl Client {
}
}
}
fn process_unknown_token_error(&self, unknown_token: matrix_sdk::UnknownToken) {
if let Some(delegate) = &*self.delegate.read().unwrap() {
delegate.did_update_restore_token();
delegate.did_receive_auth_error(unknown_token.soft_logout);
}
}
}
#[uniffi::export]
+4
View File
@@ -27,6 +27,7 @@ use ruma::{
OwnedServerName, ServerName,
};
use thiserror::Error;
use tokio::sync::broadcast;
#[cfg(not(target_arch = "wasm32"))]
use tokio::sync::OnceCell;
use tracing::{
@@ -419,6 +420,8 @@ impl ClientBuilder {
#[cfg(feature = "experimental-sliding-sync")]
let sliding_sync_proxy = sliding_sync_proxy.map(RwLock::new);
let (unknown_token_error_sender, _) = broadcast::channel(1);
let inner = Arc::new(ClientInner {
homeserver,
authentication_issuer,
@@ -441,6 +444,7 @@ impl ClientBuilder {
sync_beat: event_listener::Event::new(),
handle_refresh_tokens: self.handle_refresh_tokens,
refresh_token_lock: Mutex::new(Ok(())),
unknown_token_error_sender,
});
debug!("Done building the Client");
+33 -2
View File
@@ -68,6 +68,7 @@ use ruma::{
ServerName, UInt, UserId,
};
use serde::de::DeserializeOwned;
use tokio::sync::broadcast;
#[cfg(not(target_arch = "wasm32"))]
use tokio::sync::OnceCell;
#[cfg(feature = "e2e-encryption")]
@@ -125,6 +126,13 @@ pub enum LoopCtrl {
Break,
}
/// Wrapper struct for ErrorKind::UnknownToken
#[derive(Debug, Clone)]
pub struct UnknownToken {
/// Whether or not the session was soft logged out
pub soft_logout: bool,
}
/// An async/await enabled Matrix client.
///
/// All of the state is held in an `Arc` so the `Client` can be cloned freely.
@@ -181,6 +189,9 @@ pub(crate) struct ClientInner {
/// wait for the sync to get the data to fetch a room object from the state
/// store.
pub(crate) sync_beat: event_listener::Event,
/// Client API UnknownToken error publisher. Allows the subscriber logout
/// the user when any request fails because of an invalid access token
pub(crate) unknown_token_error_sender: broadcast::Sender<UnknownToken>,
}
#[cfg(not(tarpaulin_include))]
@@ -1843,7 +1854,8 @@ impl Client {
None => self.homeserver().await.to_string(),
};
self.inner
let response = self
.inner
.http_client
.send(
request,
@@ -1853,7 +1865,20 @@ impl Client {
self.user_id(),
self.server_versions().await?,
)
.await
.await;
if let Err(http_error) = &response {
if let Some(ErrorKind::UnknownToken { soft_logout }) =
http_error.client_api_error_kind()
{
_ = self
.inner
.unknown_token_error_sender
.send(UnknownToken { soft_logout: *soft_logout });
}
}
response
}
async fn request_server_versions(&self) -> HttpResult<Box<[MatrixVersion]>> {
@@ -2441,6 +2466,12 @@ impl Client {
let request = logout::v3::Request::new();
self.send(request, None).await
}
/// Subscribes a new receiver to client UnknownToken errors
pub fn subscribe_to_unknown_token_errors(&self) -> broadcast::Receiver<UnknownToken> {
let broadcast = &self.inner.unknown_token_error_sender;
broadcast.subscribe()
}
}
// The http mocking library is not supported for wasm32
+1 -1
View File
@@ -49,7 +49,7 @@ mod events;
pub use account::Account;
#[cfg(feature = "sso-login")]
pub use client::SsoLoginBuilder;
pub use client::{Client, ClientBuildError, ClientBuilder, LoginBuilder, LoopCtrl};
pub use client::{Client, ClientBuildError, ClientBuilder, LoginBuilder, LoopCtrl, UnknownToken};
#[cfg(feature = "image-proc")]
pub use error::ImageError;
pub use error::{Error, HttpError, HttpResult, RefreshTokenError, Result, RumaApiError};