matrix_sdk_base/response_processors/room/
sync_v2.rs1use std::collections::{BTreeMap, BTreeSet};
16
17use ruma::{
18 OwnedRoomId, OwnedUserId, RoomId, UserId,
19 api::client::sync::sync_events::v3::{
20 InvitedRoom, JoinedRoom, KnockedRoom, LeftRoom, State as RumaState,
21 },
22};
23use tracing::error;
24
25#[cfg(feature = "e2e-encryption")]
26use super::super::e2ee;
27use super::{
28 super::{Context, account_data, ephemeral_events, notification, state_events, timeline},
29 RoomCreationData,
30};
31use crate::{
32 Result, RoomState,
33 sync::{InvitedRoomUpdate, JoinedRoomUpdate, KnockedRoomUpdate, LeftRoomUpdate, State},
34};
35
36#[allow(clippy::too_many_arguments)]
38pub async fn update_joined_room(
39 context: &mut Context,
40 room_creation_data: RoomCreationData<'_>,
41 joined_room: JoinedRoom,
42 updated_members_in_room: &mut BTreeMap<OwnedRoomId, BTreeSet<OwnedUserId>>,
43 notification: notification::Notification<'_>,
44 #[cfg(feature = "e2e-encryption")] e2ee: &e2ee::E2EE<'_>,
45) -> Result<JoinedRoomUpdate> {
46 let RoomCreationData { room_id, requested_required_states, ambiguity_cache, avatar_cache } =
47 room_creation_data;
48
49 let state_store = notification.state_store;
50
51 let room = state_store.get_or_create_room(room_id, RoomState::Joined);
52
53 let mut room_info = room.clone_info();
54
55 room_info.mark_as_joined();
56 room_info.update_from_ruma_summary(&joined_room.summary);
57 room_info.set_prev_batch(joined_room.timeline.prev_batch.as_deref());
58 room_info.mark_state_fully_synced();
59 room_info.handle_encryption_state(requested_required_states.for_room(room_id));
60
61 let mut new_user_ids = BTreeSet::new();
62
63 let state = State::from_sync_v2(joined_room.state);
64 let raw_state_events = state.collect(&joined_room.timeline.events);
65
66 state_events::sync::dispatch(
67 context,
68 raw_state_events,
69 &mut room_info,
70 ambiguity_cache,
71 avatar_cache,
72 &mut new_user_ids,
73 state_store,
74 #[cfg(feature = "experimental-encrypted-state-events")]
75 e2ee,
76 )
77 .await?;
78
79 ephemeral_events::dispatch(context, &joined_room.ephemeral.events, room_id);
80
81 if joined_room.timeline.limited {
82 room_info.mark_members_missing();
83 }
84
85 #[cfg(feature = "e2e-encryption")]
86 let olm_machine = e2ee.olm_machine;
87
88 let timeline = timeline::build(
89 context,
90 &room,
91 &mut room_info,
92 timeline::builder::Timeline::from(joined_room.timeline),
93 notification,
94 #[cfg(feature = "e2e-encryption")]
95 e2ee,
96 )
97 .await?;
98
99 context.state_changes.add_room(room_info);
101
102 account_data::for_room(context, room_id, &joined_room.account_data.events, state_store);
103
104 let mut room_info = context
110 .state_changes
111 .room_infos
112 .get(room_id)
113 .expect("`RoomInfo` must exist in `StateChanges` at this point")
114 .clone();
115
116 #[cfg(feature = "e2e-encryption")]
117 e2ee::tracked_users::update_or_set_if_room_is_newly_encrypted(
118 olm_machine,
119 &new_user_ids,
120 room_info.encryption_state(),
121 room.encryption_state(),
122 room_id,
123 state_store,
124 )
125 .await?;
126
127 updated_members_in_room.insert(room_id.to_owned(), new_user_ids);
128
129 let notification_count = joined_room.unread_notifications.into();
130 room_info.update_notification_count(notification_count);
131
132 context.state_changes.add_room(room_info);
133
134 Ok(JoinedRoomUpdate::new(
135 timeline,
136 state,
137 joined_room.account_data.events,
138 joined_room.ephemeral.events,
139 notification_count,
140 ambiguity_cache.changes.remove(room_id).unwrap_or_default(),
141 avatar_cache.remove_changes(room_id),
142 ))
143}
144
145#[allow(clippy::too_many_arguments)]
147pub async fn update_left_room(
148 context: &mut Context,
149 room_creation_data: RoomCreationData<'_>,
150 left_room: LeftRoom,
151 notification: notification::Notification<'_>,
152 #[cfg(feature = "e2e-encryption")] e2ee: &e2ee::E2EE<'_>,
153) -> Result<LeftRoomUpdate> {
154 let RoomCreationData { room_id, requested_required_states, ambiguity_cache, avatar_cache } =
155 room_creation_data;
156
157 #[cfg(feature = "e2e-encryption")]
158 let olm_machine = e2ee.olm_machine;
159
160 let state_store = notification.state_store;
161
162 let room = state_store.get_or_create_room(room_id, RoomState::Left);
163
164 let mut room_info = room.clone_info();
165 room_info.mark_as_left();
166 room_info.mark_state_partially_synced();
167 room_info.handle_encryption_state(requested_required_states.for_room(room_id));
168
169 let state = State::from_sync_v2(left_room.state);
170 let raw_state_events = state.collect(&left_room.timeline.events);
171
172 state_events::sync::dispatch(
173 context,
174 raw_state_events,
175 &mut room_info,
176 ambiguity_cache,
177 avatar_cache,
178 &mut (),
179 state_store,
180 #[cfg(feature = "experimental-encrypted-state-events")]
181 e2ee,
182 )
183 .await?;
184
185 let timeline = timeline::build(
186 context,
187 &room,
188 &mut room_info,
189 timeline::builder::Timeline::from(left_room.timeline),
190 notification,
191 #[cfg(feature = "e2e-encryption")]
192 e2ee,
193 )
194 .await?;
195
196 #[cfg(feature = "e2e-encryption")]
199 if let Some(olm_machine) = olm_machine {
200 olm_machine.store().clear_room_pending_key_bundle(room_info.room_id()).await?
201 }
202
203 context.state_changes.add_room(room_info);
205
206 account_data::for_room(context, room_id, &left_room.account_data.events, state_store);
207
208 let ambiguity_changes = ambiguity_cache.changes.remove(room_id).unwrap_or_default();
209
210 Ok(LeftRoomUpdate::new(timeline, state, left_room.account_data.events, ambiguity_changes))
211}
212
213pub async fn update_invited_room(
215 context: &mut Context,
216 room_id: &RoomId,
217 user_id: &UserId,
218 invited_room: InvitedRoom,
219 notification: notification::Notification<'_>,
220 #[cfg(feature = "e2e-encryption")] e2ee: &e2ee::E2EE<'_>,
221) -> Result<InvitedRoomUpdate> {
222 let state_store = notification.state_store;
223
224 let room = state_store.get_or_create_room(room_id, RoomState::Invited);
225
226 let raw_state_events = state_events::stripped::collect(&invited_room.invite_state.events);
227
228 let mut room_info = room.clone_info();
229 room_info.mark_as_invited();
230 room_info.mark_state_fully_synced();
231
232 state_events::stripped::dispatch_invite_or_knock(
233 context,
234 raw_state_events,
235 &room,
236 &mut room_info,
237 user_id,
238 notification,
239 )
240 .await?;
241
242 #[cfg(feature = "e2e-encryption")]
245 if let Some(olm_machine) = e2ee.olm_machine {
246 olm_machine.store().clear_room_pending_key_bundle(room_info.room_id()).await?
247 }
248
249 context.state_changes.add_room(room_info);
250
251 Ok(invited_room)
252}
253
254pub async fn update_knocked_room(
256 context: &mut Context,
257 room_id: &RoomId,
258 user_id: &UserId,
259 knocked_room: KnockedRoom,
260 notification: notification::Notification<'_>,
261 #[cfg(feature = "e2e-encryption")] e2ee: &e2ee::E2EE<'_>,
262) -> Result<KnockedRoomUpdate> {
263 let state_store = notification.state_store;
264
265 let room = state_store.get_or_create_room(room_id, RoomState::Knocked);
266
267 let raw_state_events = state_events::stripped::collect(&knocked_room.knock_state.events);
268
269 let mut room_info = room.clone_info();
270 room_info.mark_as_knocked();
271 room_info.mark_state_fully_synced();
272
273 state_events::stripped::dispatch_invite_or_knock(
274 context,
275 raw_state_events,
276 &room,
277 &mut room_info,
278 user_id,
279 notification,
280 )
281 .await?;
282
283 #[cfg(feature = "e2e-encryption")]
286 if let Some(olm_machine) = e2ee.olm_machine {
287 olm_machine.store().clear_room_pending_key_bundle(room_info.room_id()).await?
288 }
289
290 context.state_changes.add_room(room_info);
291
292 Ok(knocked_room)
293}
294
295impl State {
296 fn from_sync_v2(state: RumaState) -> Self {
299 match state {
300 RumaState::Before(state) => Self::Before(state.events),
301 RumaState::After(state) => Self::After(state.events),
302 state => {
304 error!("Unsupported State variant received for joined room: {state:?}");
305 Self::default()
306 }
307 }
308 }
309}