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