From 00045e559f864eabff08295d603f7b3238288b6f Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 31 Jan 2023 12:48:47 +0000 Subject: [PATCH] client-api: Upgrade to Sliding Sync JSON Layout 0.99 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and implement typing and receipt extensions. --- .../src/sync/sync_events/v4.rs | 174 ++++++++++++++++-- 1 file changed, 158 insertions(+), 16 deletions(-) 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 6baa343a..e06eb8c6 100644 --- a/crates/ruma-client-api/src/sync/sync_events/v4.rs +++ b/crates/ruma-client-api/src/sync/sync_events/v4.rs @@ -11,8 +11,9 @@ use js_int::UInt; use ruma_common::{ api::{request, response, Metadata}, events::{ - AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent, - AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, TimelineEventType, + AnyEphemeralRoomEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, + AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, + TimelineEventType, }, metadata, serde::{duration::opt_ms, Raw}, @@ -42,6 +43,24 @@ pub struct Request { #[ruma_api(query)] pub pos: Option, + /// The delta token to store for session recovery. + /// + /// The delta token is a future bandwidth optimisation to resume from an + /// earlier session. If you received a delta token in your last response + /// you can persist and it when establishing a new sessions to "resume" + /// from the last state and not resend information you had stored. If you + /// send a delta token, the server expects you to have stored the last + /// state, if there is no delta token present the server will resend all + /// information necessary to calculate the state. + /// + /// Please consult ["Bandwidth optimisations for persistent clients" of the MSC][MSC] + /// for further details, expectations of the implementation and limitations + /// to consider before implementing this. + /// + /// [MSC]: https://github.com/matrix-org/matrix-spec-proposals/blob/kegan/sync-v3/proposals/3575-sync.md#bandwidth-optimisations-for-persistent-clients + #[serde(skip_serializing_if = "Option::is_none")] + pub delta_token: Option, + /// Allows clients to know what request params reached the server, /// functionally similar to txn IDs on /send for events. #[serde(skip_serializing_if = "Option::is_none")] @@ -52,8 +71,10 @@ pub struct Request { #[ruma_api(query)] pub timeout: Option, - /// The lists of rooms we're interested in. - pub lists: Vec, + /// The list configurations of rooms we are interested in mapped by + /// name. + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub lists: BTreeMap, /// Specific rooms and event types that we want to receive events from. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] @@ -79,9 +100,9 @@ pub struct Response { /// The token to supply in the `pos` param of the next `/sync` request. pub pos: String, - /// Updates to the sliding room list. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub lists: Vec, + /// Updates on the order of rooms, mapped by the names we asked for. + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub lists: BTreeMap, /// The updates on rooms. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] @@ -90,6 +111,23 @@ pub struct Response { /// Extensions API. #[serde(default, skip_serializing_if = "Extensions::is_empty")] pub extensions: Extensions, + + /// The delta token to store for session recovery. + /// + /// The delta token is a future bandwidth optimisation to resume from an + /// earlier session. If you received a delta token in your last response + /// you can persist and it when establishing a new sessions to "resume" + /// from the last state and not resend information you had stored. If you + /// send a delta token, the server expects you to have stored the last + /// state, if there is no delta token present the server will resend all + /// information necessary to calculate the state. + /// + /// Please consult ["Bandwidth optimisations for persistent clients" of the MSC][MSC] + /// for further details, expectations of the implementation and limitations + /// to consider before implementing this. + /// + /// [MSC]: https://github.com/matrix-org/matrix-spec-proposals/blob/kegan/sync-v3/proposals/3575-sync.md#bandwidth-optimisations-for-persistent-clients + pub delta_token: Option, } impl Request { @@ -105,6 +143,7 @@ impl Response { Self { initial: Default::default(), pos, + delta_token: Default::default(), lists: Default::default(), rooms: Default::default(), extensions: Default::default(), @@ -232,7 +271,25 @@ pub struct SyncRequestList { #[serde(default, skip_serializing_if = "Vec::is_empty")] pub sort: Vec, + /// The details to be included per room + #[serde(flatten)] + pub room_details: RoomDetailsConfig, + + /// If tombstoned rooms should be returned and if so, with what information attached + #[serde(skip_serializing_if = "Option::is_none")] + pub include_old_rooms: Option, + + /// Filters to apply to the list before sorting. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub filters: Option, +} + +/// Configuration for requesting room details. +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct RoomDetailsConfig { /// Required state for each room returned. An array of event type and state key tuples. + /// /// Note that elements of this array are NOT sticky so they must be specified in full when they /// are changed. Sticky. #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -241,13 +298,25 @@ pub struct SyncRequestList { /// The maximum number of timeline events to return per room. Sticky. #[serde(skip_serializing_if = "Option::is_none")] pub timeline_limit: Option, - - /// Filters to apply to the list before sorting. Sticky. - #[serde(skip_serializing_if = "Option::is_none")] - pub filters: Option, } -/// The RoomSubscriptions of the SlidingSync Request +/// Configuration for old rooms to include +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct IncludeOldRooms { + /// Required state for each room returned. An array of event type and state key tuples. + /// + /// Note that elements of this array are NOT sticky so they must be specified in full when they + /// are changed. Sticky. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub required_state: Vec<(TimelineEventType, String)>, + + /// The maximum number of timeline events to return per room. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub timeline_limit: Option, +} + +/// Configuration for room subscription #[derive(Clone, Debug, Default, Serialize, Deserialize)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct RoomSubscription { @@ -255,7 +324,6 @@ pub struct RoomSubscription { /// /// Note that elements of this array are NOT sticky so they must be specified in full when they /// are changed. Sticky. - #[serde(default, skip_serializing_if = "Vec::is_empty")] pub required_state: Vec<(TimelineEventType, String)>, @@ -363,6 +431,10 @@ pub struct SlidingSyncRoom { /// The number of users with membership of `invite`. #[serde(skip_serializing_if = "Option::is_none")] pub invited_count: Option, + + /// The number of timeline events which have just occurred and are not historical. + #[serde(skip_serializing_if = "Option::is_none")] + pub num_live: Option, } impl SlidingSyncRoom { @@ -388,6 +460,14 @@ pub struct ExtensionsConfig { #[serde(skip_serializing_if = "Option::is_none")] pub account_data: Option, + /// Request to receipt information with the given config. + #[serde(skip_serializing_if = "Option::is_none")] + pub receipt: Option, + + /// Request to typing information with the given config. + #[serde(skip_serializing_if = "Option::is_none")] + pub typing: Option, + /// Extensions may add further fields to the list. #[serde(flatten)] other: BTreeMap, @@ -398,6 +478,8 @@ impl ExtensionsConfig { 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() } } @@ -417,6 +499,14 @@ pub struct Extensions { /// Account data extension in response. #[serde(skip_serializing_if = "Option::is_none")] pub account_data: Option, + + /// Receipt data extension in response. + #[serde(skip_serializing_if = "Option::is_none")] + pub receipt: Option, + + /// Typing data extension in response. + #[serde(skip_serializing_if = "Option::is_none")] + pub typing: Option, } impl Extensions { @@ -424,7 +514,11 @@ impl Extensions { /// /// 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() + self.to_device.is_none() + && self.e2ee.is_none() + && self.account_data.is_none() + && self.receipt.is_none() + && self.typing.is_none() } } @@ -501,7 +595,7 @@ pub struct E2EE { /// Account-data extension configuration. /// /// Not yet part of the spec proposal. Taken from the reference implementation -/// +/// #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct AccountDataConfig { @@ -513,7 +607,7 @@ pub struct AccountDataConfig { /// 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 { @@ -525,3 +619,51 @@ pub struct AccountData { #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub rooms: BTreeMap>>, } + +/// Receipt extension configuration. +/// +/// Not yet part of the spec proposal. Taken from the reference implementation +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct ReceiptConfig { + /// Activate or deactivate this extension. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +/// Receipt 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 Receipt { + /// The empheral receipt room event for each room + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub rooms: BTreeMap>, +} + +/// Typing extension configuration. +/// +/// Not yet part of the spec proposal. Taken from the reference implementation +/// +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct TypingConfig { + /// Activate or deactivate this extension. Sticky. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +/// Typing 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 Typing { + /// The empheral typing event for each room + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub rooms: BTreeMap>, +}