Skip to content

Commit d57d3c4

Browse files
committed
feat(sdk): save the unsubscribed status in the store, and use it to return something more precise than unknown when fetching a subscription
1 parent 1a5cb2b commit d57d3c4

File tree

4 files changed

+88
-31
lines changed
  • bindings/matrix-sdk-ffi/src/room
  • crates/matrix-sdk
  • labs/multiverse/src/widgets/room_view

4 files changed

+88
-31
lines changed

bindings/matrix-sdk-ffi/src/room/mod.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,22 +1129,29 @@ impl Room {
11291129
pub async fn fetch_thread_subscription(
11301130
&self,
11311131
thread_root_event_id: String,
1132-
) -> Result<Option<ThreadSubscription>, ClientError> {
1132+
) -> Result<Option<ThreadStatus>, ClientError> {
11331133
let thread_root = EventId::parse(thread_root_event_id)?;
1134-
Ok(self
1135-
.inner
1136-
.fetch_thread_subscription(thread_root)
1137-
.await?
1138-
.map(|sub| ThreadSubscription { automatic: sub.automatic }))
1134+
Ok(self.inner.fetch_thread_subscription(thread_root).await?.map(|sub| match sub {
1135+
matrix_sdk::room::ThreadStatus::Subscribed { automatic } => {
1136+
ThreadStatus::Subscribed { automatic }
1137+
}
1138+
matrix_sdk::room::ThreadStatus::Unsubscribed => ThreadStatus::Unsubscribed,
1139+
}))
11391140
}
11401141
}
11411142

