diff --git a/crates/ruma-client-api/CHANGELOG.md b/crates/ruma-client-api/CHANGELOG.md index 54cc3ea2..e98dc2ed 100644 --- a/crates/ruma-client-api/CHANGELOG.md +++ b/crates/ruma-client-api/CHANGELOG.md @@ -1,5 +1,11 @@ # [unreleased] + +Improvements: + +* `DeviceLists` has moved from `sync::sync_events::v3` to `sync::sync_events` + * It is still available under the old location for backwards compatibility + # 0.15.0 Breaking changes: diff --git a/crates/ruma-client-api/src/sync/sync_events.rs b/crates/ruma-client-api/src/sync/sync_events.rs index f8b803ce..f401b8a8 100644 --- a/crates/ruma-client-api/src/sync/sync_events.rs +++ b/crates/ruma-client-api/src/sync/sync_events.rs @@ -1,6 +1,7 @@ //! `GET /_matrix/client/*/sync` use js_int::UInt; +use ruma_common::OwnedUserId; use serde::{self, Deserialize, Serialize}; pub mod v3; @@ -32,3 +33,30 @@ impl UnreadNotificationsCount { self.highlight_count.is_none() && self.notification_count.is_none() } } + +/// Information on E2E device updates. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct DeviceLists { + /// List of users who have updated their device identity keys or who now + /// share an encrypted room with the client since the previous sync. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub changed: Vec, + + /// List of users who no longer share encrypted rooms since the previous sync + /// response. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub left: Vec, +} + +impl DeviceLists { + /// Creates an empty `DeviceLists`. + pub fn new() -> Self { + Default::default() + } + + /// Returns true if there are no device list updates. + pub fn is_empty(&self) -> bool { + self.changed.is_empty() && self.left.is_empty() + } +} diff --git a/crates/ruma-client-api/src/sync/sync_events/v3.rs b/crates/ruma-client-api/src/sync/sync_events/v3.rs index c73b8c8c..1a30134f 100644 --- a/crates/ruma-client-api/src/sync/sync_events/v3.rs +++ b/crates/ruma-client-api/src/sync/sync_events/v3.rs @@ -4,6 +4,7 @@ use std::{collections::BTreeMap, time::Duration}; +pub use super::DeviceLists; use super::UnreadNotificationsCount; use js_int::UInt; use ruma_common::{ @@ -15,7 +16,7 @@ use ruma_common::{ }, presence::PresenceState, serde::{Incoming, Raw}, - DeviceKeyAlgorithm, OwnedRoomId, OwnedUserId, + DeviceKeyAlgorithm, OwnedRoomId, }; use serde::{Deserialize, Serialize}; @@ -579,33 +580,6 @@ impl ToDevice { } } -/// Information on E2E device updates. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -pub struct DeviceLists { - /// List of users who have updated their device identity keys or who now - /// share an encrypted room with the client since the previous sync - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub changed: Vec, - - /// List of users who no longer share encrypted rooms since the previous sync - /// response. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub left: Vec, -} - -impl DeviceLists { - /// Creates an empty `DeviceLists`. - pub fn new() -> Self { - Default::default() - } - - /// Returns true if there are no device list updates. - pub fn is_empty(&self) -> bool { - self.changed.is_empty() && self.left.is_empty() - } -} - #[cfg(test)] mod tests { use assign::assign; diff --git a/crates/ruma-client-api/src/sync/sync_events/v4.rs b/crates/ruma-client-api/src/sync/sync_events/v4.rs index 5aaef69c..e8b78d8a 100644 --- a/crates/ruma-client-api/src/sync/sync_events/v4.rs +++ b/crates/ruma-client-api/src/sync/sync_events/v4.rs @@ -2,13 +2,16 @@ use std::{collections::BTreeMap, time::Duration}; -use super::UnreadNotificationsCount; +use super::{DeviceLists, UnreadNotificationsCount}; use js_int::UInt; use ruma_common::{ api::ruma_api, - events::{AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, RoomEventType}, + events::{ + AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent, + AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, RoomEventType, + }, serde::{duration::opt_ms, Raw}, - OwnedRoomId, + DeviceKeyAlgorithm, OwnedRoomId, }; use serde::{Deserialize, Serialize}; @@ -60,8 +63,8 @@ ruma_api! { pub unsubscribe_rooms: &'a [OwnedRoomId], /// Extensions API. - #[serde(skip_serializing_if = "BTreeMap::is_empty")] - pub extensions: BTreeMap, + #[serde(default, skip_serializing_if = "ExtensionsConfig::is_empty")] + pub extensions: ExtensionsConfig, } response: { @@ -80,6 +83,10 @@ ruma_api! { /// The updates on rooms. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub rooms: BTreeMap, + + /// Extensions API. + #[serde(default, skip_serializing_if = "Extensions::is_empty")] + pub extensions: Extensions, } error: crate::Error @@ -100,9 +107,11 @@ impl Response { pos, lists: Default::default(), rooms: Default::default(), + extensions: Default::default(), } } } + /// Filter for a sliding sync list, set at request. /// /// All fields are applied with AND operators, hence if `is_dm` is `true` and `is_encrypted` is @@ -162,7 +171,7 @@ pub struct SyncRequestListFilters { /// of the strings in this array will be returned. If this field is unset, all rooms are /// returned regardless of type. This can be used to get the initial set of spaces for an /// account. - #[serde(skip_serializing_if = "Vec::is_empty")] + #[serde(default, skip_serializing_if = "Vec::is_empty")] pub room_types: Vec, /// Only list rooms that are not of these create-types, or all. @@ -176,8 +185,25 @@ pub struct SyncRequestListFilters { /// /// Filter the room name. Case-insensitive partial matching e.g 'foo' matches 'abFooab'. /// The term 'like' is inspired by SQL 'LIKE', and the text here is similar to '%foo%'. + #[serde(skip_serializing_if = "Option::is_none")] pub room_name_like: Option, + /// Filter the room based on its room tags. + /// + /// If multiple tags are present, a room can have + /// any one of the listed tags (OR'd). + #[serde(default, skip_serializing_if = "<[_]>::is_empty")] + pub tags: Vec, + + /// Filter the room based on its room tags. + /// + /// Takes priority over `tags`. For example, a room + /// with tags A and B with filters `tags:[A]` `not_tags:[B]` would NOT be included because + /// `not_tags` takes priority over `tags`. This filter is useful if your Rooms list does + /// NOT include the list of favourite rooms again. + #[serde(default, skip_serializing_if = "<[_]>::is_empty")] + pub not_tags: Vec, + /// Extensions may add further fields to the filters. #[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")] pub extensions: BTreeMap, @@ -325,6 +351,18 @@ pub struct SlidingSyncRoom { /// The prev_batch allowing you to paginate through the messages before the given ones. #[serde(skip_serializing_if = "Option::is_none")] pub prev_batch: Option, + + /// True if the number of events returned was limited by the limit on the filter. + #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")] + pub limited: bool, + + /// The number of users with membership of `join`, including the client’s own user ID. + #[serde(skip_serializing_if = "Option::is_none")] + pub joined_count: Option, + + /// The number of users with membership of `invite`. + #[serde(skip_serializing_if = "Option::is_none")] + pub invited_count: Option, } impl SlidingSyncRoom { @@ -333,3 +371,157 @@ impl SlidingSyncRoom { Default::default() } } + +/// Sliding-Sync extension configuration. +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct ExtensionsConfig { + /// Request to devices messages with the given config. + #[serde(skip_serializing_if = "Option::is_none")] + pub to_device: Option, + + /// Configure the end-to-end-encryption extension. + #[serde(skip_serializing_if = "Option::is_none")] + pub e2ee: Option, + + /// Configure the account data extension. + #[serde(skip_serializing_if = "Option::is_none")] + pub account_data: Option, + + /// Extensions may add further fields to the list. + #[serde(flatten)] + other: BTreeMap, +} + +impl ExtensionsConfig { + fn is_empty(&self) -> bool { + self.to_device.is_none() + && self.e2ee.is_none() + && self.account_data.is_none() + && self.other.is_empty() + } +} + +/// Extensions specific response data. +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct Extensions { + /// To-device extension in response. + #[serde(skip_serializing_if = "Option::is_none")] + pub to_device: Option, + + /// E2EE extension in response. + #[serde(skip_serializing_if = "Option::is_none")] + pub e2ee: Option, + + /// Account data extension in response. + #[serde(skip_serializing_if = "Option::is_none")] + pub account_data: Option, +} + +impl Extensions { + /// Whether extension data was given. + /// + /// True if neither to-device, e2ee nor account data are to be found. + pub fn is_empty(&self) -> bool { + self.to_device.is_none() && self.e2ee.is_none() && self.account_data.is_none() + } +} + +/// To-device messages extension configuration. +/// +/// According to [MSC3885](https://github.com/matrix-org/matrix-spec-proposals/pull/3885). +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct ToDeviceConfig { + /// Activate or deactivate this extension. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, + + /// Max number of to-device messages per response. + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + + /// Give messages since this token only. + #[serde(skip_serializing_if = "Option::is_none")] + pub since: Option, +} + +/// To-device messages extension response. +/// +/// According to [MSC3885](https://github.com/matrix-org/matrix-spec-proposals/pull/3885). +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct ToDevice { + /// Fetch the next batch from this entry. + pub next_batch: String, + + /// The to-device Events. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub events: Vec>, +} + +/// E2EE extension configuration. +/// +/// According to [MSC3884](https://github.com/matrix-org/matrix-spec-proposals/pull/3884). +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct E2EEConfig { + /// Activate or deactivate this extension. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +/// E2EE extension response data. +/// +/// According to [MSC3884](https://github.com/matrix-org/matrix-spec-proposals/pull/3884). +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct E2EE { + /// Information on E2EE device updates. + /// + /// Only present on an incremental sync. + #[serde(default, skip_serializing_if = "DeviceLists::is_empty")] + pub device_lists: DeviceLists, + + /// For each key algorithm, the number of unclaimed one-time keys + /// currently held on the server for a device. + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub device_one_time_keys_count: BTreeMap, + + /// For each key algorithm, the number of unclaimed one-time keys + /// currently held on the server for a device. + /// + /// The presence of this field indicates that the server supports + /// fallback keys. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_unused_fallback_key_types: Option>, +} + +/// Account-data extension configuration. +/// +/// Not yet part of the spec proposal. Taken from the reference implementation +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct AccountDataConfig { + /// Activate or deactivate this extension. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +/// Account-data extension response data. +/// +/// Not yet part of the spec proposal. Taken from the reference implementation +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct AccountData { + /// The global private data created by this user. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub global: Vec>, + + /// The private data that this user has attached to each room. + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub rooms: BTreeMap>>, +}