tauri_plugin_matrix_svelte/matrix/
sync.rs1use anyhow::bail;
2use futures::{pin_mut, StreamExt};
3use matrix_sdk::{Client, RoomState};
4use matrix_sdk_ui::{
5 eyeball_im::{Vector, VectorDiff},
6 sync_service::SyncService,
7};
8use tauri::{AppHandle, Runtime};
9
10use crate::matrix::{
11 room::rooms_list::{
12 enqueue_rooms_list_update, handle_room_list_service_loading_state, RoomsListUpdate,
13 },
14 rooms::{add_new_room, remove_room, update_room},
15 singletons::{ALL_JOINED_ROOMS, LOG_ROOM_LIST_DIFFS},
16};
17
18use super::{rooms::RoomListServiceRoomInfo, singletons::SYNC_SERVICE};
19
20pub async fn sync<R: Runtime>(_app_handle: &AppHandle<R>, client: Client) -> anyhow::Result<()> {
21 let sync_service = SyncService::builder(client).build().await?;
22
23 sync_service.start().await;
25 let room_list_service = sync_service.room_list_service();
26 SYNC_SERVICE
27 .set(sync_service)
28 .unwrap_or_else(|_| panic!("BUG: SYNC_SERVICE already set!"));
29
30 let all_rooms_list = room_list_service.all_rooms().await?;
31 handle_room_list_service_loading_state(all_rooms_list.loading_state());
32
33 let (room_diff_stream, room_list_dynamic_entries_controller) =
34 all_rooms_list.entries_with_dynamic_adapters(usize::MAX);
35
36 room_list_dynamic_entries_controller.set_filter(Box::new(|room| match room.state() {
38 RoomState::Joined => true,
39 _ => false,
40 }));
41
42 let mut all_known_rooms: Vector<RoomListServiceRoomInfo> = Vector::new();
43
44 pin_mut!(room_diff_stream);
45 while let Some(batch) = room_diff_stream.next().await {
46 let mut peekable_diffs = batch.into_iter().peekable();
47 while let Some(diff) = peekable_diffs.next() {
48 match diff {
49 VectorDiff::Append { values: new_rooms } => {
50 let _num_new_rooms = new_rooms.len();
51 if LOG_ROOM_LIST_DIFFS {
52 println!("room_list: diff Append {_num_new_rooms}");
53 }
54 for new_room in new_rooms {
55 add_new_room(&new_room, &room_list_service).await?;
56 all_known_rooms.push_back(new_room.into());
57 }
58 }
59 VectorDiff::Clear => {
60 if LOG_ROOM_LIST_DIFFS {
61 println!("room_list: diff Clear");
62 }
63 all_known_rooms.clear();
64 ALL_JOINED_ROOMS.lock().unwrap().clear();
65 enqueue_rooms_list_update(RoomsListUpdate::ClearRooms);
66 }
67 VectorDiff::PushFront { value: new_room } => {
68 if LOG_ROOM_LIST_DIFFS {
69 println!("room_list: diff PushFront");
70 }
71 add_new_room(&new_room, &room_list_service).await?;
72 all_known_rooms.push_front(new_room.into());
73 }
74 VectorDiff::PushBack { value: new_room } => {
75 if LOG_ROOM_LIST_DIFFS {
76 println!("room_list: diff PushBack");
77 }
78 add_new_room(&new_room, &room_list_service).await?;
79 all_known_rooms.push_back(new_room.into());
80 }
81 VectorDiff::PopFront => {
82 if LOG_ROOM_LIST_DIFFS {
83 println!("room_list: diff PopFront");
84 }
85 if let Some(room) = all_known_rooms.pop_front() {
86 if LOG_ROOM_LIST_DIFFS {
87 println!("PopFront: removing {}", room.room_id);
88 }
89 remove_room(&room);
90 }
91 }
92 VectorDiff::PopBack => {
93 if LOG_ROOM_LIST_DIFFS {
94 println!("room_list: diff PopBack");
95 }
96 if let Some(room) = all_known_rooms.pop_back() {
97 if LOG_ROOM_LIST_DIFFS {
98 println!("PopBack: removing {}", room.room_id);
99 }
100 remove_room(&room);
101 }
102 }
103 VectorDiff::Insert {
104 index,
105 value: new_room,
106 } => {
107 if LOG_ROOM_LIST_DIFFS {
108 println!("room_list: diff Insert at {index}");
109 }
110 add_new_room(&new_room, &room_list_service).await?;
111 all_known_rooms.insert(index, new_room.into());
112 }
113 VectorDiff::Set {
114 index,
115 value: changed_room,
116 } => {
117 if LOG_ROOM_LIST_DIFFS {
118 println!("room_list: diff Set at {index}");
119 }
120 if let Some(old_room) = all_known_rooms.get(index) {
121 update_room(old_room, &changed_room, &room_list_service).await?;
122 } else {
123 eprintln!("BUG: room list diff: Set index {index} was out of bounds.");
124 }
125 all_known_rooms.set(index, changed_room.into());
126 }
127 VectorDiff::Remove {
128 index: remove_index,
129 } => {
130 if LOG_ROOM_LIST_DIFFS {
131 println!("room_list: diff Remove at {remove_index}");
132 }
133 if remove_index < all_known_rooms.len() {
134 let room = all_known_rooms.remove(remove_index);
135 let mut next_diff_was_handled = false;
142 if let Some(VectorDiff::Insert {
143 index: insert_index,
144 value: new_room,
145 }) = peekable_diffs.peek()
146 {
147 if room.room_id == new_room.room_id() {
148 if LOG_ROOM_LIST_DIFFS {
149 println!("Optimizing Remove({remove_index}) + Insert({insert_index}) into Set (update) for room {}", room.room_id);
150 }
151 update_room(&room, new_room, &room_list_service).await?;
152 all_known_rooms.insert(*insert_index, new_room.clone().into());
153 next_diff_was_handled = true;
154 }
155 }
156 if next_diff_was_handled {
157 peekable_diffs.next(); } else {
159 println!("UNTESTED SCENARIO: room_list: diff Remove({remove_index}) was NOT followed by an Insert. Removed room: {}", room.room_id);
160 remove_room(&room);
161 }
162 } else {
163 eprintln!("BUG: room_list: diff Remove index {remove_index} out of bounds, len {}", all_known_rooms.len());
164 }
165 }
166 VectorDiff::Truncate { length } => {
167 if LOG_ROOM_LIST_DIFFS {
168 println!("room_list: diff Truncate to {length}");
169 }
170 while all_known_rooms.len() > length {
172 if let Some(room) = all_known_rooms.pop_back() {
173 remove_room(&room);
174 }
175 }
176 all_known_rooms.truncate(length); }
178 VectorDiff::Reset { values: new_rooms } => {
179 if LOG_ROOM_LIST_DIFFS {
181 println!(
182 "room_list: diff Reset, old length {}, new length {}",
183 all_known_rooms.len(),
184 new_rooms.len()
185 );
186 }
187 while let Some(room) = all_known_rooms.pop_back() {
189 remove_room(&room);
190 }
191 ALL_JOINED_ROOMS.lock().unwrap().clear();
194 enqueue_rooms_list_update(RoomsListUpdate::ClearRooms);
195 for room in &new_rooms {
196 add_new_room(room, &room_list_service).await?;
197 }
198 all_known_rooms = new_rooms.into_iter().map(|r| r.into()).collect();
199 }
200 }
201 }
202 }
203
204 bail!("room list service sync loop ended unexpectedly")
205}