1use std::{collections::BTreeMap, fmt};
18
19use matrix_sdk_common::{debug::DebugRawEvent, deserialized_responses::TimelineEvent};
20pub use ruma::api::client::sync::sync_events::v3::{
21 InvitedRoom as InvitedRoomUpdate, KnockedRoom as KnockedRoomUpdate,
22};
23use ruma::{
24 api::client::sync::sync_events::UnreadNotificationsCount as RumaUnreadNotificationsCount,
25 events::{
26 presence::PresenceEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
27 AnySyncEphemeralRoomEvent, AnySyncStateEvent, AnyToDeviceEvent,
28 },
29 push::Action,
30 serde::Raw,
31 OwnedEventId, OwnedRoomId,
32};
33use serde::{Deserialize, Serialize};
34
35use crate::{
36 debug::{DebugInvitedRoom, DebugKnockedRoom, DebugListOfRawEvents, DebugListOfRawEventsNoId},
37 deserialized_responses::{AmbiguityChange, RawAnySyncOrStrippedTimelineEvent},
38};
39
40#[derive(Clone, Default)]
45pub struct SyncResponse {
46 pub rooms: RoomUpdates,
48 pub presence: Vec<Raw<PresenceEvent>>,
50 pub account_data: Vec<Raw<AnyGlobalAccountDataEvent>>,
52 pub to_device: Vec<Raw<AnyToDeviceEvent>>,
54 pub notifications: BTreeMap<OwnedRoomId, Vec<Notification>>,
56}
57
58#[cfg(not(tarpaulin_include))]
59impl fmt::Debug for SyncResponse {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.debug_struct("SyncResponse")
62 .field("rooms", &self.rooms)
63 .field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
64 .field("to_device", &DebugListOfRawEventsNoId(&self.to_device))
65 .field("notifications", &self.notifications)
66 .finish_non_exhaustive()
67 }
68}
69
70#[derive(Clone, Default)]
72pub struct RoomUpdates {
73 pub left: BTreeMap<OwnedRoomId, LeftRoomUpdate>,
75 pub joined: BTreeMap<OwnedRoomId, JoinedRoomUpdate>,
77 pub invited: BTreeMap<OwnedRoomId, InvitedRoomUpdate>,
79 pub knocked: BTreeMap<OwnedRoomId, KnockedRoomUpdate>,
81}
82
83#[cfg(not(tarpaulin_include))]
84impl fmt::Debug for RoomUpdates {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.debug_struct("RoomUpdates")
87 .field("leave", &self.left)
88 .field("join", &self.joined)
89 .field("invite", &DebugInvitedRoomUpdates(&self.invited))
90 .field("knocked", &DebugKnockedRoomUpdates(&self.knocked))
91 .finish()
92 }
93}
94
95#[derive(Clone, Default)]
97pub struct JoinedRoomUpdate {
98 pub unread_notifications: UnreadNotificationsCount,
100 pub timeline: Timeline,
102 pub state: Vec<Raw<AnySyncStateEvent>>,
107 pub account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
109 pub ephemeral: Vec<Raw<AnySyncEphemeralRoomEvent>>,
112 pub ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
117}
118
119#[cfg(not(tarpaulin_include))]
120impl fmt::Debug for JoinedRoomUpdate {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("JoinedRoomUpdate")
123 .field("unread_notifications", &self.unread_notifications)
124 .field("timeline", &self.timeline)
125 .field("state", &DebugListOfRawEvents(&self.state))
126 .field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
127 .field("ephemeral", &self.ephemeral)
128 .field("ambiguity_changes", &self.ambiguity_changes)
129 .finish()
130 }
131}
132
133impl JoinedRoomUpdate {
134 pub(crate) fn new(
135 timeline: Timeline,
136 state: Vec<Raw<AnySyncStateEvent>>,
137 account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
138 ephemeral: Vec<Raw<AnySyncEphemeralRoomEvent>>,
139 unread_notifications: UnreadNotificationsCount,
140 ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
141 ) -> Self {
142 Self { unread_notifications, timeline, state, account_data, ephemeral, ambiguity_changes }
143 }
144}
145
146#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
148pub struct UnreadNotificationsCount {
149 pub highlight_count: u64,
152 pub notification_count: u64,
154}
155
156impl From<RumaUnreadNotificationsCount> for UnreadNotificationsCount {
157 fn from(notifications: RumaUnreadNotificationsCount) -> Self {
158 Self {
159 highlight_count: notifications.highlight_count.map(|c| c.into()).unwrap_or(0),
160 notification_count: notifications.notification_count.map(|c| c.into()).unwrap_or(0),
161 }
162 }
163}
164
165#[derive(Clone, Default)]
167pub struct LeftRoomUpdate {
168 pub timeline: Timeline,
171 pub state: Vec<Raw<AnySyncStateEvent>>,
176 pub account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
178 pub ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
183}
184
185impl LeftRoomUpdate {
186 pub(crate) fn new(
187 timeline: Timeline,
188 state: Vec<Raw<AnySyncStateEvent>>,
189 account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
190 ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
191 ) -> Self {
192 Self { timeline, state, account_data, ambiguity_changes }
193 }
194}
195
196#[cfg(not(tarpaulin_include))]
197impl fmt::Debug for LeftRoomUpdate {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 f.debug_struct("LeftRoomUpdate")
200 .field("timeline", &self.timeline)
201 .field("state", &DebugListOfRawEvents(&self.state))
202 .field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
203 .field("ambiguity_changes", &self.ambiguity_changes)
204 .finish()
205 }
206}
207
208#[derive(Clone, Debug, Default)]
210pub struct Timeline {
211 pub limited: bool,
214
215 pub prev_batch: Option<String>,
218
219 pub events: Vec<TimelineEvent>,
221}
222
223impl Timeline {
224 pub(crate) fn new(limited: bool, prev_batch: Option<String>) -> Self {
225 Self { limited, prev_batch, ..Default::default() }
226 }
227}
228
229struct DebugInvitedRoomUpdates<'a>(&'a BTreeMap<OwnedRoomId, InvitedRoomUpdate>);
230
231#[cfg(not(tarpaulin_include))]
232impl fmt::Debug for DebugInvitedRoomUpdates<'_> {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 f.debug_map().entries(self.0.iter().map(|(k, v)| (k, DebugInvitedRoom(v)))).finish()
235 }
236}
237
238struct DebugKnockedRoomUpdates<'a>(&'a BTreeMap<OwnedRoomId, KnockedRoomUpdate>);
239
240#[cfg(not(tarpaulin_include))]
241impl fmt::Debug for DebugKnockedRoomUpdates<'_> {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 f.debug_map().entries(self.0.iter().map(|(k, v)| (k, DebugKnockedRoom(v)))).finish()
244 }
245}
246
247#[derive(Clone)]
249pub struct Notification {
250 pub actions: Vec<Action>,
252
253 pub event: RawAnySyncOrStrippedTimelineEvent,
255}
256
257#[cfg(not(tarpaulin_include))]
258impl fmt::Debug for Notification {
259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 let event_debug = match &self.event {
261 RawAnySyncOrStrippedTimelineEvent::Sync(ev) => DebugRawEvent(ev),
262 RawAnySyncOrStrippedTimelineEvent::Stripped(ev) => DebugRawEvent(ev.cast_ref()),
263 };
264
265 f.debug_struct("Notification")
266 .field("actions", &self.actions)
267 .field("event", &event_debug)
268 .finish()
269 }
270}