11421143
/// Status of a thread subscription (MSC4306).
1143-
#[derive(uniffi::Record)]
1144-
pub struct ThreadSubscription {
1145-
/// Whether the thread subscription happened automatically (e.g. after a
1146-
/// mention) or if it was manually requested by the user.
1147-
automatic: bool,
1144+
#[derive(uniffi::Enum)]
1145+
pub enum ThreadStatus {
1146+
/// The thread is subscribed to.
1147+
Subscribed {
1148+
/// Whether the thread subscription happened automatically (e.g. after a
1149+
/// mention) or if it was manually requested by the user.
1150+
automatic: bool,
1151+
},
1152+
1153+
/// The thread is not subscribed to.
1154+
Unsubscribed,
11481155
}
11491156

11501157
/// A listener for receiving new live location shares in a room.

crates/matrix-sdk/src/room/mod.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use http::StatusCode;
3434
pub use identity_status_changes::IdentityStatusChanges;
3535
#[cfg(feature = "e2e-encryption")]
3636
use matrix_sdk_base::crypto::{IdentityStatusChange, RoomIdentityProvider, UserIdentity};
37+
pub use matrix_sdk_base::store::ThreadStatus;
3738
#[cfg(feature = "e2e-encryption")]
3839
use matrix_sdk_base::{crypto::RoomEventDecryptionResult, deserialized_responses::EncryptionInfo};
3940
use matrix_sdk_base::{
@@ -3657,10 +3658,21 @@ impl Room {
36573658
self.client
36583659
.send(subscribe_thread::unstable::Request::new(
36593660
self.room_id().to_owned(),
3660-
thread_root,
3661+
thread_root.clone(),
36613662
automatic,
36623663
))
36633664
.await?;
3665+
3666+
// Immediately save the result into the database.
3667+
self.client
3668+
.state_store()
3669+
.upsert_thread_subscription(
3670+
self.room_id(),
3671+
&thread_root,
3672+
ThreadStatus::Subscribed { automatic },
3673+
)
3674+
.await?;
3675+
36643676
Ok(())
36653677
}
36663678

@@ -3679,9 +3691,16 @@ impl Room {
36793691
self.client
36803692
.send(unsubscribe_thread::unstable::Request::new(
36813693
self.room_id().to_owned(),
3682-
thread_root,
3694+
thread_root.clone(),
36833695
))
36843696
.await?;
3697+
3698+
// Immediately save the result into the database.
3699+
self.client
3700+
.state_store()
3701+
.upsert_thread_subscription(self.room_id(), &thread_root, ThreadStatus::Unsubscribed)
3702+
.await?;
3703+
36853704
Ok(())
36863705
}
36873706

@@ -3695,42 +3714,57 @@ impl Room {
36953714
///
36963715
/// # Returns
36973716
///
3698-
/// - An `Ok` result with `Some(ThreadSubscription)` if the subscription
3699-
/// exists.
3717+
/// - An `Ok` result with `Some(ThreadStatus)` if we have some subscription
3718+
/// information.
37003719
/// - An `Ok` result with `None` if the subscription does not exist, or the
37013720
/// event couldn't be found, or the event isn't a thread.
37023721
/// - An error if the request fails for any other reason, such as a network
37033722
/// error.
37043723
pub async fn fetch_thread_subscription(
37053724
&self,
37063725
thread_root: OwnedEventId,
3707-
) -> Result<Option<ThreadSubscription>> {
3726+
) -> Result<Option<ThreadStatus>> {
37083727
let result = self
37093728
.client
37103729
.send(get_thread_subscription::unstable::Request::new(
37113730
self.room_id().to_owned(),
3712-
thread_root,
3731+
thread_root.clone(),
37133732
))
37143733
.await;
37153734

37163735
match result {
3717-
Ok(response) => Ok(Some(ThreadSubscription { automatic: response.automatic })),
3736+
Ok(response) => Ok(Some(ThreadStatus::Subscribed { automatic: response.automatic })),
37183737
Err(http_error) => match http_error.as_client_api_error() {
3719-
Some(error) if error.status_code == StatusCode::NOT_FOUND => Ok(None),
3738+
Some(error) if error.status_code == StatusCode::NOT_FOUND => {
3739+
// At this point the server returned no subscriptions, which can mean that the
3740+
// endpoint doesn't exist (not enabled/implemented yet on the server), or that
3741+
// the thread doesn't exist, or that the user has unsubscribed from it
3742+
// previously.
3743+
//
3744+
// If we had any information about prior unsubscription, we can use it here to
3745+
// return something slightly more precise than what the server returned.
3746+
let stored_status = self
3747+
.client
3748+
.state_store()
3749+
.load_thread_subscription(self.room_id(), &thread_root)
3750+
.await?;
3751+
3752+
if let Some(ThreadStatus::Unsubscribed) = stored_status {
3753+
// The thread was unsubscribed from before, so maintain this information.
3754+
Ok(Some(ThreadStatus::Unsubscribed))
3755+
} else {
3756+
// We either have stale information (the thread was marked as subscribed
3757+
// to, but the server said it wasn't), or we didn't have any information.
3758+
// Return unknown.
3759+
Ok(None)
3760+
}
3761+
}
37203762
_ => Err(http_error.into()),
37213763
},
37223764
}
37233765
}
37243766
}
37253767

3726-
/// Status of a thread subscription.
3727-
#[derive(Debug, Clone, Copy)]
3728-
pub struct ThreadSubscription {
3729-
/// Whether the subscription was made automatically by a client, not by
3730-
/// manual user choice.
3731-
pub automatic: bool,
3732-
}
3733-
37343768
#[cfg(feature = "e2e-encryption")]
37353769
impl RoomIdentityProvider for Room {
37363770
fn is_member<'a>(&'a self, user_id: &'a UserId) -> BoxFuture<'a, bool> {

crates/matrix-sdk/tests/integration/room/thread.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use matrix_sdk::test_utils::mocks::MatrixMockServer;
1+
use assert_matches2::assert_matches;
2+
use matrix_sdk::{room::ThreadStatus, test_utils::mocks::MatrixMockServer};
23
use matrix_sdk_test::async_test;
34
use ruma::{owned_event_id, room_id};
45

@@ -35,7 +36,7 @@ async fn test_subscribe_thread() {
3536

3637
// I can get the subscription status for that same thread.
3738
let subscription = room.fetch_thread_subscription(root_id.clone()).await.unwrap().unwrap();
38-
assert!(subscription.automatic);
39+
assert_matches!(subscription, ThreadStatus::Subscribed { automatic: true });
3940

4041
// If I try to get a subscription for a thread event that's unknown, I get no
4142
// `ThreadSubscription`, not an error.
@@ -53,5 +54,10 @@ async fn test_subscribe_thread() {
5354
.mount()
5455
.await;
5556

56-
room.unsubscribe_thread(root_id).await.unwrap();
57+
room.unsubscribe_thread(root_id.clone()).await.unwrap();
58+
59+
// Now, if I retry to get the subscription status for this thread, it's
60+
// unsubscribed.
61+
let subscription = room.fetch_thread_subscription(root_id).await.unwrap();
62+
assert_matches!(subscription, Some(ThreadStatus::Unsubscribed));
5763
}

labs/multiverse/src/widgets/room_view/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use matrix_sdk::{
1313
api::client::receipt::create_receipt::v3::ReceiptType,
1414
events::room::message::RoomMessageEventContent,
1515
},
16+
store::ThreadStatus,
1617
};
1718
use matrix_sdk_ui::{
1819
Timeline,
@@ -525,7 +526,16 @@ impl RoomView {
525526
Ok(Some(subscription)) => {
526527
status_handle.set_message(format!(
527528
"Thread subscription status: {}",
528-
if subscription.automatic { "automatic" } else { "manual" }
529+
match subscription {
530+
ThreadStatus::Subscribed { automatic } => {
531+
if automatic {
532+
"subscribed (automatic)"
533+
} else {
534+
"subscribed (manual)"
535+
}
536+
}
537+
ThreadStatus::Unsubscribed => "unsubscribed",
538+
}
529539
));
530540
}
531541
Ok(None) => {

0 commit comments

Comments
 (0)