Skip to content

Commit ebb7059

Browse files
committed
refactor(threads): adapt to Ruma API changes for thread subscriptions
1 parent 8d3b1d3 commit ebb7059

File tree

5 files changed

+77
-21
lines changed

5 files changed

+77
-21
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ impl Room {
11121112
let thread_root = EventId::parse(thread_root_event_id)?;
11131113
if subscribed {
11141114
// This is a manual subscription.
1115-
let automatic = false;
1115+
let automatic = None;
11161116
self.inner.subscribe_thread(thread_root, automatic).await?;
11171117
} else {
11181118
self.inner.unsubscribe_thread(thread_root).await?;

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

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3655,35 +3655,63 @@ impl Room {
36553655
///
36563656
/// - `thread_root`: The ID of the thread root event to subscribe to.
36573657
/// - `automatic`: Whether the subscription was made automatically by a
3658-
/// client, not by manual user choice. If there was a previous automatic
3659-
/// subscription, and that's set to `true` (i.e. we're now subscribing
3660-
/// manually), the subscription will be overridden to a manual one
3661-
/// instead.
3658+
/// client, not by manual user choice. If set, must include the latest
3659+
/// event ID that's known in the thread and that is causing the automatic
3660+
/// subscription. If unset (i.e. we're now subscribing manually) and there
3661+
/// was a previous automatic subscription, the subscription will be
3662+
/// overridden to a manual one instead.
36623663
///
36633664
/// # Returns
36643665
///
36653666
/// - A 404 error if the event isn't known, or isn't a thread root.
3666-
/// - An `Ok` result if the subscription was successful.
3667-
pub async fn subscribe_thread(&self, thread_root: OwnedEventId, automatic: bool) -> Result<()> {
3668-
self.client
3667+
/// - An `Ok` result if the subscription was successful, or if the server
3668+
/// skipped an automatic subscription (as the user unsubscribed from the
3669+
/// thread after the event causing the automatic subscription).
3670+
pub async fn subscribe_thread(
3671+
&self,
3672+
thread_root: OwnedEventId,
3673+
automatic: Option<OwnedEventId>,
3674+
) -> Result<()> {
3675+
let is_automatic = automatic.is_some();
3676+
3677+
match self
3678+
.client
36693679
.send(subscribe_thread::unstable::Request::new(
36703680
self.room_id().to_owned(),
36713681
thread_root.clone(),
36723682
automatic,
36733683
))
3674-
.await?;
3684+
.await
3685+
{
3686+
Ok(_response) => {
3687+
trace!("Server acknowledged the thread subscription; saving in db");
3688+
// Immediately save the result into the database.
3689+
self.client
3690+
.state_store()
3691+
.upsert_thread_subscription(
3692+
self.room_id(),
3693+
&thread_root,
3694+
ThreadStatus::Subscribed { automatic: is_automatic },
3695+
)
3696+
.await?;
36753697

3676-
// Immediately save the result into the database.
3677-
self.client
3678-
.state_store()
3679-
.upsert_thread_subscription(
3680-
self.room_id(),
3681-
&thread_root,
3682-
ThreadStatus::Subscribed { automatic },
3683-
)
3684-
.await?;
3698+
Ok(())
3699+
}
36853700

3686-
Ok(())
3701+
Err(err) => {
3702+
if let Some(ErrorKind::ConflictingUnsubscription) = err.client_api_error_kind() {
3703+
// In this case: the server indicates that the user unsubscribed *after* the
3704+
// event ID we've used in an automatic subscription; don't
3705+
// save the subscription state in the database, as the
3706+
// previous one should be more correct.
3707+
trace!("Thread subscription skipped: {err}");
3708+
Ok(())
3709+
} else {
3710+
// Forward the error to the caller.
3711+
Err(err.into())
3712+
}
3713+
}
3714+
}
36873715
}
36883716

36893717
/// Unsubscribe from a given thread in this room.

crates/matrix-sdk/src/test_utils/mocks/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3879,6 +3879,17 @@ impl<'a> MockEndpoint<'a, PutThreadSubscriptionEndpoint> {
38793879
self.respond_with(ResponseTemplate::new(200))
38803880
}
38813881

3882+
/// Returns that the server skipped an automated thread subscription,
3883+
/// because the user unsubscribed to the thread after the event id passed in
3884+
/// the automatic subscription.
3885+
pub fn conflicting_unsubscription(mut self) -> MatrixMock<'a> {
3886+
self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
3887+
self.respond_with(ResponseTemplate::new(409).set_body_json(json!({
3888+
"errcode": "IO.ELEMENT.MSC4306.M_CONFLICTING_UNSUBSCRIPTION",
3889+
"error": "the user unsubscribed after the subscription event id"
3890+
})))
3891+
}
3892+
38823893
/// Match the request parameter against a specific room id.
38833894
pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
38843895
self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async fn test_subscribe_thread() {
2323
.await;
2424

2525
// I can subscribe to a thread.
26-
room.subscribe_thread(root_id.clone(), true).await.unwrap();
26+
room.subscribe_thread(root_id.clone(), Some(root_id.clone())).await.unwrap();
2727

2828
server
2929
.mock_get_thread_subscription()
@@ -58,6 +58,23 @@ async fn test_subscribe_thread() {
5858

5959
// Now, if I retry to get the subscription status for this thread, it's
6060
// unsubscribed.
61+
let subscription = room.fetch_thread_subscription(root_id.clone()).await.unwrap();
62+
assert_matches!(subscription, Some(ThreadStatus::Unsubscribed));
63+
64+
// Subscribing automatically to the thread may also return a `M_SKIPPED` error
65+
// that should be non-fatal.
66+
server
67+
.mock_put_thread_subscription()
68+
.match_room_id(room_id.to_owned())
69+
.match_thread_id(root_id.clone())
70+
.conflicting_unsubscription()
71+
.mock_once()
72+
.mount()
73+
.await;
74+
75+
room.subscribe_thread(root_id.clone(), Some(root_id.clone())).await.unwrap();
76+
77+
// And in this case, the thread is still unsubscribed.
6178
let subscription = room.fetch_thread_subscription(root_id).await.unwrap();
6279
assert_matches!(subscription, Some(ThreadStatus::Unsubscribed));
6380
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ impl RoomView {
491491
async fn subscribe_thread(&mut self) {
492492
if let TimelineKind::Thread { thread_root, .. } = &self.kind {
493493
self.call_with_room(async |room, status_handle| {
494-
if let Err(err) = room.subscribe_thread(thread_root.clone(), false).await {
494+
if let Err(err) = room.subscribe_thread(thread_root.clone(), None).await {
495495
status_handle.set_message(format!("error when subscribing to a thread: {err}"));
496496
} else {
497497
status_handle.set_message("Subscribed to thread!".to_owned());

0 commit comments

Comments
 (0)