1use std::{
18 collections::{BTreeMap, HashSet},
19 sync::Arc,
20};
21
22use matrix_sdk_common::deserialized_responses::TimelineEvent;
23use ruma::{
24 OwnedRoomId, OwnedUserId, RoomId,
25 events::{
26 EmptyStateKey, RedactContent, StateEventContent, StateEventType,
27 direct::OwnedDirectUserIdentifier,
28 room::{
29 avatar::RoomAvatarEventContent,
30 canonical_alias::RoomCanonicalAliasEventContent,
31 create::RoomCreateEventContent,
32 encryption::RoomEncryptionEventContent,
33 guest_access::RoomGuestAccessEventContent,
34 history_visibility::RoomHistoryVisibilityEventContent,
35 join_rules::RoomJoinRulesEventContent,
36 name::{RedactedRoomNameEventContent, RoomNameEventContent},
37 tombstone::RoomTombstoneEventContent,
38 topic::RoomTopicEventContent,
39 },
40 },
41 room_version_rules::RedactionRules,
42};
43use serde::{Deserialize, Serialize};
44
45use crate::{
46 MinimalStateEvent, OriginalMinimalStateEvent, RoomInfo, RoomState,
47 deserialized_responses::SyncOrStrippedState,
48 latest_event::{LatestEvent, LatestEventValue},
49 room::{BaseRoomInfo, RoomSummary, SyncInfo},
50 sync::UnreadNotificationsCount,
51};
52
53#[derive(Clone, Debug, Serialize, Deserialize)]
66pub struct RoomInfoV1 {
67 room_id: OwnedRoomId,
68 room_type: RoomState,
69 notification_counts: UnreadNotificationsCount,
70 summary: RoomSummary,
71 members_synced: bool,
72 last_prev_batch: Option<String>,
73 #[serde(default = "sync_info_complete")] sync_info: SyncInfo,
75 #[serde(default = "encryption_state_default")] encryption_state_synced: bool,
77 latest_event: Option<TimelineEvent>,
78 base_info: BaseRoomInfoV1,
79}
80
81impl RoomInfoV1 {
82 pub fn room_id(&self) -> &RoomId {
84 &self.room_id
85 }
86
87 pub fn state(&self) -> RoomState {
89 self.room_type
90 }
91
92 pub fn migrate(self, create: Option<&SyncOrStrippedState<RoomCreateEventContent>>) -> RoomInfo {
95 let RoomInfoV1 {
96 room_id,
97 room_type,
98 notification_counts,
99 summary,
100 members_synced,
101 last_prev_batch,
102 sync_info,
103 encryption_state_synced,
104 latest_event,
105 base_info,
106 } = self;
107
108 RoomInfo {
109 data_format_version: 0,
110 room_id,
111 room_state: room_type,
112 notification_counts,
113 summary,
114 members_synced,
115 last_prev_batch,
116 sync_info,
117 encryption_state_synced,
118 latest_event: latest_event.map(|ev| Box::new(LatestEvent::new(ev))),
119 new_latest_event: LatestEventValue::None,
120 read_receipts: Default::default(),
121 base_info: base_info.migrate(create),
122 warned_about_unknown_room_version_rules: Arc::new(false.into()),
123 cached_display_name: None,
124 cached_user_defined_notification_mode: None,
125 recency_stamp: None,
126 invite_acceptance_details: None,
127 }
128 }
129}
130
131fn sync_info_complete() -> SyncInfo {
136 SyncInfo::FullySynced
137}
138
139fn encryption_state_default() -> bool {
144 true
145}
146
147#[derive(Clone, Debug, Serialize, Deserialize)]
149struct BaseRoomInfoV1 {
150 avatar: Option<MinimalStateEvent<RoomAvatarEventContent>>,
151 canonical_alias: Option<MinimalStateEvent<RoomCanonicalAliasEventContent>>,
152 dm_targets: HashSet<OwnedUserId>,
153 encryption: Option<RoomEncryptionEventContent>,
154 guest_access: Option<MinimalStateEvent<RoomGuestAccessEventContent>>,
155 history_visibility: Option<MinimalStateEvent<RoomHistoryVisibilityEventContent>>,
156 join_rules: Option<MinimalStateEvent<RoomJoinRulesEventContent>>,
157 max_power_level: i64,
158 name: Option<MinimalStateEvent<RoomNameEventContentV1>>,
159 tombstone: Option<MinimalStateEvent<RoomTombstoneEventContent>>,
160 topic: Option<MinimalStateEvent<RoomTopicEventContent>>,
161}
162
163impl BaseRoomInfoV1 {
164 fn migrate(
166 self,
167 create: Option<&SyncOrStrippedState<RoomCreateEventContent>>,
168 ) -> Box<BaseRoomInfo> {
169 let BaseRoomInfoV1 {
170 avatar,
171 canonical_alias,
172 dm_targets,
173 encryption,
174 guest_access,
175 history_visibility,
176 join_rules,
177 max_power_level,
178 name,
179 tombstone,
180 topic,
181 } = self;
182
183 let create = create.map(|ev| match ev {
184 SyncOrStrippedState::Sync(e) => e.into(),
185 SyncOrStrippedState::Stripped(e) => e.into(),
186 });
187 let name = name.map(|name| match name {
188 MinimalStateEvent::Original(ev) => {
189 MinimalStateEvent::Original(OriginalMinimalStateEvent {
190 content: ev.content.into(),
191 event_id: ev.event_id,
192 })
193 }
194 MinimalStateEvent::Redacted(ev) => MinimalStateEvent::Redacted(ev),
195 });
196
197 let mut converted_dm_targets = HashSet::new();
198 for dm_target in dm_targets {
199 converted_dm_targets.insert(OwnedDirectUserIdentifier::from(dm_target));
200 }
201
202 Box::new(BaseRoomInfo {
203 avatar,
204 beacons: BTreeMap::new(),
205 canonical_alias,
206 create,
207 dm_targets: converted_dm_targets,
208 encryption,
209 guest_access,
210 history_visibility,
211 join_rules,
212 max_power_level,
213 name,
214 tombstone,
215 topic,
216 ..Default::default()
217 })
218 }
219}
220
221#[derive(Clone, Debug, Serialize, Deserialize)]
223struct RoomNameEventContentV1 {
224 name: Option<String>,
225}
226
227impl StateEventContent for RoomNameEventContentV1 {
228 type StateKey = EmptyStateKey;
229
230 fn event_type(&self) -> StateEventType {
231 StateEventType::RoomName
232 }
233}
234
235impl RedactContent for RoomNameEventContentV1 {
236 type Redacted = RedactedRoomNameEventContent;
237
238 fn redact(self, _rules: &RedactionRules) -> Self::Redacted {
239 RedactedRoomNameEventContent::new()
240 }
241}
242
243impl From<RoomNameEventContentV1> for RoomNameEventContent {
244 fn from(value: RoomNameEventContentV1) -> Self {
245 RoomNameEventContent::new(value.name.unwrap_or_default())
246 }
247}