Skip to content

Commit 1554c9d

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

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,26 @@ impl Room {
37713771
}
37723772
}
37733773

3774+
/// Subscribe to a thread if needed, based on a current subscription to it.
3775+
///
3776+
/// This is like [`Self::subscribe_thread`], but it first checks if the user
3777+
/// has already subscribed to a thread, so as to minimize sending
3778+
/// unnecessary subscriptions which would be ignored by the server.
3779+
pub async fn subscribe_thread_if_needed(
3780+
&self,
3781+
thread_root: &EventId,
3782+
automatic: Option<OwnedEventId>,
3783+
) -> Result<()> {
3784+
if let Some(prev_sub) = self.load_or_fetch_thread_subscription(thread_root).await? {
3785+
// If we have a previous subscription, we should only send the new one if it's
3786+
// manual and the previous one was automatic.
3787+
if !prev_sub.automatic || automatic.is_some() {
3788+
return Ok(());
3789+
}
3790+
}
3791+
self.subscribe_thread(thread_root.to_owned(), automatic).await
3792+
}
3793+
37743794
/// Unsubscribe from a given thread in this room.
37753795
///
37763796
/// # Arguments
@@ -3852,6 +3872,20 @@ impl Room {
38523872

38533873
Ok(subscription)
38543874
}
3875+
3876+
/// Return the current thread subscription for the given thread root in this
3877+
/// room, by getting it from storage if possible, or fetching it from
3878+
/// network otherwise.
3879+
///
3880+
/// See also [`Self::fetch_thread_subscription`] for the exact semantics of
3881+
/// this method.
3882+
pub async fn load_or_fetch_thread_subscription(
3883+
&self,
3884+
thread_root: &EventId,
3885+
) -> Result<Option<ThreadSubscription>> {
3886+
// A bit of a lie at the moment, since thread subscriptions are not sync'd yet.
3887+
self.fetch_thread_subscription(thread_root.to_owned()).await
3888+
}
38553889
}
38563890

38573891
#[cfg(feature = "e2e-encryption")]

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

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,97 @@ 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+
// If there's no prior subscription, the function `subscribe_thread_if_needed`
91+
// will automatically subscribe to the thread, whether the new subscription
92+
// 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+
// If there's a prior automatic subscription, the function
110+
// `subscribe_thread_if_needed` will only subscribe to the thread if the new
111+
// subscription is manual.
112+
{
113+
let root_id = owned_event_id!("$toot");
114+
115+
server
116+
.mock_get_thread_subscription()
117+
.match_room_id(room_id.to_owned())
118+
.match_thread_id(root_id.clone())
119+
.ok(true)
120+
.mock_once()
121+
.mount()
122+
.await;
123+
124+
server
125+
.mock_put_thread_subscription()
126+
.match_room_id(room_id.to_owned())
127+
.match_thread_id(root_id.clone())
128+
.ok()
129+
.mock_once()
130+
.mount()
131+
.await;
132+
133+
room.subscribe_thread_if_needed(&root_id, None).await.unwrap();
134+
}
135+
136+
// Otherwise, it will be a no-op.
137+
{
138+
let root_id = owned_event_id!("$foot");
139+
140+
server
141+
.mock_get_thread_subscription()
142+
.match_room_id(room_id.to_owned())
143+
.match_thread_id(root_id.clone())
144+
.ok(true)
145+
.mock_once()
146+
.mount()
147+
.await;
148+
149+
room.subscribe_thread_if_needed(&root_id, Some(owned_event_id!("$foot"))).await.unwrap();
150+
}
151+
152+
// The function `subscribe_thread_if_needed` is a no-op if there's a prior
153+
// manual subscription, whether the new subscription is automatic or not.
154+
for (root_id, automatic) in [
155+
(owned_event_id!("$root"), None),
156+
(owned_event_id!("$woot"), Some(owned_event_id!("$woot"))),
157+
] {
158+
server
159+
.mock_get_thread_subscription()
160+
.match_room_id(room_id.to_owned())
161+
.match_thread_id(root_id.clone())
162+
.ok(false)
163+
.mock_once()
164+
.mount()
165+
.await;
166+
167+
// No-op! (The PUT endpoint hasn't been mocked, so this would result in a 404 if
168+
// it were trying to hit it.)
169+
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
170+
}
171+
}
172+
82173
#[async_test]
83174
async fn test_thread_push_rule_is_triggered_for_subscribed_threads() {
84175
// This test checks that the evaluation of push rules for threads will correctly

0 commit comments

Comments
 (0)