Skip to content

Commit 5e546f6

Browse files
committed
change(spaces): publish VectorDiffs instead of a full vectors for joined spaces and space room list subscriptions
1 parent b13fb14 commit 5e546f6

File tree

3 files changed

+185
-99
lines changed

3 files changed

+185
-99
lines changed

bindings/matrix-sdk-ffi/src/spaces.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
use std::{fmt::Debug, sync::Arc};
1616

17+
use eyeball_im::VectorDiff;
1718
use futures_util::{pin_mut, StreamExt};
1819
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
1920
use matrix_sdk_ui::spaces::{
@@ -57,17 +58,18 @@ impl SpaceService {
5758
&self,
5859
listener: Box<dyn SpaceServiceJoinedSpacesListener>,
5960
) -> Arc<TaskHandle> {
60-
let entries_stream = self.inner.subscribe_to_joined_spaces();
61+
let (initial_values, mut stream) = self.inner.subscribe_to_joined_spaces();
6162

62-
Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
63-
pin_mut!(entries_stream);
63+
listener.on_update(vec![SpaceListUpdate::Reset {
64+
values: initial_values.into_iter().map(Into::into).collect(),
65+
}]);
6466

65-
while let Some(rooms) = entries_stream.next().await {
66-
listener.on_update(rooms.into_iter().map(Into::into).collect());
67+
Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
68+
while let Some(diffs) = stream.next().await {
69+
listener.on_update(diffs.into_iter().map(Into::into).collect());
6770
}
6871
})))
6972
}
70-
7173
#[allow(clippy::unused_async)]
7274
// This method doesn't need to be async but if its not the FFI layer panics
7375
// with "there is no no reactor running, must be called from the context
@@ -122,13 +124,15 @@ impl SpaceRoomList {
122124
&self,
123125
listener: Box<dyn SpaceRoomListEntriesListener>,
124126
) -> Arc<TaskHandle> {
125-
let entries_stream = self.inner.subscribe_to_room_updates();
127+
let (initial_values, mut stream) = self.inner.subscribe_to_room_updates();
126128

127-
Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
128-
pin_mut!(entries_stream);
129+
listener.on_update(vec![SpaceListUpdate::Reset {
130+
values: initial_values.into_iter().map(Into::into).collect(),
131+
}]);
129132

130-
while let Some(rooms) = entries_stream.next().await {
131-
listener.on_update(rooms.into_iter().map(Into::into).collect());
133+
Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
134+
while let Some(diffs) = stream.next().await {
135+
listener.on_update(diffs.into_iter().map(Into::into).collect());
132136
}
133137
})))
134138
}
@@ -145,12 +149,12 @@ pub trait SpaceRoomListPaginationStateListener: SendOutsideWasm + SyncOutsideWas
145149

146150
#[matrix_sdk_ffi_macros::export(callback_interface)]
147151
pub trait SpaceRoomListEntriesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
148-
fn on_update(&self, rooms: Vec<SpaceRoom>);
152+
fn on_update(&self, rooms: Vec<SpaceListUpdate>);
149153
}
150154

151155
#[matrix_sdk_ffi_macros::export(callback_interface)]
152156
pub trait SpaceServiceJoinedSpacesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
153-
fn on_update(&self, rooms: Vec<SpaceRoom>);
157+
fn on_update(&self, room_updates: Vec<SpaceListUpdate>);
154158
}
155159

