matrix_sdk_base/response_processors/
changes.rs1use eyeball::SharedObservable;
16use matrix_sdk_common::timer;
17use ruma::{
18 events::{GlobalAccountDataEventType, ignored_user_list::IgnoredUserListEvent},
19 serde::Raw,
20};
21use tracing::{error, instrument, trace};
22
23use super::Context;
24use crate::{
25 Result,
26 store::{BaseStateStore, StateStoreExt as _},
27};
28
29#[instrument(skip_all)]
32pub async fn save_only(context: Context, state_store: &BaseStateStore) -> Result<()> {
33 let _timer = timer!(tracing::Level::TRACE, "_method");
34
35 save_changes(&context, state_store, None).await?;
36 broadcast_room_info_notable_updates(&context, state_store);
37
38 Ok(())
39}
40
41#[instrument(skip_all)]
44pub async fn save_and_apply(
45 context: Context,
46 state_store: &BaseStateStore,
47 ignore_user_list_changes: &SharedObservable<Vec<String>>,
48 sync_token: Option<String>,
49) -> Result<()> {
50 let _timer = timer!(tracing::Level::TRACE, "_method");
51
52 trace!("ready to submit changes to store");
53
54 let previous_ignored_user_list =
55 state_store.get_account_data_event_static().await.ok().flatten();
56
57 save_changes(&context, state_store, sync_token).await?;
58 apply_changes(&context, ignore_user_list_changes, previous_ignored_user_list);
59 broadcast_room_info_notable_updates(&context, state_store);
60
61 trace!("applied changes");
62
63 Ok(())
64}
65
66async fn save_changes(
67 context: &Context,
68 state_store: &BaseStateStore,
69 sync_token: Option<String>,
70) -> Result<()> {
71 state_store.save_changes(&context.state_changes).await?;
72
73 if let Some(sync_token) = sync_token {
74 *state_store.sync_token.write().await = Some(sync_token);
75 }
76
77 Ok(())
78}
79
80fn apply_changes(
81 context: &Context,
82 ignore_user_list_changes: &SharedObservable<Vec<String>>,
83 previous_ignored_user_list: Option<Raw<IgnoredUserListEvent>>,
84) {
85 if let Some(event) =
86 context.state_changes.account_data.get(&GlobalAccountDataEventType::IgnoredUserList)
87 {
88 match event.deserialize_as_unchecked::<IgnoredUserListEvent>() {
89 Ok(event) => {
90 let user_ids: Vec<String> =
91 event.content.ignored_users.keys().map(|id| id.to_string()).collect();
92
93 if let Some(prev_user_ids) =
97 previous_ignored_user_list.and_then(|raw| raw.deserialize().ok()).map(|event| {
98 event
99 .content
100 .ignored_users
101 .keys()
102 .map(|id| id.to_string())
103 .collect::<Vec<_>>()
104 })
105 {
106 if user_ids != prev_user_ids {
107 ignore_user_list_changes.set(user_ids);
108 }
109 } else {
110 ignore_user_list_changes.set(user_ids);
111 }
112 }
113
114 Err(error) => {
115 error!("Failed to deserialize ignored user list event: {error}")
116 }
117 }
118 }
119}
120
121fn broadcast_room_info_notable_updates(context: &Context, state_store: &BaseStateStore) {
122 for (room_id, room_info) in &context.state_changes.room_infos {
123 if let Some(room) = state_store.room(room_id) {
124 let room_info_notable_update_reasons =
125 context.room_info_notable_updates.get(room_id).copied().unwrap_or_default();
126
127 room.set_room_info(room_info.clone(), room_info_notable_update_reasons)
128 }
129 }
130}