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:
@@ -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]
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user