156160
#[derive(uniffi::Record)]
@@ -190,3 +194,44 @@ impl From<UISpaceRoom> for SpaceRoom {
190194
}
191195
}
192196
}
197+
198+
#[derive(uniffi::Enum)]
199+
pub enum SpaceListUpdate {
200+
Append { values: Vec<SpaceRoom> },
201+
Clear,
202+
PushFront { value: SpaceRoom },
203+
PushBack { value: SpaceRoom },
204+
PopFront,
205+
PopBack,
206+
Insert { index: u32, value: SpaceRoom },
207+
Set { index: u32, value: SpaceRoom },
208+
Remove { index: u32 },
209+
Truncate { length: u32 },
210+
Reset { values: Vec<SpaceRoom> },
211+
}
212+
213+
impl From<VectorDiff<UISpaceRoom>> for SpaceListUpdate {
214+
fn from(diff: VectorDiff<UISpaceRoom>) -> Self {
215+
match diff {
216+
VectorDiff::Append { values } => {
217+
Self::Append { values: values.into_iter().map(|v| v.into()).collect() }
218+
}
219+
VectorDiff::Clear => Self::Clear,
220+
VectorDiff::PushFront { value } => Self::PushFront { value: value.into() },
221+
VectorDiff::PushBack { value } => Self::PushBack { value: value.into() },
222+
VectorDiff::PopFront => Self::PopFront,
223+
VectorDiff::PopBack => Self::PopBack,
224+
VectorDiff::Insert { index, value } => {
225+
Self::Insert { index: index as u32, value: value.into() }
226+
}
227+
VectorDiff::Set { index, value } => {
228+
Self::Set { index: index as u32, value: value.into() }
229+
}
230+
VectorDiff::Remove { index } => Self::Remove { index: index as u32 },
231+
VectorDiff::Truncate { length } => Self::Truncate { length: length as u32 },
232+
VectorDiff::Reset { values } => {
233+
Self::Reset { values: values.into_iter().map(|v| v.into()).collect() }
234+
}
235+
}
236+
}
237+
}

