Make conversions from Ruma types to http types generic
So users can select the Body type that makes the most sense for them.
This commit is contained in:
parent
ae26be88c5
commit
f818b53ca1
@ -11,10 +11,10 @@ impl Request {
|
|||||||
lifetimes: &TokenStream,
|
lifetimes: &TokenStream,
|
||||||
ruma_api: &TokenStream,
|
ruma_api: &TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
let bytes = quote! { #ruma_api::exports::bytes };
|
||||||
let http = quote! { #ruma_api::exports::http };
|
let http = quote! { #ruma_api::exports::http };
|
||||||
let percent_encoding = quote! { #ruma_api::exports::percent_encoding };
|
let percent_encoding = quote! { #ruma_api::exports::percent_encoding };
|
||||||
let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
|
let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
|
||||||
let serde_json = quote! { #ruma_api::exports::serde_json };
|
|
||||||
|
|
||||||
let method = &metadata.method;
|
let method = &metadata.method;
|
||||||
let request_path_string = if self.has_path_fields() {
|
let request_path_string = if self.has_path_fields() {
|
||||||
@ -165,7 +165,7 @@ impl Request {
|
|||||||
|
|
||||||
let request_body = if let Some(field) = self.newtype_raw_body_field() {
|
let request_body = if let Some(field) = self.newtype_raw_body_field() {
|
||||||
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
||||||
quote! { self.#field_name }
|
quote! { #ruma_serde::slice_to_buf(&self.#field_name) }
|
||||||
} else if self.has_body_fields() || self.newtype_body_field().is_some() {
|
} else if self.has_body_fields() || self.newtype_body_field().is_some() {
|
||||||
let request_body_initializers = if let Some(field) = self.newtype_body_field() {
|
let request_body_initializers = if let Some(field) = self.newtype_body_field() {
|
||||||
let field_name =
|
let field_name =
|
||||||
@ -177,13 +177,10 @@ impl Request {
|
|||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{
|
#ruma_serde::json_to_buf(&RequestBody #request_body_initializers)?
|
||||||
let request_body = RequestBody #request_body_initializers;
|
|
||||||
#serde_json::to_vec(&request_body)?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! { Vec::new() }
|
quote! { <T as ::std::default::Default>::default() }
|
||||||
};
|
};
|
||||||
|
|
||||||
let non_auth_impls = metadata.authentication.iter().map(|auth| {
|
let non_auth_impls = metadata.authentication.iter().map(|auth| {
|
||||||
@ -210,14 +207,11 @@ impl Request {
|
|||||||
|
|
||||||
const METADATA: #ruma_api::Metadata = self::METADATA;
|
const METADATA: #ruma_api::Metadata = self::METADATA;
|
||||||
|
|
||||||
fn try_into_http_request(
|
fn try_into_http_request<T: ::std::default::Default + #bytes::BufMut>(
|
||||||
self,
|
self,
|
||||||
base_url: &::std::primitive::str,
|
base_url: &::std::primitive::str,
|
||||||
access_token: #ruma_api::SendAccessToken<'_>,
|
access_token: #ruma_api::SendAccessToken<'_>,
|
||||||
) -> ::std::result::Result<
|
) -> ::std::result::Result<#http::Request<T>, #ruma_api::error::IntoHttpError> {
|
||||||
#http::Request<::std::vec::Vec<::std::primitive::u8>>,
|
|
||||||
#ruma_api::error::IntoHttpError,
|
|
||||||
> {
|
|
||||||
let metadata = self::METADATA;
|
let metadata = self::METADATA;
|
||||||
|
|
||||||
let mut req_builder = #http::Request::builder()
|
let mut req_builder = #http::Request::builder()
|
||||||
|
@ -5,8 +5,9 @@ use super::{Response, ResponseField};
|
|||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn expand_outgoing(&self, ruma_api: &TokenStream) -> TokenStream {
|
pub fn expand_outgoing(&self, ruma_api: &TokenStream) -> TokenStream {
|
||||||
|
let bytes = quote! { #ruma_api::exports::bytes };
|
||||||
let http = quote! { #ruma_api::exports::http };
|
let http = quote! { #ruma_api::exports::http };
|
||||||
let serde_json = quote! { #ruma_api::exports::serde_json };
|
let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
|
||||||
|
|
||||||
let serialize_response_headers = self.fields.iter().map(|response_field| {
|
let serialize_response_headers = self.fields.iter().map(|response_field| {
|
||||||
if let ResponseField::Header(field, header_name) = response_field {
|
if let ResponseField::Header(field, header_name) = response_field {
|
||||||
@ -40,11 +41,11 @@ impl Response {
|
|||||||
|
|
||||||
let body = if let Some(field) = self.newtype_raw_body_field() {
|
let body = if let Some(field) = self.newtype_raw_body_field() {
|
||||||
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
||||||
quote! { self.#field_name }
|
quote! { #ruma_serde::slice_to_buf(&self.#field_name) }
|
||||||
} else if let Some(field) = self.newtype_body_field() {
|
} else if let Some(field) = self.newtype_body_field() {
|
||||||
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
|
||||||
quote! {
|
quote! {
|
||||||
#serde_json::to_vec(&self.#field_name)?
|
#ruma_serde::json_to_buf(&self.#field_name)?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let fields = self.fields.iter().map(|response_field| {
|
let fields = self.fields.iter().map(|response_field| {
|
||||||
@ -63,7 +64,7 @@ impl Response {
|
|||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#serde_json::to_vec(&ResponseBody { #(#fields)* })?
|
#ruma_serde::json_to_buf(&ResponseBody { #(#fields)* })?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,12 +73,9 @@ impl Response {
|
|||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
#[allow(clippy::unknown_clippy_lints, clippy::inconsistent_struct_constructor)]
|
#[allow(clippy::unknown_clippy_lints, clippy::inconsistent_struct_constructor)]
|
||||||
impl #ruma_api::OutgoingResponse for Response {
|
impl #ruma_api::OutgoingResponse for Response {
|
||||||
fn try_into_http_response(
|
fn try_into_http_response<T: ::std::default::Default + #bytes::BufMut>(
|
||||||
self,
|
self,
|
||||||
) -> ::std::result::Result<
|
) -> ::std::result::Result<#http::Response<T>, #ruma_api::error::IntoHttpError> {
|
||||||
#http::Response<::std::vec::Vec<::std::primitive::u8>>,
|
|
||||||
#ruma_api::error::IntoHttpError,
|
|
||||||
> {
|
|
||||||
let mut resp_builder = #http::Response::builder()
|
let mut resp_builder = #http::Response::builder()
|
||||||
.header(#http::header::CONTENT_TYPE, "application/json");
|
.header(#http::header::CONTENT_TYPE, "application/json");
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ all-features = true
|
|||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bytes = "1.0.1"
|
||||||
http = "0.2.2"
|
http = "0.2.2"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
ruma-api-macros = { version = "=0.17.0-alpha.4", path = "../ruma-api-macros" }
|
ruma-api-macros = { version = "=0.17.0-alpha.4", path = "../ruma-api-macros" }
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use std::{error::Error as StdError, fmt};
|
use std::{error::Error as StdError, fmt};
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{EndpointError, OutgoingResponse};
|
use crate::{EndpointError, OutgoingResponse};
|
||||||
@ -14,7 +15,9 @@ use crate::{EndpointError, OutgoingResponse};
|
|||||||
pub enum Void {}
|
pub enum Void {}
|
||||||
|
|
||||||
impl OutgoingResponse for Void {
|
impl OutgoingResponse for Void {
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError> {
|
||||||
match self {}
|
match self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ compile_error!("ruma_api's Cargo features only exist as a workaround are not mea
|
|||||||
|
|
||||||
use std::{convert::TryInto as _, error::Error as StdError};
|
use std::{convert::TryInto as _, error::Error as StdError};
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
use http::Method;
|
use http::Method;
|
||||||
use ruma_identifiers::UserId;
|
use ruma_identifiers::UserId;
|
||||||
|
|
||||||
@ -203,6 +204,7 @@ pub mod error;
|
|||||||
/// It is not considered part of ruma-api's public API.
|
/// It is not considered part of ruma-api's public API.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod exports {
|
pub mod exports {
|
||||||
|
pub use bytes;
|
||||||
pub use http;
|
pub use http;
|
||||||
pub use percent_encoding;
|
pub use percent_encoding;
|
||||||
pub use ruma_serde;
|
pub use ruma_serde;
|
||||||
@ -267,11 +269,11 @@ pub trait OutgoingRequest: Sized {
|
|||||||
/// The endpoints path will be appended to the given `base_url`, for example
|
/// The endpoints path will be appended to the given `base_url`, for example
|
||||||
/// `https://matrix.org`. Since all paths begin with a slash, it is not necessary for the
|
/// `https://matrix.org`. Since all paths begin with a slash, it is not necessary for the
|
||||||
/// `base_url` to have a trailing slash. If it has one however, it will be ignored.
|
/// `base_url` to have a trailing slash. If it has one however, it will be ignored.
|
||||||
fn try_into_http_request(
|
fn try_into_http_request<T: Default + BufMut>(
|
||||||
self,
|
self,
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
access_token: SendAccessToken<'_>,
|
access_token: SendAccessToken<'_>,
|
||||||
) -> Result<http::Request<Vec<u8>>, IntoHttpError>;
|
) -> Result<http::Request<T>, IntoHttpError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A response type for a Matrix API endpoint, used for receiving responses.
|
/// A response type for a Matrix API endpoint, used for receiving responses.
|
||||||
@ -291,12 +293,12 @@ pub trait OutgoingRequestAppserviceExt: OutgoingRequest {
|
|||||||
/// [assert Appservice identity][id_assert].
|
/// [assert Appservice identity][id_assert].
|
||||||
///
|
///
|
||||||
/// [id_assert]: https://matrix.org/docs/spec/application_service/r0.1.2#identity-assertion
|
/// [id_assert]: https://matrix.org/docs/spec/application_service/r0.1.2#identity-assertion
|
||||||
fn try_into_http_request_with_user_id(
|
fn try_into_http_request_with_user_id<T: Default + BufMut>(
|
||||||
self,
|
self,
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
access_token: SendAccessToken<'_>,
|
access_token: SendAccessToken<'_>,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
) -> Result<http::Request<Vec<u8>>, IntoHttpError> {
|
) -> Result<http::Request<T>, IntoHttpError> {
|
||||||
let mut http_request = self.try_into_http_request(base_url, access_token)?;
|
let mut http_request = self.try_into_http_request(base_url, access_token)?;
|
||||||
let user_id_query =
|
let user_id_query =
|
||||||
ruma_serde::urlencoded::to_string(&[("user_id", &user_id.into_string())])?;
|
ruma_serde::urlencoded::to_string(&[("user_id", &user_id.into_string())])?;
|
||||||
@ -346,7 +348,9 @@ pub trait OutgoingResponse {
|
|||||||
///
|
///
|
||||||
/// This method should only fail when when invalid header values are specified. It may also
|
/// This method should only fail when when invalid header values are specified. It may also
|
||||||
/// fail with a serialization error in case of bugs in Ruma though.
|
/// fail with a serialization error in case of bugs in Ruma though.
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError>;
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives users the ability to define their own serializable / deserializable errors.
|
/// Gives users the ability to define their own serializable / deserializable errors.
|
||||||
|
@ -48,8 +48,10 @@ fn request_serde() {
|
|||||||
user: user_id!("@bazme:ruma.io"),
|
user: user_id!("@bazme:ruma.io"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let http_req =
|
let http_req = req
|
||||||
req.clone().try_into_http_request("https://homeserver.tld", SendAccessToken::None).unwrap();
|
.clone()
|
||||||
|
.try_into_http_request::<Vec<u8>>("https://homeserver.tld", SendAccessToken::None)
|
||||||
|
.unwrap();
|
||||||
let req2 = Request::try_from_http_request(http_req).unwrap();
|
let req2 = Request::try_from_http_request(http_req).unwrap();
|
||||||
|
|
||||||
assert_eq!(req.hello, req2.hello);
|
assert_eq!(req.hello, req2.hello);
|
||||||
@ -73,7 +75,7 @@ fn request_with_user_id_serde() {
|
|||||||
|
|
||||||
let user_id = user_id!("@_virtual_:ruma.io");
|
let user_id = user_id!("@_virtual_:ruma.io");
|
||||||
let http_req = req
|
let http_req = req
|
||||||
.try_into_http_request_with_user_id(
|
.try_into_http_request_with_user_id::<Vec<u8>>(
|
||||||
"https://homeserver.tld",
|
"https://homeserver.tld",
|
||||||
SendAccessToken::None,
|
SendAccessToken::None,
|
||||||
user_id,
|
user_id,
|
||||||
@ -131,7 +133,7 @@ mod without_query {
|
|||||||
|
|
||||||
let user_id = user_id!("@_virtual_:ruma.io");
|
let user_id = user_id!("@_virtual_:ruma.io");
|
||||||
let http_req = req
|
let http_req = req
|
||||||
.try_into_http_request_with_user_id(
|
.try_into_http_request_with_user_id::<Vec<u8>>(
|
||||||
"https://homeserver.tld",
|
"https://homeserver.tld",
|
||||||
SendAccessToken::None,
|
SendAccessToken::None,
|
||||||
user_id,
|
user_id,
|
||||||
|
@ -28,7 +28,7 @@ ruma_api! {
|
|||||||
#[test]
|
#[test]
|
||||||
fn response_content_type_override() {
|
fn response_content_type_override() {
|
||||||
let res = Response { stuff: "magic".into() };
|
let res = Response { stuff: "magic".into() };
|
||||||
let mut http_res = res.try_into_http_response().unwrap();
|
let mut http_res = res.try_into_http_response::<Vec<u8>>().unwrap();
|
||||||
|
|
||||||
// Test that we correctly replaced the default content type,
|
// Test that we correctly replaced the default content type,
|
||||||
// not adding another content-type header.
|
// not adding another content-type header.
|
||||||
@ -45,8 +45,9 @@ fn response_content_type_override() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn request_content_type_override() {
|
fn request_content_type_override() {
|
||||||
let req = Request { location: None, stuff: "magic".into() };
|
let req = Request { location: None, stuff: "magic".into() };
|
||||||
let mut http_req =
|
let mut http_req = req
|
||||||
req.try_into_http_request("https://homeserver.tld", SendAccessToken::None).unwrap();
|
.try_into_http_request::<Vec<u8>>("https://homeserver.tld", SendAccessToken::None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
match http_req.headers_mut().entry(CONTENT_TYPE) {
|
match http_req.headers_mut().entry(CONTENT_TYPE) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
use http::{header::CONTENT_TYPE, method::Method};
|
use http::{header::CONTENT_TYPE, method::Method};
|
||||||
use ruma_api::{
|
use ruma_api::{
|
||||||
error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError, ServerError, Void},
|
error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError, ServerError, Void},
|
||||||
@ -38,11 +39,11 @@ impl OutgoingRequest for Request {
|
|||||||
|
|
||||||
const METADATA: Metadata = METADATA;
|
const METADATA: Metadata = METADATA;
|
||||||
|
|
||||||
fn try_into_http_request(
|
fn try_into_http_request<T: Default + BufMut>(
|
||||||
self,
|
self,
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
_access_token: SendAccessToken<'_>,
|
_access_token: SendAccessToken<'_>,
|
||||||
) -> Result<http::Request<Vec<u8>>, IntoHttpError> {
|
) -> Result<http::Request<T>, IntoHttpError> {
|
||||||
let url = (base_url.to_owned() + METADATA.path)
|
let url = (base_url.to_owned() + METADATA.path)
|
||||||
.replace(":room_alias", &self.room_alias.to_string());
|
.replace(":room_alias", &self.room_alias.to_string());
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ impl OutgoingRequest for Request {
|
|||||||
let http_request = http::Request::builder()
|
let http_request = http::Request::builder()
|
||||||
.method(METADATA.method)
|
.method(METADATA.method)
|
||||||
.uri(url)
|
.uri(url)
|
||||||
.body(serde_json::to_vec(&request_body)?)
|
.body(ruma_serde::json_to_buf(&request_body)?)
|
||||||
// this cannot fail because we don't give user-supplied data to any of the
|
// this cannot fail because we don't give user-supplied data to any of the
|
||||||
// builder methods
|
// builder methods
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -113,10 +114,12 @@ impl IncomingResponse for Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OutgoingResponse for Response {
|
impl OutgoingResponse for Response {
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError> {
|
||||||
let response = http::Response::builder()
|
let response = http::Response::builder()
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.body(b"{}".to_vec())
|
.body(ruma_serde::slice_to_buf(b"{}"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
@ -17,8 +17,9 @@ ruma_api! {
|
|||||||
#[test]
|
#[test]
|
||||||
fn empty_request_http_repr() {
|
fn empty_request_http_repr() {
|
||||||
let req = Request {};
|
let req = Request {};
|
||||||
let http_req =
|
let http_req = req
|
||||||
req.try_into_http_request("https://homeserver.tld", SendAccessToken::None).unwrap();
|
.try_into_http_request::<Vec<u8>>("https://homeserver.tld", SendAccessToken::None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(http_req.body().is_empty());
|
assert!(http_req.body().is_empty());
|
||||||
}
|
}
|
||||||
@ -26,7 +27,7 @@ fn empty_request_http_repr() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn empty_response_http_repr() {
|
fn empty_response_http_repr() {
|
||||||
let res = Response {};
|
let res = Response {};
|
||||||
let http_res = res.try_into_http_response().unwrap();
|
let http_res = res.try_into_http_response::<Vec<u8>>().unwrap();
|
||||||
|
|
||||||
assert_eq!(http_res.body(), b"{}");
|
assert_eq!(http_res.body(), b"{}");
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use bytes::BufMut;
|
||||||
use ruma_api::{
|
use ruma_api::{
|
||||||
error::{FromHttpResponseError, IntoHttpError, Void},
|
error::{FromHttpResponseError, IntoHttpError, Void},
|
||||||
ruma_api, IncomingResponse, OutgoingResponse,
|
ruma_api, IncomingResponse, OutgoingResponse,
|
||||||
@ -35,7 +36,9 @@ impl IncomingResponse for Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OutgoingResponse for Response {
|
impl OutgoingResponse for Response {
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
assign = "1.1.1"
|
assign = "1.1.1"
|
||||||
|
bytes = "1.0.1"
|
||||||
http = "0.2.2"
|
http = "0.2.2"
|
||||||
js_int = { version = "0.2.0", features = ["serde"] }
|
js_int = { version = "0.2.0", features = ["serde"] }
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
use std::{collections::BTreeMap, fmt, time::Duration};
|
use std::{collections::BTreeMap, fmt, time::Duration};
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
use ruma_api::{
|
use ruma_api::{
|
||||||
error::{IntoHttpError, ResponseDeserializationError},
|
error::{IntoHttpError, ResponseDeserializationError},
|
||||||
EndpointError, OutgoingResponse,
|
EndpointError, OutgoingResponse,
|
||||||
};
|
};
|
||||||
use ruma_identifiers::RoomVersionId;
|
use ruma_identifiers::RoomVersionId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{from_slice as from_json_slice, to_vec as to_json_vec, Value as JsonValue};
|
use serde_json::{from_slice as from_json_slice, Value as JsonValue};
|
||||||
|
|
||||||
/// Deserialize and Serialize implementations for ErrorKind.
|
/// Deserialize and Serialize implementations for ErrorKind.
|
||||||
/// Separate module because it's a lot of code.
|
/// Separate module because it's a lot of code.
|
||||||
@ -236,11 +237,13 @@ impl ErrorBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OutgoingResponse for Error {
|
impl OutgoingResponse for Error {
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError> {
|
||||||
http::Response::builder()
|
http::Response::builder()
|
||||||
.header(http::header::CONTENT_TYPE, "application/json")
|
.header(http::header::CONTENT_TYPE, "application/json")
|
||||||
.status(self.status_code)
|
.status(self.status_code)
|
||||||
.body(to_json_vec(&ErrorBody::from(self))?)
|
.body(ruma_serde::json_to_buf(&ErrorBody::from(self))?)
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,10 @@ mod tests {
|
|||||||
since: Some("hello"),
|
since: Some("hello"),
|
||||||
server: Some(&server_name!("test.tld")),
|
server: Some(&server_name!("test.tld")),
|
||||||
}
|
}
|
||||||
.try_into_http_request("https://homeserver.tld", SendAccessToken::IfRequired("auth_tok"))
|
.try_into_http_request::<Vec<u8>>(
|
||||||
|
"https://homeserver.tld",
|
||||||
|
SendAccessToken::IfRequired("auth_tok"),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let uri = req.uri();
|
let uri = req.uri();
|
||||||
@ -107,7 +110,7 @@ mod tests {
|
|||||||
prev_batch: Some("prev_batch_token".into()),
|
prev_batch: Some("prev_batch_token".into()),
|
||||||
total_room_count_estimate: Some(uint!(10)),
|
total_room_count_estimate: Some(uint!(10)),
|
||||||
}
|
}
|
||||||
.try_into_http_response()
|
.try_into_http_response::<Vec<u8>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -191,7 +191,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let request = req
|
let request = req
|
||||||
.try_into_http_request(
|
.try_into_http_request::<Vec<u8>>(
|
||||||
"https://homeserver.tld",
|
"https://homeserver.tld",
|
||||||
SendAccessToken::IfRequired("auth_tok"),
|
SendAccessToken::IfRequired("auth_tok"),
|
||||||
)
|
)
|
||||||
|
@ -60,7 +60,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn serialize_sso_login_with_provider_request_uri() {
|
fn serialize_sso_login_with_provider_request_uri() {
|
||||||
let req = Request { idp_id: "provider", redirect_url: "https://example.com/sso" }
|
let req = Request { idp_id: "provider", redirect_url: "https://example.com/sso" }
|
||||||
.try_into_http_request("https://homeserver.tld", SendAccessToken::None)
|
.try_into_http_request::<Vec<u8>>("https://homeserver.tld", SendAccessToken::None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! [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)
|
//! [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 bytes::BufMut;
|
||||||
use ruma_api::{ruma_api, SendAccessToken};
|
use ruma_api::{ruma_api, SendAccessToken};
|
||||||
use ruma_events::{AnyStateEventContent, EventType};
|
use ruma_events::{AnyStateEventContent, EventType};
|
||||||
use ruma_identifiers::RoomId;
|
use ruma_identifiers::RoomId;
|
||||||
@ -65,14 +66,14 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> {
|
|||||||
|
|
||||||
const METADATA: ruma_api::Metadata = METADATA;
|
const METADATA: ruma_api::Metadata = METADATA;
|
||||||
|
|
||||||
fn try_into_http_request(
|
fn try_into_http_request<T: Default + BufMut>(
|
||||||
self,
|
self,
|
||||||
base_url: &str,
|
base_url: &str,
|
||||||
access_token: SendAccessToken<'_>,
|
access_token: SendAccessToken<'_>,
|
||||||
) -> Result<http::Request<Vec<u8>>, ruma_api::error::IntoHttpError> {
|
) -> Result<http::Request<T>, ruma_api::error::IntoHttpError> {
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use http::header::{HeaderValue, AUTHORIZATION, CONTENT_TYPE};
|
use http::header::{self, HeaderValue};
|
||||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||||
|
|
||||||
let mut url = format!(
|
let mut url = format!(
|
||||||
@ -90,9 +91,9 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> {
|
|||||||
http::Request::builder()
|
http::Request::builder()
|
||||||
.method(http::Method::GET)
|
.method(http::Method::GET)
|
||||||
.uri(url)
|
.uri(url)
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(header::CONTENT_TYPE, "application/json")
|
||||||
.header(
|
.header(
|
||||||
AUTHORIZATION,
|
header::AUTHORIZATION,
|
||||||
HeaderValue::from_str(&format!(
|
HeaderValue::from_str(&format!(
|
||||||
"Bearer {}",
|
"Bearer {}",
|
||||||
access_token
|
access_token
|
||||||
@ -100,7 +101,7 @@ impl<'a> ruma_api::OutgoingRequest for Request<'a> {
|
|||||||
.ok_or(ruma_api::error::IntoHttpError::NeedsAuthentication)?,
|
.ok_or(ruma_api::error::IntoHttpError::NeedsAuthentication)?,
|
||||||
))?,
|
))?,
|
||||||
)
|
)
|
||||||
.body(Vec::new())
|
.body(T::default())
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ mod server_tests {
|
|||||||
tags.insert("u.user_tag".into(), assign!(TagInfo::new(), { order: Some(0.11) }));
|
tags.insert("u.user_tag".into(), assign!(TagInfo::new(), { order: Some(0.11) }));
|
||||||
let response = Response { tags };
|
let response = Response { tags };
|
||||||
|
|
||||||
let http_response = response.try_into_http_response().unwrap();
|
let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
|
||||||
|
|
||||||
let json_response: serde_json::Value =
|
let json_response: serde_json::Value =
|
||||||
serde_json::from_slice(http_response.body()).unwrap();
|
serde_json::from_slice(http_response.body()).unwrap();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use std::{collections::BTreeMap, fmt};
|
use std::{collections::BTreeMap, fmt};
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
use ruma_api::{
|
use ruma_api::{
|
||||||
error::{IntoHttpError, ResponseDeserializationError},
|
error::{IntoHttpError, ResponseDeserializationError},
|
||||||
EndpointError, OutgoingResponse,
|
EndpointError, OutgoingResponse,
|
||||||
@ -9,8 +10,7 @@ use ruma_api::{
|
|||||||
use ruma_serde::Outgoing;
|
use ruma_serde::Outgoing;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{
|
use serde_json::{
|
||||||
from_slice as from_json_slice, to_vec as to_json_vec, value::RawValue as RawJsonValue,
|
from_slice as from_json_slice, value::RawValue as RawJsonValue, Value as JsonValue,
|
||||||
Value as JsonValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::{Error as MatrixError, ErrorBody};
|
use crate::error::{Error as MatrixError, ErrorBody};
|
||||||
@ -150,12 +150,14 @@ impl EndpointError for UiaaResponse {
|
|||||||
impl std::error::Error for UiaaResponse {}
|
impl std::error::Error for UiaaResponse {}
|
||||||
|
|
||||||
impl OutgoingResponse for UiaaResponse {
|
impl OutgoingResponse for UiaaResponse {
|
||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
fn try_into_http_response<T: Default + BufMut>(
|
||||||
|
self,
|
||||||
|
) -> Result<http::Response<T>, IntoHttpError> {
|
||||||
match self {
|
match self {
|
||||||
UiaaResponse::AuthResponse(authentication_info) => http::Response::builder()
|
UiaaResponse::AuthResponse(authentication_info) => http::Response::builder()
|
||||||
.header(http::header::CONTENT_TYPE, "application/json")
|
.header(http::header::CONTENT_TYPE, "application/json")
|
||||||
.status(&http::StatusCode::UNAUTHORIZED)
|
.status(&http::StatusCode::UNAUTHORIZED)
|
||||||
.body(to_json_vec(&authentication_info)?)
|
.body(ruma_serde::json_to_buf(&authentication_info)?)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
UiaaResponse::MatrixError(error) => error.try_into_http_response(),
|
UiaaResponse::MatrixError(error) => error.try_into_http_response(),
|
||||||
}
|
}
|
||||||
@ -336,7 +338,8 @@ mod tests {
|
|||||||
session: None,
|
session: None,
|
||||||
auth_error: None,
|
auth_error: None,
|
||||||
};
|
};
|
||||||
let uiaa_response = UiaaResponse::AuthResponse(uiaa_info).try_into_http_response().unwrap();
|
let uiaa_response =
|
||||||
|
UiaaResponse::AuthResponse(uiaa_info).try_into_http_response::<Vec<u8>>().unwrap();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
from_json_slice::<UiaaInfo>(uiaa_response.body()).unwrap(),
|
from_json_slice::<UiaaInfo>(uiaa_response.body()).unwrap(),
|
||||||
|
@ -357,7 +357,10 @@ impl Client {
|
|||||||
SendAccessToken::None
|
SendAccessToken::None
|
||||||
};
|
};
|
||||||
|
|
||||||
request.try_into_http_request(&client.homeserver_url.to_string(), access_token)?
|
request.try_into_http_request::<Vec<u8>>(
|
||||||
|
&client.homeserver_url.to_string(),
|
||||||
|
access_token,
|
||||||
|
)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let extra_params = urlencoded::to_string(extra_params).unwrap();
|
let extra_params = urlencoded::to_string(extra_params).unwrap();
|
||||||
|
@ -57,7 +57,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn response_body() {
|
fn response_body() {
|
||||||
let res = Response::new().try_into_http_response().unwrap();
|
let res = Response::new().try_into_http_response::<Vec<u8>>().unwrap();
|
||||||
|
|
||||||
assert_eq!(res.body(), b"{}");
|
assert_eq!(res.body(), b"{}");
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ version = "0.3.1"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bytes = "1.0.1"
|
||||||
form_urlencoded = "1.0.0"
|
form_urlencoded = "1.0.0"
|
||||||
js_int = { version = "0.2.0", features = ["serde"] }
|
js_int = { version = "0.2.0", features = ["serde"] }
|
||||||
itoa = "0.4.6"
|
itoa = "0.4.6"
|
||||||
|
16
ruma-serde/src/buf.rs
Normal file
16
ruma-serde/src/buf.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use bytes::BufMut;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
/// Converts a byte slice to a buffer by copying.
|
||||||
|
pub fn slice_to_buf<B: Default + BufMut>(s: &[u8]) -> B {
|
||||||
|
let mut buf = B::default();
|
||||||
|
buf.put_slice(s);
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a buffer and writes a serializable value to it.
|
||||||
|
pub fn json_to_buf<B: Default + BufMut, T: Serialize>(val: &T) -> serde_json::Result<B> {
|
||||||
|
let mut buf = B::default().writer();
|
||||||
|
serde_json::to_writer(&mut buf, val)?;
|
||||||
|
Ok(buf.into_inner())
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
|
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
|
||||||
//! (De)serialization helpers for other ruma crates.
|
//! (De)serialization helpers for other ruma crates.
|
||||||
|
|
||||||
|
mod buf;
|
||||||
pub mod can_be_empty;
|
pub mod can_be_empty;
|
||||||
mod canonical_json;
|
mod canonical_json;
|
||||||
mod cow;
|
mod cow;
|
||||||
@ -15,6 +16,7 @@ pub mod test;
|
|||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod urlencoded;
|
pub mod urlencoded;
|
||||||
|
|
||||||
|
pub use buf::{json_to_buf, slice_to_buf};
|
||||||
pub use can_be_empty::{is_empty, CanBeEmpty};
|
pub use can_be_empty::{is_empty, CanBeEmpty};
|
||||||
pub use canonical_json::{
|
pub use canonical_json::{
|
||||||
to_canonical_value, to_string as to_canonical_json_string, try_from_json_map,
|
to_canonical_value, to_string as to_canonical_json_string, try_from_json_map,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user