matrix_sdk_base/room/
knock.rs1use std::collections::BTreeMap;
16
17use eyeball::{AsyncLock, ObservableWriteGuard};
18use ruma::{
19 OwnedEventId, OwnedUserId,
20 events::{
21 StateEventType, SyncStateEvent,
22 room::member::{MembershipState, RoomMemberEventContent},
23 },
24};
25use tracing::warn;
26
27use super::Room;
28use crate::{
29 StateStore, StateStoreDataKey, StateStoreDataValue, StoreError,
30 deserialized_responses::{MemberEvent, RawMemberEvent, SyncOrStrippedState},
31 store::{Result as StoreResult, StateStoreExt},
32};
33
34impl Room {
35 pub async fn mark_knock_requests_as_seen(&self, user_ids: &[OwnedUserId]) -> StoreResult<()> {
38 let raw_user_ids: Vec<&str> = user_ids.iter().map(|id| id.as_str()).collect();
39 let member_raw_events = self
40 .store
41 .get_state_events_for_keys(self.room_id(), StateEventType::RoomMember, &raw_user_ids)
42 .await?;
43 let mut event_to_user_ids = Vec::with_capacity(member_raw_events.len());
44
45 for raw_event in member_raw_events {
48 let event = raw_event.cast::<RoomMemberEventContent>().deserialize()?;
49 match event {
50 SyncOrStrippedState::Sync(SyncStateEvent::Original(event)) => {
51 if event.content.membership == MembershipState::Knock {
52 event_to_user_ids.push((event.event_id, event.state_key))
53 } else {
54 warn!(
55 "Could not mark knock event as seen: event {} for user {} \
56 is not in Knock membership state.",
57 event.event_id, event.state_key
58 );
59 }
60 }
61 _ => warn!(
62 "Could not mark knock event as seen: event for user {} is not valid.",
63 event.state_key()
64 ),
65 }
66 }
67
68 let current_seen_events_guard = self.get_write_guarded_current_knock_request_ids().await?;
69 let mut current_seen_events = current_seen_events_guard.clone().unwrap_or_default();
70
71 current_seen_events.extend(event_to_user_ids);
72
73 self.update_seen_knock_request_ids(current_seen_events_guard, current_seen_events).await?;
74
75 Ok(())
76 }
77
78 pub async fn remove_outdated_seen_knock_requests_ids(&self) -> StoreResult<()> {
81 let current_seen_events_guard = self.get_write_guarded_current_knock_request_ids().await?;
82 let mut current_seen_events = current_seen_events_guard.clone().unwrap_or_default();
83
84 let keys: Vec<OwnedUserId> = current_seen_events.values().map(|id| id.to_owned()).collect();
86 let raw_member_events: Vec<RawMemberEvent> =
87 self.store.get_state_events_for_keys_static(self.room_id(), &keys).await?;
88 let member_events = raw_member_events
89 .into_iter()
90 .map(|raw| raw.deserialize())
91 .collect::<Result<Vec<MemberEvent>, _>>()?;
92
93 let mut ids_to_remove = Vec::new();
94
95 for (event_id, user_id) in current_seen_events.iter() {
96 let matching_member = member_events.iter().find(|event| event.user_id() == user_id);
99
100 if let Some(member) = matching_member {
101 let member_event_id = member.event_id();
102 if *member.membership() != MembershipState::Knock
105 || member_event_id.is_some_and(|id| id != event_id)
106 {
107 ids_to_remove.push(event_id.to_owned());
108 }
109 } else {
110 ids_to_remove.push(event_id.to_owned());
111 }
112 }
113
114 if ids_to_remove.is_empty() {
116 return Ok(());
117 }
118
119 for event_id in ids_to_remove {
120 current_seen_events.remove(&event_id);
121 }
122
123 self.update_seen_knock_request_ids(current_seen_events_guard, current_seen_events).await?;
124
125 Ok(())
126 }
127
128 pub async fn get_seen_knock_request_ids(
130 &self,
131 ) -> Result<BTreeMap<OwnedEventId, OwnedUserId>, StoreError> {
132 Ok(self.get_write_guarded_current_knock_request_ids().await?.clone().unwrap_or_default())
133 }
134
135 async fn get_write_guarded_current_knock_request_ids(
136 &self,
137 ) -> StoreResult<ObservableWriteGuard<'_, Option<BTreeMap<OwnedEventId, OwnedUserId>>, AsyncLock>>
138 {
139 let mut guard = self.seen_knock_request_ids_map.write().await;
140 if guard.is_none() {
142 let updated_seen_ids = self
145 .store
146 .get_kv_data(StateStoreDataKey::SeenKnockRequests(self.room_id()))
147 .await?
148 .and_then(|v| v.into_seen_knock_requests())
149 .unwrap_or_default();
150
151 ObservableWriteGuard::set(&mut guard, Some(updated_seen_ids));
152 }
153 Ok(guard)
154 }
155
156 async fn update_seen_knock_request_ids(
157 &self,
158 mut guard: ObservableWriteGuard<'_, Option<BTreeMap<OwnedEventId, OwnedUserId>>, AsyncLock>,
159 new_value: BTreeMap<OwnedEventId, OwnedUserId>,
160 ) -> StoreResult<()> {
161 ObservableWriteGuard::set(&mut guard, Some(new_value.clone()));
163
164 self.store
166 .set_kv_data(
167 StateStoreDataKey::SeenKnockRequests(self.room_id()),
168 StateStoreDataValue::SeenKnockRequests(new_value),
169 )
170 .await?;
171
172 Ok(())
173 }
174}