use std::{collections::BTreeMap, time::Duration};
use super::{DeviceLists, UnreadNotificationsCount};
use js_int::UInt;
use ruma_common::{
api::{request, response, Metadata},
events::{
AnyEphemeralRoomEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent,
TimelineEventType,
},
metadata,
serde::{duration::opt_ms, Raw},
DeviceKeyAlgorithm, OwnedRoomId,
};
use serde::{Deserialize, Serialize};
const METADATA: Metadata = metadata! {
method: POST,
rate_limited: false,
authentication: AccessToken,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc3575/sync",
}
};
#[request(error = crate::Error)]
#[derive(Default)]
pub struct Request {
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub pos: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delta_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub txn_id: Option<String>,
#[serde(with = "opt_ms", default, skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub timeout: Option<Duration>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: BTreeMap<String, SyncRequestList>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub room_subscriptions: BTreeMap<OwnedRoomId, RoomSubscription>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub unsubscribe_rooms: Vec<OwnedRoomId>,
#[serde(default, skip_serializing_if = "ExtensionsConfig::is_empty")]
pub extensions: ExtensionsConfig,
}
#[response(error = crate::Error)]
pub struct Response {
#[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
pub initial: bool,
pub pos: String,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: BTreeMap<String, SyncList>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, SlidingSyncRoom>,
#[serde(default, skip_serializing_if = "Extensions::is_empty")]
pub extensions: Extensions,
pub delta_token: Option<String>,
}
impl Request {
pub fn new() -> Self {
Default::default()
}
}
impl Response {
pub fn new(pos: String) -> Self {
Self {
initial: Default::default(),
pos,
delta_token: Default::default(),
lists: Default::default(),
rooms: Default::default(),
extensions: Default::default(),
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SyncRequestListFilters {
#[serde(skip_serializing_if = "Option::is_none")]
pub is_dm: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub spaces: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_encrypted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_invite: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_tombstoned: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub room_types: Vec<String>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub not_room_types: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub room_name_like: Option<String>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub tags: Vec<String>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub not_tags: Vec<String>,
#[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")]
pub extensions: BTreeMap<String, serde_json::Value>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SyncRequestList {
#[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
pub slow_get_all_rooms: bool,
pub ranges: Vec<(UInt, UInt)>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sort: Vec<String>,
#[serde(flatten)]
pub room_details: RoomDetailsConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_old_rooms: Option<IncludeOldRooms>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<SyncRequestListFilters>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomDetailsConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(TimelineEventType, String)>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeline_limit: Option<UInt>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct IncludeOldRooms {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(TimelineEventType, String)>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeline_limit: Option<UInt>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomSubscription {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(TimelineEventType, String)>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeline_limit: Option<UInt>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "UPPERCASE")]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum SlidingOp {
Sync,
Insert,
Delete,
Invalidate,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SyncList {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub ops: Vec<SyncOp>,
pub count: UInt,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SyncOp {
pub op: SlidingOp,
pub range: Option<(UInt, UInt)>,
pub index: Option<UInt>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub room_ids: Vec<OwnedRoomId>,
pub room_id: Option<OwnedRoomId>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SlidingSyncRoom {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_dm: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub invite_state: Vec<Raw<AnyStrippedStateEvent>>,
#[serde(flatten, default, skip_serializing_if = "UnreadNotificationsCount::is_empty")]
pub unread_notifications: UnreadNotificationsCount,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub timeline: Vec<Raw<AnySyncTimelineEvent>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<Raw<AnySyncStateEvent>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prev_batch: Option<String>,
#[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
pub limited: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub joined_count: Option<UInt>,
#[serde(skip_serializing_if = "Option::is_none")]
pub invited_count: Option<UInt>,
#[serde(skip_serializing_if = "Option::is_none")]
pub num_live: Option<UInt>,
}
impl SlidingSyncRoom {
pub fn new() -> Self {
Default::default()
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ExtensionsConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub to_device: Option<ToDeviceConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub e2ee: Option<E2EEConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<AccountDataConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt: Option<ReceiptConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub typing: Option<TypingConfig>,
#[serde(flatten)]
other: BTreeMap<String, serde_json::Value>,
}
impl ExtensionsConfig {
fn is_empty(&self) -> bool {
self.to_device.is_none()
&& self.e2ee.is_none()
&& self.account_data.is_none()
&& self.receipt.is_none()
&& self.typing.is_none()
&& self.other.is_empty()
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Extensions {
#[serde(skip_serializing_if = "Option::is_none")]
pub to_device: Option<ToDevice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub e2ee: Option<E2EE>,
#[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<AccountData>,
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt: Option<Receipt>,
#[serde(skip_serializing_if = "Option::is_none")]
pub typing: Option<Typing>,
}
impl Extensions {
pub fn is_empty(&self) -> bool {
self.to_device.is_none()
&& self.e2ee.is_none()
&& self.account_data.is_none()
&& self.receipt.is_none()
&& self.typing.is_none()
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ToDeviceConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<UInt>,
#[serde(skip_serializing_if = "Option::is_none")]
pub since: Option<String>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ToDevice {
pub next_batch: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events: Vec<Raw<AnyToDeviceEvent>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct E2EEConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct E2EE {
#[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, UInt>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_unused_fallback_key_types: Option<Vec<DeviceKeyAlgorithm>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct AccountDataConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct AccountData {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub global: Vec<Raw<AnyGlobalAccountDataEvent>>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, Vec<Raw<AnyRoomAccountDataEvent>>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ReceiptConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Receipt {
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, Raw<AnyEphemeralRoomEvent>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct TypingConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Typing {
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, Raw<AnyEphemeralRoomEvent>>,
}