crates/matrix-sdk-ui/src/spaces/mod.rs

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
//!
1717
//! See [`SpaceService`] for details.
1818
19-
use eyeball::{SharedObservable, Subscriber};
19+
use std::sync::Arc;
20+
21+
use eyeball_im::{ObservableVector, VectorSubscriberBatchedStream};
2022
use futures_util::pin_mut;
23+
use imbl::Vector;
2124
use matrix_sdk::{Client, deserialized_responses::SyncOrStrippedState, locks::Mutex};
2225
use matrix_sdk_common::executor::{JoinHandle, spawn};
2326
use ruma::{
@@ -39,7 +42,7 @@ pub mod room_list;
3942
pub struct SpaceService {
4043
client: Client,
4144

42-
joined_spaces: SharedObservable<Vec<SpaceRoom>>,
45+
joined_spaces: Arc<Mutex<ObservableVector<SpaceRoom>>>,
4346

4447
room_update_handle: Mutex<Option<JoinHandle<()>>>,
4548
}
@@ -56,15 +59,17 @@ impl SpaceService {
5659
pub fn new(client: Client) -> Self {
5760
Self {
5861
client,
59-
joined_spaces: SharedObservable::new(Vec::new()),
62+
joined_spaces: Arc::new(Mutex::new(ObservableVector::new())),
6063
room_update_handle: Mutex::new(None),
6164
}
6265
}
6366

64-
pub fn subscribe_to_joined_spaces(&self) -> Subscriber<Vec<SpaceRoom>> {
67+
pub fn subscribe_to_joined_spaces(
68+
&self,
69+
) -> (Vector<SpaceRoom>, VectorSubscriberBatchedStream<SpaceRoom>) {
6570
if self.room_update_handle.lock().is_none() {
66-
let client_clone = self.client.clone();
67-
let joined_spaces_clone = self.joined_spaces.clone();
71+
let client = self.client.clone();
72+
let joined_spaces = Arc::clone(&self.joined_spaces);
6873
let all_room_updates_receiver = self.client.subscribe_to_all_room_updates();
6974

7075
*self.room_update_handle.lock() = Some(spawn(async move {
@@ -73,10 +78,8 @@ impl SpaceService {
7378
loop {
7479
match all_room_updates_receiver.recv().await {
7580
Ok(_) => {
76-
let new_spaces = Self::joined_spaces_for(&client_clone).await;
77-
if new_spaces != joined_spaces_clone.get() {
78-
joined_spaces_clone.set(new_spaces);
79-
}
81+
let new_spaces = Vector::from(Self::joined_spaces_for(&client).await);
82+
Self::update_joined_spaces_if_needed(new_spaces, &joined_spaces);
8083
}
8184
Err(err) => {
8285
error!("error when listening to room updates: {err}");
@@ -86,15 +89,13 @@ impl SpaceService {
8689
}));
8790
}
8891

89-
self.joined_spaces.subscribe()
92+
self.joined_spaces.lock().subscribe().into_values_and_batched_stream()
9093
}
9194

9295
pub async fn joined_spaces(&self) -> Vec<SpaceRoom> {
9396
let spaces = Self::joined_spaces_for(&self.client).await;
9497

95-
if spaces != self.joined_spaces.get() {
96-
self.joined_spaces.set(spaces.clone());
97-
}
98+
Self::update_joined_spaces_if_needed(Vector::from(spaces.clone()), &self.joined_spaces);
9899

99100
spaces
100101
}
@@ -103,6 +104,18 @@ impl SpaceService {
103104
SpaceRoomList::new(self.client.clone(), space_id)
104105
}
105106

107+
fn update_joined_spaces_if_needed(
108+
new_spaces: Vector<SpaceRoom>,
109+
joined_spaces: &Arc<Mutex<ObservableVector<SpaceRoom>>>,
110+
) {
111+
let old_spaces = joined_spaces.lock().clone();
112+
113+
if new_spaces != old_spaces {
114+
joined_spaces.lock().clear();
115+
joined_spaces.lock().append(new_spaces);
116+
}
117+
}
118+
106119
async fn joined_spaces_for(client: &Client) -> Vec<SpaceRoom> {
107120
let joined_spaces = client
108121
.joined_rooms()
@@ -175,6 +188,7 @@ impl SpaceService {
175188
#[cfg(test)]
176189
mod tests {
177190
use assert_matches2::assert_let;
191+
use eyeball_im::VectorDiff;
178192
use futures_util::pin_mut;
179193
use matrix_sdk::{room::ParentSpace, test_utils::mocks::MatrixMockServer};
180194
use matrix_sdk_test::{
@@ -340,7 +354,7 @@ mod tests {
340354

341355
let space_service = SpaceService::new(client.clone());
342356

343-
let joined_spaces_subscriber = space_service.subscribe_to_joined_spaces();
357+
let (_, joined_spaces_subscriber) = space_service.subscribe_to_joined_spaces();
344358
pin_mut!(joined_spaces_subscriber);
345359
assert_pending!(joined_spaces_subscriber);
346360

@@ -349,6 +363,17 @@ mod tests {
349363
vec![SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
350364
);
351365

366+
assert_next_eq!(
367+
joined_spaces_subscriber,
368+
vec![VectorDiff::Append {
369+
values: vec![SpaceRoom::new_from_known(
370+
client.get_room(first_space_id).unwrap(),
371+
0
372+
)]
373+
.into()
374+
}]
375+
);
376+
352377
// Join the second space
353378

354379
server
@@ -380,12 +405,17 @@ mod tests {
380405
]
381406
);
382407

383-
// The subscriber yields new results when a space is joined
384408
assert_next_eq!(
385409
joined_spaces_subscriber,
386410
vec![
387-
SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
388-
SpaceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
411+
VectorDiff::Clear,
412+
VectorDiff::Append {
413+
values: vec![
414+
SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0),
415+
SpaceRoom::new_from_known(client.get_room(second_space_id).unwrap(), 1)
416+
]
417+
.into()
418+
},
389419
]
390420
);
391421

@@ -394,7 +424,16 @@ mod tests {
394424
// and when one is left
395425
assert_next_eq!(
396426
joined_spaces_subscriber,
397-
vec![SpaceRoom::new_from_known(client.get_room(first_space_id).unwrap(), 0)]
427+
vec![
428+
VectorDiff::Clear,
429+
VectorDiff::Append {
430+
values: vec![SpaceRoom::new_from_known(
431+
client.get_room(first_space_id).unwrap(),
432+
0
433+
)]
434+
.into()
435+
},
436+
]
398437
);
399438

400439
// but it doesn't when a non-space room gets joined

0 commit comments

Comments
 (0)