Skip to content

Commit 6dcc394

Browse files
committed
feat(room): add a new function that will only subscribe to a thread if needed
1 parent 67e3bee commit 6dcc394

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
@@ -3740,6 +3740,26 @@ impl Room {
37403740
}
37413741
}
37423742

3743+
/// Subscribe to a thread if needed, based on a current subscription to it.
3744+
///
3745+
/// This is like [`Self::subscribe_thread`], but it first checks if the user
3746+
/// has already subscribed to a thread, so as to minimize sending
3747+
/// unnecessary subscriptions which would be ignored by the server.
3748+
pub async fn subscribe_thread_if_needed(
3749+
&self,
3750+
thread_root: &EventId,
3751+
automatic: Option<OwnedEventId>,
3752+
) -> Result<()> {
3753+
if let Some(prev_sub) = self.load_or_fetch_thread_subscription(thread_root).await? {
3754+
// If we have a previous subscription, we should only send the new one if it's
3755+
// manual and the previous one was automatic.
3756+
if !prev_sub.automatic || automatic.is_some() {
3757+
return Ok(());
3758+
}
3759+
}
3760+
self.subscribe_thread(thread_root.to_owned(), automatic).await
3761+
}
3762+
37433763
/// Unsubscribe from a given thread in this room.
37443764
///
37453765
/// # Arguments
@@ -3821,6 +3841,20 @@ impl Room {
38213841

38223842
Ok(subscription)
38233843
}
3844+
3845+
/// Return the current thread subscription for the given thread root in this
3846+
/// room, by getting it from storage if possible, or fetching it from
3847+
/// network otherwise.
3848+
///
3849+
/// See also [`Self::fetch_thread_subscription`] for the exact semantics of
3850+
/// this method.
3851+
pub async fn load_or_fetch_thread_subscription(
3852+
&self,
3853+
thread_root: &EventId,
3854+
) -> Result<Option<ThreadSubscription>> {
3855+
// A bit of a lie at the moment, since thread subscriptions are not sync'd yet.
3856+
self.fetch_thread_subscription(thread_root.to_owned()).await
3857+
}
38243858
}
38253859

38263860
#[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)