use std::{collections::BTreeMap, time::Duration};
use salvo::oapi::{ToParameters, ToSchema};
use serde::{Deserialize, Serialize};
use crate::events::{
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent,
AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, presence::PresenceEvent,
};
use crate::{DeviceKeyAlgorithm, OwnedEventId, OwnedRoomId, presence::PresenceState, serde::RawJson};
use super::UnreadNotificationsCount;
use crate::client::filter::FilterDefinition;
use crate::device::DeviceLists;
#[derive(ToParameters, Deserialize, Debug)]
pub struct SyncEventsReqArgs {
#[salvo(parameter(parameter_in = Query))]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>,
#[salvo(parameter(parameter_in = Query))]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub since: Option<String>,
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub full_state: bool,
#[salvo(parameter(parameter_in = Query))]
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub set_presence: PresenceState,
#[salvo(parameter(parameter_in = Query))]
#[serde(
with = "crate::serde::duration::opt_ms",
default,
skip_serializing_if = "Option::is_none"
)]
pub timeout: Option<Duration>,
}
#[derive(ToSchema, Serialize, Clone, Debug)]
pub struct SyncEventsResBody {
pub next_batch: String,
#[serde(default, skip_serializing_if = "Rooms::is_empty")]
pub rooms: Rooms,
#[serde(default, skip_serializing_if = "Presence::is_empty")]
pub presence: Presence,
#[serde(default, skip_serializing_if = "GlobalAccountData::is_empty")]
pub account_data: GlobalAccountData,
#[serde(default, skip_serializing_if = "ToDevice::is_empty")]
pub to_device: ToDevice,
#[serde(default, skip_serializing_if = "DeviceLists::is_empty")]
pub device_lists: DeviceLists,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub device_one_time_keys_count: BTreeMap<DeviceKeyAlgorithm, u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub device_unused_fallback_key_types: Option<Vec<DeviceKeyAlgorithm>>,
}
impl SyncEventsResBody {
pub fn new(next_batch: String) -> Self {
Self {
next_batch,
rooms: Default::default(),
presence: Default::default(),
account_data: Default::default(),
to_device: Default::default(),
device_lists: Default::default(),
device_one_time_keys_count: BTreeMap::new(),
device_unused_fallback_key_types: None,
}
}
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
#[allow(clippy::large_enum_variant)]
#[serde(untagged)]
pub enum Filter {
#[serde(with = "crate::serde::json_string")]
FilterDefinition(FilterDefinition),
FilterId(String),
}
impl From<FilterDefinition> for Filter {
fn from(def: FilterDefinition) -> Self {
Self::FilterDefinition(def)
}
}
impl From<String> for Filter {
fn from(id: String) -> Self {
Self::FilterId(id)
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct Rooms {
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub leave: BTreeMap<OwnedRoomId, LeftRoom>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub join: BTreeMap<OwnedRoomId, JoinedRoom>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub invite: BTreeMap<OwnedRoomId, InvitedRoom>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub knock: BTreeMap<OwnedRoomId, KnockedRoom>,
}
impl Rooms {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.leave.is_empty() && self.join.is_empty() && self.invite.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct LeftRoom {
#[serde(default)]
pub timeline: Timeline,
#[serde(default, skip_serializing_if = "State::is_empty")]
pub state: State,
#[serde(default, skip_serializing_if = "RoomAccountData::is_empty")]
pub account_data: RoomAccountData,
}
impl LeftRoom {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.timeline.is_empty() && self.state.is_empty() && self.account_data.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct JoinedRoom {
#[serde(default, skip_serializing_if = "RoomSummary::is_empty")]
pub summary: RoomSummary,
#[serde(default, skip_serializing_if = "UnreadNotificationsCount::is_empty")]
pub unread_notifications: UnreadNotificationsCount,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub unread_thread_notifications: BTreeMap<OwnedEventId, UnreadNotificationsCount>,
#[serde(default, skip_serializing_if = "Timeline::is_empty")]
pub timeline: Timeline,
#[serde(default, skip_serializing_if = "State::is_empty")]
pub state: State,
#[serde(default, skip_serializing_if = "RoomAccountData::is_empty")]
pub account_data: RoomAccountData,
#[serde(default, skip_serializing_if = "Ephemeral::is_empty")]
pub ephemeral: Ephemeral,
#[serde(rename = "org.matrix.msc2654.unread_count", skip_serializing_if = "Option::is_none")]
pub unread_count: Option<u64>,
}
impl JoinedRoom {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
let is_empty = self.summary.is_empty()
&& self.unread_notifications.is_empty()
&& self.unread_thread_notifications.is_empty()
&& self.timeline.is_empty()
&& self.state.is_empty()
&& self.account_data.is_empty()
&& self.ephemeral.is_empty();
#[cfg(not(feature = "unstable-msc2654"))]
return is_empty;
#[cfg(feature = "unstable-msc2654")]
return is_empty && self.unread_count.is_none();
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct KnockedRoom {
pub knock_state: KnockState,
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct KnockState {
pub events: Vec<RawJson<AnyStrippedStateEvent>>,
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct Timeline {
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub limited: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub prev_batch: Option<String>,
#[serde(default)]
pub events: Vec<RawJson<AnySyncTimelineEvent>>,
}
impl Timeline {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct State {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnySyncStateEvent>>,
}
impl State {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
pub fn with_events(events: Vec<RawJson<AnySyncStateEvent>>) -> Self {
Self {
events,
..Default::default()
}
}
}
impl From<Vec<RawJson<AnySyncStateEvent>>> for State {
fn from(events: Vec<RawJson<AnySyncStateEvent>>) -> Self {
Self::with_events(events)
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct GlobalAccountData {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnyGlobalAccountDataEvent>>,
}
impl GlobalAccountData {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct RoomAccountData {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnyRoomAccountDataEvent>>,
}
impl RoomAccountData {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct Ephemeral {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnySyncEphemeralRoomEvent>>,
}
impl Ephemeral {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct RoomSummary {
#[serde(rename = "m.heroes", default, skip_serializing_if = "Vec::is_empty")]
pub heroes: Vec<String>,
#[serde(default, rename = "m.joined_member_count", skip_serializing_if = "Option::is_none")]
pub joined_member_count: Option<u64>,
#[serde(default, rename = "m.invited_member_count", skip_serializing_if = "Option::is_none")]
pub invited_member_count: Option<u64>,
}
impl RoomSummary {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.heroes.is_empty() && self.joined_member_count.is_none() && self.invited_member_count.is_none()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct InvitedRoom {
#[serde(default, skip_serializing_if = "InviteState::is_empty")]
pub invite_state: InviteState,
}
impl InvitedRoom {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.invite_state.is_empty()
}
}
impl From<InviteState> for InvitedRoom {
fn from(invite_state: InviteState) -> Self {
InvitedRoom {
invite_state,
..Default::default()
}
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct InviteState {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnyStrippedStateEvent>>,
}
impl InviteState {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
impl From<Vec<RawJson<AnyStrippedStateEvent>>> for InviteState {
fn from(events: Vec<RawJson<AnyStrippedStateEvent>>) -> Self {
Self {
events,
..Default::default()
}
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct Presence {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<PresenceEvent>>,
}
impl Presence {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(ToSchema, Clone, Debug, Default, Deserialize, Serialize)]
pub struct ToDevice {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<RawJson<AnyToDeviceEvent>>,
}
impl ToDevice {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}