From 6dfd89b98d829dc7d232c3d31be58701ee0d0847 Mon Sep 17 00:00:00 2001 From: Adam <13720823+Frinksy@users.noreply.github.com> Date: Mon, 5 Jul 2021 15:57:06 +0100 Subject: [PATCH] Add knock feature (unstable-pre-spec) --- crates/ruma-client-api/src/r0.rs | 3 + crates/ruma-client-api/src/r0/directory.rs | 6 ++ crates/ruma-client-api/src/r0/knock.rs | 3 + .../src/r0/knock/knock_room.rs | 51 +++++++++++++++++ .../src/r0/sync/sync_events.rs | 28 +++++++++ crates/ruma-federation-api/src/knock.rs | 4 ++ .../src/knock/create_knock_event_template.rs | 3 + .../knock/create_knock_event_template/v1.rs | 57 +++++++++++++++++++ .../src/knock/send_knock.rs | 3 + .../src/knock/send_knock/v1.rs | 49 ++++++++++++++++ crates/ruma-federation-api/src/lib.rs | 3 + 11 files changed, 210 insertions(+) create mode 100644 crates/ruma-client-api/src/r0/knock.rs create mode 100644 crates/ruma-client-api/src/r0/knock/knock_room.rs create mode 100644 crates/ruma-federation-api/src/knock.rs create mode 100644 crates/ruma-federation-api/src/knock/create_knock_event_template.rs create mode 100644 crates/ruma-federation-api/src/knock/create_knock_event_template/v1.rs create mode 100644 crates/ruma-federation-api/src/knock/send_knock.rs create mode 100644 crates/ruma-federation-api/src/knock/send_knock/v1.rs diff --git a/crates/ruma-client-api/src/r0.rs b/crates/ruma-client-api/src/r0.rs index f33715e0..296a294b 100644 --- a/crates/ruma-client-api/src/r0.rs +++ b/crates/ruma-client-api/src/r0.rs @@ -12,6 +12,9 @@ pub mod device; pub mod directory; pub mod filter; pub mod keys; +#[cfg(feature = "unstable-pre-spec")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] +pub mod knock; pub mod media; pub mod membership; pub mod message; diff --git a/crates/ruma-client-api/src/r0/directory.rs b/crates/ruma-client-api/src/r0/directory.rs index 494f372f..097e0736 100644 --- a/crates/ruma-client-api/src/r0/directory.rs +++ b/crates/ruma-client-api/src/r0/directory.rs @@ -6,6 +6,7 @@ pub mod get_room_visibility; pub mod set_room_visibility; use js_int::{uint, UInt}; +use ruma_events::room::join_rules::JoinRule; use ruma_identifiers::{MxcUri, RoomAliasId, RoomId}; use serde::{Deserialize, Serialize}; @@ -53,6 +54,10 @@ pub struct PublicRoomsChunk { serde(default, deserialize_with = "ruma_serde::empty_string_as_none") )] pub avatar_url: Option, + + /// The joining rule for the room. + #[serde(skip_serializing_if = "Option::is_none")] + pub join_rule: Option, } impl PublicRoomsChunk { @@ -72,6 +77,7 @@ impl PublicRoomsChunk { world_readable: false, guest_can_join: false, avatar_url: None, + join_rule: None, } } } diff --git a/crates/ruma-client-api/src/r0/knock.rs b/crates/ruma-client-api/src/r0/knock.rs new file mode 100644 index 00000000..3f0f8df1 --- /dev/null +++ b/crates/ruma-client-api/src/r0/knock.rs @@ -0,0 +1,3 @@ +//! Endpoints to knock on a room. + +pub mod knock_room; diff --git a/crates/ruma-client-api/src/r0/knock/knock_room.rs b/crates/ruma-client-api/src/r0/knock/knock_room.rs new file mode 100644 index 00000000..7c9e883a --- /dev/null +++ b/crates/ruma-client-api/src/r0/knock/knock_room.rs @@ -0,0 +1,51 @@ +//! [POST /_matrix/client/r0/knock/{roomIdOrAlias}](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientr0knockroomidoralias) + +use ruma_api::ruma_api; +use ruma_identifiers::{RoomId, RoomIdOrAliasId, ServerNameBox}; + +ruma_api! { + metadata: { + description: "Knock on a room.", + method: POST, + name: "knock_room", + path: "/_matrix/client/r0/knock/:room_id_or_alias", + rate_limited: true, + authentication: AccessToken, + } + + request: { + /// The room the user should knock on. + #[ruma_api(path)] + pub room_id_or_alias: RoomIdOrAliasId, + + /// The reason for joining a room. + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option<&'a str>, + + /// The servers to attempt to knock on the room through. + /// + /// One of the servers must be participating in the room. + #[ruma_api(query)] + #[serde(default, skip_serializing_if = "<[_]>::is_empty")] + pub server_name: &'a [ServerNameBox], + } + + response: { + /// The room that the user knocked on. + pub room_id: RoomId, + } +} + +impl<'a> Request<'a> { + /// Creates a new `Request` with the given room ID or alias. + pub fn new(room_id_or_alias: RoomIdOrAliasId) -> Self { + Self { room_id_or_alias, reason: None, server_name: &[] } + } +} + +impl Response { + /// Creates a new `Response` with the given room ID. + pub fn new(room_id: RoomId) -> Self { + Self { room_id } + } +} diff --git a/crates/ruma-client-api/src/r0/sync/sync_events.rs b/crates/ruma-client-api/src/r0/sync/sync_events.rs index afe1ad7d..62c9fb05 100644 --- a/crates/ruma-client-api/src/r0/sync/sync_events.rs +++ b/crates/ruma-client-api/src/r0/sync/sync_events.rs @@ -181,6 +181,12 @@ pub struct Rooms { #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub invite: BTreeMap, + /// The rooms that the user has knocked on. + #[cfg(feature = "unstable-pre-spec")] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub knock: BTreeMap, + #[cfg(not(feature = "unstable-exhaustive-types"))] #[doc(hidden)] #[serde(skip, default = "crate::private")] @@ -205,6 +211,8 @@ impl Default for Rooms { leave: BTreeMap::new(), join: BTreeMap::new(), invite: BTreeMap::new(), + #[cfg(feature = "unstable-pre-spec")] + knock: BTreeMap::new(), #[cfg(not(feature = "unstable-exhaustive-types"))] __test_exhaustive: crate::private(), } @@ -326,6 +334,26 @@ impl Default for JoinedRoom { } } +/// Updates to knocked rooms. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg(feature = "unstable-pre-spec")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct KnockedRoom { + /// The knock state. + pub knock_state: KnockState, +} + +/// A mapping from a key `events` to a list of `StrippedStateEvent`. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg(feature = "unstable-pre-spec")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub struct KnockState { + /// The list of events. + pub events: Vec, +} + /// Unread notifications count. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct UnreadNotificationsCount { diff --git a/crates/ruma-federation-api/src/knock.rs b/crates/ruma-federation-api/src/knock.rs new file mode 100644 index 00000000..001265d6 --- /dev/null +++ b/crates/ruma-federation-api/src/knock.rs @@ -0,0 +1,4 @@ +//! Endpoints for handling room knocking. + +pub mod create_knock_event_template; +pub mod send_knock; diff --git a/crates/ruma-federation-api/src/knock/create_knock_event_template.rs b/crates/ruma-federation-api/src/knock/create_knock_event_template.rs new file mode 100644 index 00000000..67f958f7 --- /dev/null +++ b/crates/ruma-federation-api/src/knock/create_knock_event_template.rs @@ -0,0 +1,3 @@ +//! Endpoint to query information to prepare a knock event. + +pub mod v1; diff --git a/crates/ruma-federation-api/src/knock/create_knock_event_template/v1.rs b/crates/ruma-federation-api/src/knock/create_knock_event_template/v1.rs new file mode 100644 index 00000000..a7afb255 --- /dev/null +++ b/crates/ruma-federation-api/src/knock/create_knock_event_template/v1.rs @@ -0,0 +1,57 @@ +//! [GET /_matrix/federation/v1/make_knock/{roomId}/{userId}](https://spec.matrix.org/unstable/server-server-api/#get_matrixfederationv1make_knockroomiduserid) + +use ruma_api::ruma_api; +use ruma_events::pdu::Pdu; +use ruma_identifiers::{RoomId, RoomVersionId, UserId}; +use ruma_serde::Raw; + +ruma_api! { + metadata: { + description: "Send a request for a knock event template to a resident server.", + name: "create_knock_event_template", + method: GET, + path: "/_matrix/federation/v1/make_knock/:room_id/:user_id", + rate_limited: false, + authentication: ServerSignatures, + } + + request: { + /// The room ID that should receive the knock. + #[ruma_api(path)] + pub room_id: &'a RoomId, + + /// The user ID the knock event will be for. + #[ruma_api(path)] + pub user_id: &'a UserId, + + /// The room versions the sending has support for. + /// + /// Defaults to `&[RoomVersionId::Version1]`. + #[ruma_api(query)] + pub ver: &'a [RoomVersionId], + } + + response: { + /// The version of the room where the server is trying to knock. + pub room_version: RoomVersionId, + + /// An unsigned template event. + /// + /// May differ between room versions. + pub event: Raw, + } +} + +impl<'a> Request<'a> { + /// Creates a `Request` with the given room ID and user ID. + pub fn new(room_id: &'a RoomId, user_id: &'a UserId) -> Self { + Self { room_id, user_id, ver: &[RoomVersionId::Version1] } + } +} + +impl Response { + /// Creates a new `Response` with the given room version ID and event. + pub fn new(room_version: RoomVersionId, event: Raw) -> Self { + Self { room_version, event } + } +} diff --git a/crates/ruma-federation-api/src/knock/send_knock.rs b/crates/ruma-federation-api/src/knock/send_knock.rs new file mode 100644 index 00000000..1fdcd4c8 --- /dev/null +++ b/crates/ruma-federation-api/src/knock/send_knock.rs @@ -0,0 +1,3 @@ +//! Endpoint to submit a signed knock event to the resident homeserver. + +pub mod v1; diff --git a/crates/ruma-federation-api/src/knock/send_knock/v1.rs b/crates/ruma-federation-api/src/knock/send_knock/v1.rs new file mode 100644 index 00000000..7054904b --- /dev/null +++ b/crates/ruma-federation-api/src/knock/send_knock/v1.rs @@ -0,0 +1,49 @@ +//! [PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}](https://spec.matrix.org/unstable/server-server-api/#put_matrixfederationv1send_knockroomideventid) + +use ruma_api::ruma_api; +use ruma_events::{room::member::MemberEvent, AnyStrippedStateEvent}; +use ruma_identifiers::{EventId, RoomId}; + +ruma_api! { + metadata: { + description: "Submits a signed knock event to the resident homeserver for it to accept into the room's graph.", + name: "send_knock", + method: PUT, + path: "/_matrix/federation/v1/send_knock/:room_id/:event_id", + rate_limited: false, + authentication: ServerSignatures, + } + + request: { + /// The room ID that should receive the knock. + #[ruma_api(path)] + pub room_id: &'a RoomId, + + /// The event ID for the knock event. + #[ruma_api(path)] + pub event_id: &'a EventId, + + /// The full knock event. + #[ruma_api(body)] + pub knock_event: &'a MemberEvent, + } + + response: { + /// State events providing public room metadata. + pub knock_room_state: Vec, + } +} + +impl<'a> Request<'a> { + /// Creates a new `Request` with the given room ID, event ID and knock event. + pub fn new(room_id: &'a RoomId, event_id: &'a EventId, knock_event: &'a MemberEvent) -> Self { + Self { room_id, event_id, knock_event } + } +} + +impl Response { + /// Creates a new `Response` with the given public room metadata state events. + pub fn new(knock_room_state: Vec) -> Self { + Self { knock_room_state } + } +} diff --git a/crates/ruma-federation-api/src/lib.rs b/crates/ruma-federation-api/src/lib.rs index ad025d93..0679ca2f 100644 --- a/crates/ruma-federation-api/src/lib.rs +++ b/crates/ruma-federation-api/src/lib.rs @@ -17,6 +17,9 @@ pub mod directory; pub mod discovery; pub mod event; pub mod keys; +#[cfg(feature = "unstable-pre-spec")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] +pub mod knock; pub mod membership; pub mod openid; pub mod query;