client-api: Upgrade to Sliding Sync JSON Layout 0.99

… and implement typing and receipt extensions.
This commit is contained in:
Benjamin Kampmann 2023-01-31 12:48:47 +00:00 committed by GitHub
parent e37d064306
commit 00045e559f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -11,8 +11,9 @@ use js_int::UInt;
use ruma_common::{ use ruma_common::{
api::{request, response, Metadata}, api::{request, response, Metadata},
events::{ events::{
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnyEphemeralRoomEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent, TimelineEventType, AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyToDeviceEvent,
TimelineEventType,
}, },
metadata, metadata,
serde::{duration::opt_ms, Raw}, serde::{duration::opt_ms, Raw},
@ -42,6 +43,24 @@ pub struct Request {
#[ruma_api(query)] #[ruma_api(query)]
pub pos: Option<String>, pub pos: Option<String>,
/// 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<String>,
/// Allows clients to know what request params reached the server, /// Allows clients to know what request params reached the server,
/// functionally similar to txn IDs on /send for events. /// functionally similar to txn IDs on /send for events.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -52,8 +71,10 @@ pub struct Request {
#[ruma_api(query)] #[ruma_api(query)]
pub timeout: Option<Duration>, pub timeout: Option<Duration>,
/// The lists of rooms we're interested in. /// The list configurations of rooms we are interested in mapped by
pub lists: Vec<SyncRequestList>, /// name.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: BTreeMap<String, SyncRequestList>,
/// Specific rooms and event types that we want to receive events from. /// Specific rooms and event types that we want to receive events from.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[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. /// The token to supply in the `pos` param of the next `/sync` request.
pub pos: String, pub pos: String,
/// Updates to the sliding room list. /// Updates on the order of rooms, mapped by the names we asked for.
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub lists: Vec<SyncList>, pub lists: BTreeMap<String, SyncList>,
/// The updates on rooms. /// The updates on rooms.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
@ -90,6 +111,23 @@ pub struct Response {
/// Extensions API. /// Extensions API.
#[serde(default, skip_serializing_if = "Extensions::is_empty")] #[serde(default, skip_serializing_if = "Extensions::is_empty")]
pub extensions: Extensions, 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<String>,
} }
impl Request { impl Request {
@ -105,6 +143,7 @@ impl Response {
Self { Self {
initial: Default::default(), initial: Default::default(),
pos, pos,
delta_token: Default::default(),
lists: Default::default(), lists: Default::default(),
rooms: Default::default(), rooms: Default::default(),
extensions: Default::default(), extensions: Default::default(),
@ -232,7 +271,25 @@ pub struct SyncRequestList {
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sort: Vec<String>, pub sort: Vec<String>,
/// 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<IncludeOldRooms>,
/// Filters to apply to the list before sorting. Sticky.
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<SyncRequestListFilters>,
}
/// 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. /// 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 /// Note that elements of this array are NOT sticky so they must be specified in full when they
/// are changed. Sticky. /// are changed. Sticky.
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[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. /// The maximum number of timeline events to return per room. Sticky.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub timeline_limit: Option<UInt>, pub timeline_limit: Option<UInt>,
/// Filters to apply to the list before sorting. Sticky.
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<SyncRequestListFilters>,
} }
/// 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<UInt>,
}
/// Configuration for room subscription
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomSubscription { 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 /// Note that elements of this array are NOT sticky so they must be specified in full when they
/// are changed. Sticky. /// are changed. Sticky.
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub required_state: Vec<(TimelineEventType, String)>, pub required_state: Vec<(TimelineEventType, String)>,
@ -363,6 +431,10 @@ pub struct SlidingSyncRoom {
/// The number of users with membership of `invite`. /// The number of users with membership of `invite`.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub invited_count: Option<UInt>, pub invited_count: Option<UInt>,
/// The number of timeline events which have just occurred and are not historical.
#[serde(skip_serializing_if = "Option::is_none")]
pub num_live: Option<UInt>,
} }
impl SlidingSyncRoom { impl SlidingSyncRoom {
@ -388,6 +460,14 @@ pub struct ExtensionsConfig {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<AccountDataConfig>, pub account_data: Option<AccountDataConfig>,
/// Request to receipt information with the given config.
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt: Option<ReceiptConfig>,
/// Request to typing information with the given config.
#[serde(skip_serializing_if = "Option::is_none")]
pub typing: Option<TypingConfig>,
/// Extensions may add further fields to the list. /// Extensions may add further fields to the list.
#[serde(flatten)] #[serde(flatten)]
other: BTreeMap<String, serde_json::Value>, other: BTreeMap<String, serde_json::Value>,
@ -398,6 +478,8 @@ impl ExtensionsConfig {
self.to_device.is_none() self.to_device.is_none()
&& self.e2ee.is_none() && self.e2ee.is_none()
&& self.account_data.is_none() && self.account_data.is_none()
&& self.receipt.is_none()
&& self.typing.is_none()
&& self.other.is_empty() && self.other.is_empty()
} }
} }
@ -417,6 +499,14 @@ pub struct Extensions {
/// Account data extension in response. /// Account data extension in response.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<AccountData>, pub account_data: Option<AccountData>,
/// Receipt data extension in response.
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt: Option<Receipt>,
/// Typing data extension in response.
#[serde(skip_serializing_if = "Option::is_none")]
pub typing: Option<Typing>,
} }
impl Extensions { impl Extensions {
@ -424,7 +514,11 @@ impl Extensions {
/// ///
/// True if neither to-device, e2ee nor account data are to be found. /// True if neither to-device, e2ee nor account data are to be found.
pub fn is_empty(&self) -> bool { 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. /// Account-data extension configuration.
/// ///
/// Not yet part of the spec proposal. Taken from the reference implementation /// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/d77e21138d4886d27b3888d36cf3627f54f67590/sync3/extensions/account_data.go> /// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/account_data.go>
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct AccountDataConfig { pub struct AccountDataConfig {
@ -513,7 +607,7 @@ pub struct AccountDataConfig {
/// Account-data extension response data. /// Account-data extension response data.
/// ///
/// Not yet part of the spec proposal. Taken from the reference implementation /// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/d77e21138d4886d27b3888d36cf3627f54f67590/sync3/extensions/account_data.go> /// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/account_data.go>
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct AccountData { pub struct AccountData {
@ -525,3 +619,51 @@ pub struct AccountData {
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub rooms: BTreeMap<OwnedRoomId, Vec<Raw<AnyRoomAccountDataEvent>>>, pub rooms: BTreeMap<OwnedRoomId, Vec<Raw<AnyRoomAccountDataEvent>>>,
} }
/// Receipt extension configuration.
///
/// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/receipts.go>
#[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<bool>,
}
/// Receipt extension response data.
///
/// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/receipts.go>
#[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<OwnedRoomId, Raw<AnyEphemeralRoomEvent>>,
}
/// Typing extension configuration.
///
/// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/typing.go>
#[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<bool>,
}
/// Typing extension response data.
///
/// Not yet part of the spec proposal. Taken from the reference implementation
/// <https://github.com/matrix-org/sliding-sync/blob/main/sync3/extensions/typing.go>
#[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<OwnedRoomId, Raw<AnyEphemeralRoomEvent>>,
}