From 2f1b9f097930bf7908ca539f2ab7bb0ccf5d8b25 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 5 Apr 2021 16:01:38 +0200 Subject: [PATCH] client-api: Merge _for_empty_key endpoints into their more general siblings --- .../src/r0/message/send_message_event.rs | 2 +- ruma-client-api/src/r0/state.rs | 4 +- .../state/get_state_events_for_empty_key.rs | 51 ------- .../src/r0/state/get_state_events_for_key.rs | 139 +++++++++++++++-- ...e_event_for_key.rs => send_state_event.rs} | 30 ++-- .../state/send_state_event_for_empty_key.rs | 144 ------------------ 6 files changed, 143 insertions(+), 227 deletions(-) delete mode 100644 ruma-client-api/src/r0/state/get_state_events_for_empty_key.rs rename ruma-client-api/src/r0/state/{send_state_event_for_key.rs => send_state_event.rs} (87%) delete mode 100644 ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs diff --git a/ruma-client-api/src/r0/message/send_message_event.rs b/ruma-client-api/src/r0/message/send_message_event.rs index d5619938..06f53982 100644 --- a/ruma-client-api/src/r0/message/send_message_event.rs +++ b/ruma-client-api/src/r0/message/send_message_event.rs @@ -88,6 +88,7 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> { utf8_percent_encode(self.content.event_type(), NON_ALPHANUMERIC), utf8_percent_encode(&self.txn_id, NON_ALPHANUMERIC), )) + .header(CONTENT_TYPE, "application/json") .header( AUTHORIZATION, HeaderValue::from_str(&format!( @@ -95,7 +96,6 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> { access_token.ok_or(IntoHttpError::NeedsAuthentication)? ))?, ) - .header(CONTENT_TYPE, "application/json") .body(serde_json::to_vec(&self.content)?)?; Ok(http_request) diff --git a/ruma-client-api/src/r0/state.rs b/ruma-client-api/src/r0/state.rs index bc3b8cd0..a2a386ad 100644 --- a/ruma-client-api/src/r0/state.rs +++ b/ruma-client-api/src/r0/state.rs @@ -1,7 +1,5 @@ //! Endpoints for managing room state pub mod get_state_events; -pub mod get_state_events_for_empty_key; pub mod get_state_events_for_key; -pub mod send_state_event_for_empty_key; -pub mod send_state_event_for_key; +pub mod send_state_event; diff --git a/ruma-client-api/src/r0/state/get_state_events_for_empty_key.rs b/ruma-client-api/src/r0/state/get_state_events_for_empty_key.rs deleted file mode 100644 index b11c0074..00000000 --- a/ruma-client-api/src/r0/state/get_state_events_for_empty_key.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-state-eventtype) - -use ruma_api::ruma_api; -use ruma_events::EventType; -use ruma_identifiers::RoomId; -use serde_json::value::RawValue as RawJsonValue; - -ruma_api! { - metadata: { - description: "Get state events of a given type associated with the empty key.", - method: GET, - name: "get_state_events_for_empty_key", - path: "/_matrix/client/r0/rooms/:room_id/state/:event_type", - rate_limited: false, - authentication: AccessToken, - } - - request: { - /// The room to look up the state for. - #[ruma_api(path)] - pub room_id: &'a RoomId, - - /// The type of state to look up. - #[ruma_api(path)] - pub event_type: EventType, - } - - response: { - /// The content of the state event. - /// - /// To create a `Box`, use `serde_json::value::to_raw_value`. - #[ruma_api(body)] - pub content: Box, - } - - error: crate::Error -} - -impl<'a> Request<'a> { - /// Creates a new `Request` with the given room ID and event type. - pub fn new(room_id: &'a RoomId, event_type: EventType) -> Self { - Self { room_id, event_type } - } -} - -impl Response { - /// Creates a new `Response` with the given content. - pub fn new(content: Box) -> Self { - Self { content } - } -} diff --git a/ruma-client-api/src/r0/state/get_state_events_for_key.rs b/ruma-client-api/src/r0/state/get_state_events_for_key.rs index 2caaa912..b4600da5 100644 --- a/ruma-client-api/src/r0/state/get_state_events_for_key.rs +++ b/ruma-client-api/src/r0/state/get_state_events_for_key.rs @@ -1,8 +1,14 @@ -//! [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-state-eventtype-state-key) +//! [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey) -use ruma_api::ruma_api; +use std::{borrow::Cow, convert::TryFrom}; + +use ruma_api::{ + error::{FromHttpRequestError, IntoHttpError, RequestDeserializationError}, + ruma_api, Metadata, +}; use ruma_events::EventType; use ruma_identifiers::RoomId; +use ruma_serde::Outgoing; use serde_json::value::RawValue as RawJsonValue; ruma_api! { @@ -15,20 +21,6 @@ ruma_api! { authentication: AccessToken, } - request: { - /// The room to look up the state for. - #[ruma_api(path)] - pub room_id: &'a RoomId, - - /// The type of state to look up. - #[ruma_api(path)] - pub event_type: EventType, - - /// The key of the state to look up. - #[ruma_api(path)] - pub state_key: &'a str, - } - response: { /// The content of the state event. #[ruma_api(body)] @@ -38,6 +30,23 @@ ruma_api! { error: crate::Error } +/// Data for a request to the `get_state_events_for_key` API endpoint. +/// +/// Get state events associated with a given key. +#[derive(Clone, Debug, Outgoing)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +#[incoming_derive(!Deserialize)] +pub struct Request<'a> { + /// The room to look up the state for. + pub room_id: &'a RoomId, + + /// The type of state to look up. + pub event_type: EventType, + + /// The key of the state to look up. + pub state_key: &'a str, +} + impl<'a> Request<'a> { /// Creates a new `Request` with the given room ID, event type and state key. pub fn new(room_id: &'a RoomId, event_type: EventType, state_key: &'a str) -> Self { @@ -51,3 +60,101 @@ impl Response { Self { content } } } + +#[cfg(feature = "client")] +impl<'a> ruma_api::OutgoingRequest for Request<'a> { + type EndpointError = crate::Error; + type IncomingResponse = ::Incoming; + + const METADATA: Metadata = METADATA; + + fn try_into_http_request( + self, + base_url: &str, + access_token: Option<&str>, + ) -> Result>, IntoHttpError> { + use http::header::{HeaderValue, AUTHORIZATION, CONTENT_TYPE}; + use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; + + let mut url = format!( + "{}/_matrix/client/r0/rooms/{}/state/{}", + base_url.strip_suffix('/').unwrap_or(base_url), + utf8_percent_encode(&self.room_id.to_string(), NON_ALPHANUMERIC,), + utf8_percent_encode(&self.event_type.to_string(), NON_ALPHANUMERIC,) + ); + + if !self.state_key.is_empty() { + url.push('/'); + url.push_str(&Cow::from(utf8_percent_encode(&self.state_key, NON_ALPHANUMERIC))); + } + + http::Request::builder() + .method(http::Method::GET) + .uri(url) + .header(CONTENT_TYPE, "application/json") + .header( + AUTHORIZATION, + HeaderValue::from_str(&format!( + "Bearer {}", + access_token.ok_or(IntoHttpError::NeedsAuthentication)? + ))?, + ) + .body(Vec::new()) + .map_err(Into::into) + } +} + +#[cfg(feature = "server")] +impl ruma_api::IncomingRequest for IncomingRequest { + type EndpointError = crate::Error; + type OutgoingResponse = Response; + + const METADATA: Metadata = METADATA; + + fn try_from_http_request( + request: http::Request>, + ) -> Result { + let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect(); + + let room_id = { + let decoded = + match percent_encoding::percent_decode(path_segments[4].as_bytes()).decode_utf8() { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + }; + + match RoomId::try_from(&*decoded) { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + } + }; + + let event_type = { + let decoded = + match percent_encoding::percent_decode(path_segments[6].as_bytes()).decode_utf8() { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + }; + + match EventType::try_from(&*decoded) { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + } + }; + + let state_key = { + let decoded = + match percent_encoding::percent_decode(path_segments[7].as_bytes()).decode_utf8() { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + }; + + match String::try_from(&*decoded) { + Ok(val) => val, + Err(err) => return Err(RequestDeserializationError::new(err, request).into()), + } + }; + + Ok(Self { room_id, event_type, state_key }) + } +} diff --git a/ruma-client-api/src/r0/state/send_state_event_for_key.rs b/ruma-client-api/src/r0/state/send_state_event.rs similarity index 87% rename from ruma-client-api/src/r0/state/send_state_event_for_key.rs rename to ruma-client-api/src/r0/state/send_state_event.rs index 848d68a4..345833ee 100644 --- a/ruma-client-api/src/r0/state/send_state_event_for_key.rs +++ b/ruma-client-api/src/r0/state/send_state_event.rs @@ -1,6 +1,6 @@ //! [PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey) -use std::convert::TryFrom; +use std::{borrow::Cow, convert::TryFrom}; use ruma_api::{ error::{FromHttpRequestError, IntoHttpError, RequestDeserializationError}, @@ -15,7 +15,7 @@ ruma_api! { metadata: { description: "Send a state event to a room associated with a given state key.", method: PUT, - name: "send_state_event_for_key", + name: "send_state_event", path: "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key", rate_limited: false, authentication: AccessToken, @@ -29,7 +29,7 @@ ruma_api! { error: crate::Error } -/// Data for a request to the `send_state_event_for_key` API endpoint. +/// Data for a request to the `send_state_event` API endpoint. /// /// Send a state event to a room associated with a given state key. #[derive(Clone, Debug, Outgoing)] @@ -39,7 +39,7 @@ pub struct Request<'a> { /// The room to set the state in. pub room_id: &'a RoomId, - /// The state_key for the state to send. Defaults to the empty string. + /// The state_key for the state to send. pub state_key: &'a str, /// The event content to send. @@ -75,15 +75,22 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> { use http::header::{HeaderValue, AUTHORIZATION, CONTENT_TYPE}; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; + let mut url = format!( + "{}/_matrix/client/r0/rooms/{}/state/{}", + base_url.strip_suffix('/').unwrap_or(base_url), + utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC), + utf8_percent_encode(self.content.event_type(), NON_ALPHANUMERIC), + ); + + if !self.state_key.is_empty() { + url.push('/'); + url.push_str(&Cow::from(utf8_percent_encode(&self.state_key, NON_ALPHANUMERIC))); + } + let http_request = http::Request::builder() .method(http::Method::PUT) - .uri(format!( - "{}/_matrix/client/r0/rooms/{}/state/{}/{}", - base_url.strip_suffix('/').unwrap_or(base_url), - utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC), - utf8_percent_encode(self.content.event_type(), NON_ALPHANUMERIC), - utf8_percent_encode(&self.state_key, NON_ALPHANUMERIC), - )) + .uri(url) + .header(CONTENT_TYPE, "application/json") .header( AUTHORIZATION, HeaderValue::from_str(&format!( @@ -91,7 +98,6 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> { access_token.ok_or(IntoHttpError::NeedsAuthentication)? ))?, ) - .header(CONTENT_TYPE, "application/json") .body(serde_json::to_vec(&self.content)?)?; Ok(http_request) diff --git a/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs b/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs deleted file mode 100644 index a10dd346..00000000 --- a/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! [PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-state-eventtype) - -use std::convert::TryFrom; - -use ruma_api::{ - error::{FromHttpRequestError, IntoHttpError, RequestDeserializationError}, - ruma_api, Metadata, -}; -use ruma_events::{AnyStateEventContent, EventContent as _}; -use ruma_identifiers::{EventId, RoomId}; -use ruma_serde::Outgoing; -use serde_json::value::RawValue as RawJsonValue; - -ruma_api! { - metadata: { - description: "Send a state event to a room associated with the empty state key.", - method: PUT, - name: "send_state_event_for_empty_key", - path: "/_matrix/client/r0/rooms/:room_id/state/:event_type", - rate_limited: false, - authentication: AccessToken, - } - - response: { - /// A unique identifier for the event. - pub event_id: EventId, - } - - error: crate::Error -} - -/// Data for a request to the `send_state_event_for_empty_key` API endpoint. -/// -/// Send a state event to a room associated with the empty state key. -#[derive(Clone, Debug, Outgoing)] -#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[incoming_derive(!Deserialize)] -pub struct Request<'a> { - /// The room to set the state in. - pub room_id: &'a RoomId, - - /// The event content to send. - pub content: &'a AnyStateEventContent, -} - -impl<'a> Request<'a> { - /// Creates a new `Request` with the given room id and event content. - pub fn new(room_id: &'a RoomId, content: &'a AnyStateEventContent) -> Self { - Self { room_id, content } - } -} - -impl Response { - /// Creates a new `Response` with the given event id. - pub fn new(event_id: EventId) -> Self { - Self { event_id } - } -} - -#[cfg(feature = "client")] -impl<'a> ruma_api::OutgoingRequest for Request<'a> { - type EndpointError = crate::Error; - type IncomingResponse = Response; - - const METADATA: Metadata = METADATA; - - fn try_into_http_request( - self, - base_url: &str, - access_token: Option<&str>, - ) -> Result>, IntoHttpError> { - use http::header::{HeaderValue, AUTHORIZATION, CONTENT_TYPE}; - use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; - - let http_request = http::Request::builder() - .method(http::Method::PUT) - .uri(format!( - "{}/_matrix/client/r0/rooms/{}/state/{}", - base_url.strip_suffix('/').unwrap_or(base_url), - utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC), - utf8_percent_encode(self.content.event_type(), NON_ALPHANUMERIC), - )) - .header( - AUTHORIZATION, - HeaderValue::from_str(&format!( - "Bearer {}", - access_token.ok_or(IntoHttpError::NeedsAuthentication)? - ))?, - ) - .header(CONTENT_TYPE, "application/json") - .body(serde_json::to_vec(&self.content)?)?; - - Ok(http_request) - } -} - -#[cfg(feature = "server")] -impl ruma_api::IncomingRequest for IncomingRequest { - type EndpointError = crate::Error; - type OutgoingResponse = Response; - - const METADATA: Metadata = METADATA; - - fn try_from_http_request( - request: http::Request>, - ) -> Result { - let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect(); - - let room_id = { - let decoded = - match percent_encoding::percent_decode(path_segments[4].as_bytes()).decode_utf8() { - Ok(val) => val, - Err(err) => return Err(RequestDeserializationError::new(err, request).into()), - }; - - match RoomId::try_from(&*decoded) { - Ok(val) => val, - Err(err) => return Err(RequestDeserializationError::new(err, request).into()), - } - }; - - let content = { - let request_body: Box = - match serde_json::from_slice(request.body().as_slice()) { - Ok(val) => val, - Err(err) => return Err(RequestDeserializationError::new(err, request).into()), - }; - - let event_type = { - match percent_encoding::percent_decode(path_segments[6].as_bytes()).decode_utf8() { - Ok(val) => val, - Err(err) => return Err(RequestDeserializationError::new(err, request).into()), - } - }; - - match AnyStateEventContent::from_parts(&event_type, request_body) { - Ok(content) => content, - Err(err) => return Err(RequestDeserializationError::new(err, request).into()), - } - }; - - Ok(Self { room_id, content }) - } -}