use std::{collections::BTreeMap, fmt};
use matrix_sdk_common::{debug::DebugRawEvent, deserialized_responses::SyncTimelineEvent};
use ruma::{
api::client::sync::sync_events::{
v3::{InvitedRoom as InvitedRoomUpdate, KnockedRoom as KnockedRoomUpdate},
UnreadNotificationsCount as RumaUnreadNotificationsCount,
},
events::{
presence::PresenceEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
AnySyncEphemeralRoomEvent, AnySyncStateEvent, AnyToDeviceEvent,
},
push::Action,
serde::Raw,
OwnedEventId, OwnedRoomId,
};
use serde::{Deserialize, Serialize};
use crate::{
debug::{DebugInvitedRoom, DebugKnockedRoom, DebugListOfRawEvents, DebugListOfRawEventsNoId},
deserialized_responses::{AmbiguityChange, RawAnySyncOrStrippedTimelineEvent},
store::Store,
};
#[derive(Clone, Default)]
pub struct SyncResponse {
pub rooms: RoomUpdates,
pub presence: Vec<Raw<PresenceEvent>>,
pub account_data: Vec<Raw<AnyGlobalAccountDataEvent>>,
pub to_device: Vec<Raw<AnyToDeviceEvent>>,
pub notifications: BTreeMap<OwnedRoomId, Vec<Notification>>,
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for SyncResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SyncResponse")
.field("rooms", &self.rooms)
.field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
.field("to_device", &DebugListOfRawEventsNoId(&self.to_device))
.field("notifications", &self.notifications)
.finish_non_exhaustive()
}
}
#[derive(Clone, Default)]
pub struct RoomUpdates {
pub leave: BTreeMap<OwnedRoomId, LeftRoomUpdate>,
pub join: BTreeMap<OwnedRoomId, JoinedRoomUpdate>,
pub invite: BTreeMap<OwnedRoomId, InvitedRoomUpdate>,
pub knocked: BTreeMap<OwnedRoomId, KnockedRoomUpdate>,
}
impl RoomUpdates {
pub(crate) async fn update_in_memory_caches(&self, store: &Store) {
for room in self
.leave
.keys()
.chain(self.join.keys())
.chain(self.invite.keys())
.chain(self.knocked.keys())
.filter_map(|room_id| store.room(room_id))
{
let _ = room.compute_display_name().await;
}
}
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for RoomUpdates {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rooms")
.field("leave", &self.leave)
.field("join", &self.join)
.field("invite", &DebugInvitedRoomUpdates(&self.invite))
.field("knocked", &DebugKnockedRoomUpdates(&self.knocked))
.finish()
}
}
#[derive(Clone, Default)]
pub struct JoinedRoomUpdate {
pub unread_notifications: UnreadNotificationsCount,
pub timeline: Timeline,
pub state: Vec<Raw<AnySyncStateEvent>>,
pub account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
pub ephemeral: Vec<Raw<AnySyncEphemeralRoomEvent>>,
pub ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for JoinedRoomUpdate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("JoinedRoom")
.field("unread_notifications", &self.unread_notifications)
.field("timeline", &self.timeline)
.field("state", &DebugListOfRawEvents(&self.state))
.field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
.field("ephemeral", &self.ephemeral)
.field("ambiguity_changes", &self.ambiguity_changes)
.finish()
}
}
impl JoinedRoomUpdate {
pub(crate) fn new(
timeline: Timeline,
state: Vec<Raw<AnySyncStateEvent>>,
account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
ephemeral: Vec<Raw<AnySyncEphemeralRoomEvent>>,
unread_notifications: UnreadNotificationsCount,
ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
) -> Self {
Self { unread_notifications, timeline, state, account_data, ephemeral, ambiguity_changes }
}
}
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
pub struct UnreadNotificationsCount {
pub highlight_count: u64,
pub notification_count: u64,
}
impl From<RumaUnreadNotificationsCount> for UnreadNotificationsCount {
fn from(notifications: RumaUnreadNotificationsCount) -> Self {
Self {
highlight_count: notifications.highlight_count.map(|c| c.into()).unwrap_or(0),
notification_count: notifications.notification_count.map(|c| c.into()).unwrap_or(0),
}
}
}
#[derive(Clone, Default)]
pub struct LeftRoomUpdate {
pub timeline: Timeline,
pub state: Vec<Raw<AnySyncStateEvent>>,
pub account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
pub ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
}
impl LeftRoomUpdate {
pub(crate) fn new(
timeline: Timeline,
state: Vec<Raw<AnySyncStateEvent>>,
account_data: Vec<Raw<AnyRoomAccountDataEvent>>,
ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
) -> Self {
Self { timeline, state, account_data, ambiguity_changes }
}
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for LeftRoomUpdate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("JoinedRoom")
.field("timeline", &self.timeline)
.field("state", &DebugListOfRawEvents(&self.state))
.field("account_data", &DebugListOfRawEventsNoId(&self.account_data))
.field("ambiguity_changes", &self.ambiguity_changes)
.finish()
}
}
#[derive(Clone, Debug, Default)]
pub struct Timeline {
pub limited: bool,
pub prev_batch: Option<String>,
pub events: Vec<SyncTimelineEvent>,
}
impl Timeline {
pub(crate) fn new(limited: bool, prev_batch: Option<String>) -> Self {
Self { limited, prev_batch, ..Default::default() }
}
}
struct DebugInvitedRoomUpdates<'a>(&'a BTreeMap<OwnedRoomId, InvitedRoomUpdate>);
#[cfg(not(tarpaulin_include))]
impl<'a> fmt::Debug for DebugInvitedRoomUpdates<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.0.iter().map(|(k, v)| (k, DebugInvitedRoom(v)))).finish()
}
}
struct DebugKnockedRoomUpdates<'a>(&'a BTreeMap<OwnedRoomId, KnockedRoomUpdate>);
#[cfg(not(tarpaulin_include))]
impl<'a> fmt::Debug for DebugKnockedRoomUpdates<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.0.iter().map(|(k, v)| (k, DebugKnockedRoom(v)))).finish()
}
}
#[derive(Clone)]
pub struct Notification {
pub actions: Vec<Action>,
pub event: RawAnySyncOrStrippedTimelineEvent,
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for Notification {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let event_debug = match &self.event {
RawAnySyncOrStrippedTimelineEvent::Sync(ev) => DebugRawEvent(ev),
RawAnySyncOrStrippedTimelineEvent::Stripped(ev) => DebugRawEvent(ev.cast_ref()),
};
f.debug_struct("Notification")
.field("actions", &self.actions)
.field("event", &event_debug)
.finish()
}
}