Skip to content

Commit d0f4d67

Browse files
committed
feat(room): add a new function that will only subscribe to a thread if needed
1 parent a8bfb7b commit d0f4d67

File tree

3 files changed

+119
-25
lines changed

3 files changed

+119
-25
lines changed

crates/matrix-sdk/src/event_cache/room/threads.rs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use eyeball_im::VectorDiff;
2020
use matrix_sdk_base::{
2121
event_cache::{Event, Gap},
2222
linked_chunk::{ChunkContent, Position},
23-
store::ThreadSubscription,
2423
};
2524
use ruma::OwnedEventId;
2625
use tokio::sync::broadcast::{Receiver, Sender};
@@ -358,35 +357,17 @@ pub async fn should_subscribe_thread(
358357
/// Optionally subscribe to new threads, if the client enabled automatic thread
359358
/// subscription support.
360359
pub async fn subscribe_to_new_threads(room: &Room, new_thread_subs: AutomaticThreadSubscriptions) {
361-
// If there's no subscriptions, or the client hasn't enabled thread
360+
// If there's no new subscriptions, or the client hasn't enabled thread
362361
// subscriptions, we don't have anything to do.
363362
if new_thread_subs.is_empty() || !room.client.enabled_thread_subscriptions() {
364363
return;
365364
}
366-
367365
for (thread_root, subscribe_up_to_event_id) in new_thread_subs {
368-
let previous_status = match room.load_or_fetch_thread_subscription(&thread_root).await {
369-
Ok(status) => status,
370-
Err(err) => {
371-
warn!(%thread_root, "couldn't fetch thread subscription: {err}");
372-
continue;
373-
}
374-
};
375-
376-
match previous_status {
377-
Some(ThreadSubscription { .. }) => {
378-
// Already subscribed, nothing to do.
379-
trace!(%thread_root, "already subscribed to thread");
380-
}
381-
None => {
382-
// Send an automatic subscription!
383-
let automatic = Some(subscribe_up_to_event_id);
384-
if let Err(err) = room.subscribe_thread(thread_root.clone(), automatic).await {
385-
warn!(%thread_root, "couldn't subscribe to thread: {err}");
386-
} else {
387-
trace!(%thread_root, "subscribed to thread");
388-
}
389-
}
366+
let automatic = Some(subscribe_up_to_event_id);
367+
if let Err(err) = room.subscribe_thread_if_needed(&thread_root, automatic).await {
368+
warn!(%thread_root, "couldn't subscribe to thread: {err}");
369+
} else {
370+
trace!(%thread_root, "subscribed to thread");
390371
}
391372
}
392373
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,6 +3765,43 @@ impl Room {
37653765
}
37663766
}
37673767

3768+
/// Subscribe to a thread if needed, based on a current subscription to it.
3769+
///
3770+
/// This is like [`Self::subscribe_thread`], but it first checks if the user
3771+
/// has already subscribed to a thread, so as to minimize sending
3772+
/// unnecessary subscriptions which would be ignored by the server.
3773+
pub async fn subscribe_thread_if_needed(
3774+
&self,
3775+
thread_root: &EventId,
3776+
automatic: Option<OwnedEventId>,
3777+
) -> Result<()> {
3778+
let prev_sub = self.load_or_fetch_thread_subscription(thread_root).await?;
3779+
3780+
match prev_sub {
3781+
Some(prev_sub) => {
3782+
if prev_sub.automatic {
3783+
// Either we have a manual subscription (which overrides an
3784+
// automatic one), or we have another
3785+
// automatic one (and we can't order these), so send the
3786+
// request to the server.
3787+
} else {
3788+
// The previous subscription was manual. There's no point sending the request
3789+
// here:
3790+
// - if the new subscription is automatic, since a manual subscription is higher
3791+
// priority than an automatic one, it will be ignored by the server.
3792+
// - if the new subscription is manual, this is an idempotent operation.
3793+
return Ok(());
3794+
}
3795+
}
3796+
3797+
None => {
3798+
// There's no prior subscription, so we can safely send one.
3799+
}
3800+
}
3801+
3802+
self.subscribe_thread(thread_root.to_owned(), automatic).await
3803+
}
3804+
37683805
/// Unsubscribe from a given thread in this room.
37693806
///
37703807
/// # Arguments

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,82 @@ async fn test_subscribe_thread() {
7979
assert_matches!(subscription, None);
8080
}
8181

82+
#[async_test]
83+
async fn test_subscribe_thread_if_needed() {
84+
let server = MatrixMockServer::new().await;
85+
let client = server.client_builder().build().await;
86+
87+
let room_id = room_id!("!test:example.org");
88+
let room = server.sync_joined_room(&client, room_id).await;
89+
90+
// The function `subscribe_thread_if_needed` will automatically subscribe to the
91+
// thread, if there's no prior manual subscription, whether the new
92+
// subscription is automatic or not.
93+
for (root_id, automatic) in [
94+
(owned_event_id!("$root"), None),
95+
(owned_event_id!("$woot"), Some(owned_event_id!("$woot"))),
96+
] {
97+
server
98+
.mock_put_thread_subscription()
99+
.match_room_id(room_id.to_owned())
100+
.match_thread_id(root_id.clone())
101+
.ok()
102+
.mock_once()
103+
.mount()
104+
.await;
105+
106+
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
107+
}
108+
109+
// The function `subscribe_thread_if_needed` will automatically subscribe to the
110+
// thread, if there's a previous automatic subscription, whether the new
111+
// subscription is automatic or not.
112+
for (root_id, automatic) in [
113+
(owned_event_id!("$foot"), None),
114+
(owned_event_id!("$toot"), Some(owned_event_id!("$toot"))),
115+
] {
116+
server
117+
.mock_get_thread_subscription()
118+
.match_room_id(room_id.to_owned())
119+
.match_thread_id(root_id.clone())
120+
.ok(true)
121+
.mock_once()
122+
.mount()
123+
.await;
124+
125+
server
126+
.mock_put_thread_subscription()
127+
.match_room_id(room_id.to_owned())
128+
.match_thread_id(root_id.clone())
129+
.ok()
130+
.mock_once()
131+
.mount()
132+
.await;
133+
134+
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
135+
}
136+
137+
// The function `subscribe_thread_if_needed` is a no-op if there's a prior
138+
// manual subscription, whether the new subscription is automatic or not.
139+
for (root_id, automatic) in [
140+
(owned_event_id!("$root"), None),
141+
(owned_event_id!("$woot"), Some(owned_event_id!("$woot"))),
142+
] {
143+
server
144+
.mock_get_thread_subscription()
145+
.match_room_id(room_id.to_owned())
146+
.match_thread_id(root_id.clone())
147+
.ok(false)
148+
.mock_once()
149+
.mount()
150+
.await;
151+
152+
// No-op! (The PUT endpoint hasn't been mocked, so this would result in a 404 if
153+
// it were trying to hit it.)
154+
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
155+
}
156+
}
157+
82158
#[async_test]
83159
async fn test_thread_push_rule_is_triggered_for_subscribed_threads() {
84160
// This test checks that the evaluation of push rules for threads will correctly

0 commit comments

Comments
 (0)