From 3ec9d5845ec670d48ed37046bb799fd75bda0c84 Mon Sep 17 00:00:00 2001 From: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> Date: Fri, 3 Jul 2026 00:36:02 +0530 Subject: [PATCH 1/5] feat: add discovery_cache_timeout to ClientBuilder and rediscover() to Client Signed-off-by: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> --- crates/matrix-sdk/src/client/builder/mod.rs | 15 ++++++- crates/matrix-sdk/src/client/caches.rs | 4 +- crates/matrix-sdk/src/client/mod.rs | 49 ++++++++++++++++++++- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/crates/matrix-sdk/src/client/builder/mod.rs b/crates/matrix-sdk/src/client/builder/mod.rs index 84d1fcd9c5a..43436c690e5 100644 --- a/crates/matrix-sdk/src/client/builder/mod.rs +++ b/crates/matrix-sdk/src/client/builder/mod.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use std::path::Path; #[cfg(any(feature = "experimental-search", feature = "sqlite"))] use std::path::PathBuf; -use std::{collections::BTreeSet, fmt, sync::Arc}; +use std::{collections::BTreeSet, fmt, sync::Arc, time::Duration}; #[cfg(feature = "sqlite")] use futures_util::try_join; @@ -133,6 +133,7 @@ pub struct ClientBuilder { search_index_store_kind: SearchIndexStoreKind, dm_room_definition: DmRoomDefinition, media_fetcher: Arc, + discovery_cache_timeout: Duration, } impl ClientBuilder { @@ -171,6 +172,7 @@ impl ClientBuilder { search_index_store_kind: SearchIndexStoreKind::InMemory, dm_room_definition: DmRoomDefinition::MatrixSpec, media_fetcher: Arc::new(DefaultMediaFetcher), + discovery_cache_timeout: Duration::from_secs(60 * 60 * 24), } } @@ -675,6 +677,7 @@ impl ClientBuilder { search_index, thread_subscriptions_catchup, self.media_fetcher.clone(), + self.discovery_cache_timeout, ) .await; @@ -682,6 +685,16 @@ impl ClientBuilder { Ok(Client { inner }) } + + /// Set the duration after which cached discovery data (e.g. supported + /// versions, well-known info) is considered stale and needs to be + /// refreshed. + /// + /// By default, this is 24 hours + pub fn discovery_cache_timeout(mut self, stale_timeout: Duration) -> Self { + self.discovery_cache_timeout = stale_timeout; + self + } } /// Creates a server name from a user supplied string. The string is first diff --git a/crates/matrix-sdk/src/client/caches.rs b/crates/matrix-sdk/src/client/caches.rs index 068e9deb8f6..5d5b2334a95 100644 --- a/crates/matrix-sdk/src/client/caches.rs +++ b/crates/matrix-sdk/src/client/caches.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use matrix_sdk_base::store::WellKnownResponse; use matrix_sdk_common::{locks::Mutex, ttl::TtlValue}; @@ -43,6 +43,8 @@ pub(crate) struct ClientCaches { pub(crate) server_metadata: Cache, /// Homeserver capabilities. pub(crate) homeserver_capabilities: Cache>, + /// The duration after which cached discovery data is considered stale. + pub(crate) discovery_cache_timeout: Duration, } /// A cached value that can either be set or not set, used to avoid confusion diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index bb104eeb499..b60d6b2975e 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -89,8 +89,9 @@ use crate::{ Account, AuthApi, AuthSession, Error, HttpError, Media, Pusher, RefreshTokenError, Result, Room, SessionTokens, TransmissionProgress, authentication::{ - AuthCtx, AuthData, ReloadSessionCallback, SaveSessionCallback, matrix::MatrixAuth, - oauth::OAuth, + AuthCtx, AuthData, ReloadSessionCallback, SaveSessionCallback, + matrix::MatrixAuth, + oauth::{OAuth, OAuthError, error::OAuthDiscoveryError}, }, client::{ homeserver_capabilities::HomeserverCapabilities, @@ -439,12 +440,14 @@ impl ClientInner { #[cfg(feature = "experimental-search")] search_index_handler: SearchIndex, thread_subscription_catchup: OnceCell>, media_fetcher: Arc, + discovery_cache_timeout: Duration, ) -> Arc { let caches = ClientCaches { supported_versions: Cache::with_value(supported_versions), well_known: Cache::with_value(well_known), server_metadata: Cache::new(), homeserver_capabilities: Cache::new(), + discovery_cache_timeout, }; let client = Self { @@ -3261,6 +3264,7 @@ impl Client { self.inner.search_index.clone(), self.inner.thread_subscription_catchup.clone(), self.inner.media_fetcher.clone(), + self.inner.caches.discovery_cache_timeout, ) .await, }; @@ -3562,6 +3566,26 @@ impl Client { pub fn dm_room_definition(&self) -> &DmRoomDefinition { &self.inner.base_client.dm_room_definition } + + /// Force a refresh of all the cached discovery data (supported versions, + /// well-known info, homeserver capabilities, and OAuth 2.0 server metadata), + /// ignoring whether the existing cache is still fresh. + /// + /// If refreshing the well-known info fails, or if the server doesn't support OAuth 2.0 server metadata, it is silently ignored. + /// All other refresh + /// failures are returned as an error, and any remaining refreshes that + /// haven't run yet are skipped. + pub async fn rediscover(&self) -> Result<(), Error> { + self.refresh_supported_versions_cache(false).await?; + self.refresh_well_known_cache().await; + self.homeserver_capabilities().refresh().await?; + match self.oauth().server_metadata().await { + Ok(_) => {} + Err(OAuthDiscoveryError::NotSupported) => {} + Err(e) => return Err(Error::from(OAuthError::Discovery(e))), + } + Ok(()) + } } /// Contains the disk size of the different stores, if known. It won't be @@ -3748,6 +3772,27 @@ pub(crate) mod tests { client.server_versions().await.unwrap(); } + #[async_test] + async fn test_rediscover() { + let server = MatrixMockServer::new().await; + + // Mock the two required endpoints + server.mock_versions().ok().mock_once().named("versions").mount().await; + server + .mock_get_homeserver_capabilities() + .ok() + .mock_once() + .named("capabilities") + .mount() + .await; + + // Build the client + let client = server.client_builder().build().await; + + // Call rediscover and assert it succeeded + client.rediscover().await.unwrap(); + } + #[async_test] async fn test_discovery_broken_server() { let server = MatrixMockServer::new().await; From 16b5b72496ef9abf06d83a31e6b282724d935c4d Mon Sep 17 00:00:00 2001 From: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> Date: Fri, 3 Jul 2026 00:50:39 +0530 Subject: [PATCH 2/5] changelog: add entry for discovery cache timeout and rediscover() Signed-off-by: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> --- crates/matrix-sdk/changelog.d/6712.added.md | Bin 0 -> 276 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 crates/matrix-sdk/changelog.d/6712.added.md diff --git a/crates/matrix-sdk/changelog.d/6712.added.md b/crates/matrix-sdk/changelog.d/6712.added.md new file mode 100644 index 0000000000000000000000000000000000000000..84228e87bbea7782087cec2de51713a369addb3b GIT binary patch literal 276 zcmZvWK?=e!6hvn&c!w-?;{m!;uOSpQu?A`)X0>|9$Q()=%Bq? zc{v4T?bP#bVVsgG#)3PY6*ZKHm%dC~wI2!oy$9?uoXumx_R~Z*W zTCY13(Pr?R9dse5fk}9uXy^*_>fzxVa71P36-%QIO?tOBKba#+i&thhT56#ukH<7> literal 0 HcmV?d00001 From 9f83e5d5c0d1880585c315017ee7f3f52e9af118 Mon Sep 17 00:00:00 2001 From: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> Date: Thu, 9 Jul 2026 10:59:46 +0530 Subject: [PATCH 3/5] fix: use ok_with_capabilities in test_rediscover Signed-off-by: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> --- crates/matrix-sdk/src/client/mod.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 6d3e66ea44b..2504bd07f34 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -3627,13 +3627,13 @@ impl Client { } /// Force a refresh of all the cached discovery data (supported versions, - /// well-known info, homeserver capabilities, and OAuth 2.0 server metadata), - /// ignoring whether the existing cache is still fresh. + /// well-known info, homeserver capabilities, and OAuth 2.0 server + /// metadata), ignoring whether the existing cache is still fresh. /// - /// If refreshing the well-known info fails, or if the server doesn't support OAuth 2.0 server metadata, it is silently ignored. - /// All other refresh - /// failures are returned as an error, and any remaining refreshes that - /// haven't run yet are skipped. + /// If refreshing the well-known info fails, or if the server doesn't + /// support OAuth 2.0 server metadata, it is silently ignored. All other + /// refresh failures are returned as an error, and any remaining + /// refreshes that haven't run yet are skipped. pub async fn rediscover(&self) -> Result<(), Error> { self.refresh_supported_versions_cache(false).await?; self.refresh_well_known_cache().await; @@ -3740,7 +3740,11 @@ pub(crate) mod tests { RoomId, ServerName, UserId, api::{ FeatureFlag, MatrixVersion, - client::{room::create_room::v3::Request as CreateRoomRequest, rtc::RtcTransport}, + client::{ + discovery::get_capabilities::v3::Capabilities, + room::create_room::v3::Request as CreateRoomRequest, + rtc::RtcTransport, + }, }, assign, events::{ @@ -3972,7 +3976,7 @@ pub(crate) mod tests { server.mock_versions().ok().mock_once().named("versions").mount().await; server .mock_get_homeserver_capabilities() - .ok() + .ok_with_capabilities(Capabilities::default()) .mock_once() .named("capabilities") .mount() From c6a5011e32139ddba7e0b69ce1a03b30413fc7cf Mon Sep 17 00:00:00 2001 From: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:32:15 +0530 Subject: [PATCH 4/5] fix: ignore all OAuth discovery errors in rediscover() Signed-off-by: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> --- crates/matrix-sdk/src/client/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 2504bd07f34..98eb4d547b6 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -3630,8 +3630,8 @@ impl Client { /// well-known info, homeserver capabilities, and OAuth 2.0 server /// metadata), ignoring whether the existing cache is still fresh. /// - /// If refreshing the well-known info fails, or if the server doesn't - /// support OAuth 2.0 server metadata, it is silently ignored. All other + /// If refreshing the well-known info fails, or if the OAuth 2.0 server + /// metadata request fails for any reason, it is silently ignored. /// refresh failures are returned as an error, and any remaining /// refreshes that haven't run yet are skipped. pub async fn rediscover(&self) -> Result<(), Error> { @@ -3639,9 +3639,7 @@ impl Client { self.refresh_well_known_cache().await; self.homeserver_capabilities().refresh().await?; match self.oauth().server_metadata().await { - Ok(_) => {} - Err(OAuthDiscoveryError::NotSupported) => {} - Err(e) => return Err(Error::from(OAuthError::Discovery(e))), + Ok(_) | Err(_) => {} } Ok(()) } From 54d3d0fea6d4e1596183cdfa9d3a2d87d6c9d9e4 Mon Sep 17 00:00:00 2001 From: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:46:56 +0530 Subject: [PATCH 5/5] fix: remove unused OAuthError and OAuthDiscoveryError imports Signed-off-by: SIDHARTH20K4 <91970588+SIDHARTH20K4@users.noreply.github.com> --- crates/matrix-sdk/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 98eb4d547b6..3bec04e4b43 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -93,7 +93,7 @@ use crate::{ authentication::{ AuthCtx, AuthData, ReloadSessionCallback, SaveSessionCallback, matrix::MatrixAuth, - oauth::{OAuth, OAuthError, error::OAuthDiscoveryError}, + oauth::OAuth, }, client::{ homeserver_capabilities::HomeserverCapabilities,