Add convertion to/from Request/Response from/to http::Request/Response

This commit is contained in:
Jonas Herzig 2018-09-11 14:02:09 +02:00
parent 74dad12056
commit c71b60ef70
2 changed files with 72 additions and 7 deletions

View File

@ -16,8 +16,9 @@ http = "0.1.0"
hyper = "0.12" hyper = "0.12"
serde_json = "1.0.3" serde_json = "1.0.3"
serde_urlencoded = "0.5.1" serde_urlencoded = "0.5.1"
ruma-identifiers = "0.11"
[dev-dependencies] [dev-dependencies]
ruma-identifiers = "0.11"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
url = "1.7"

View File

@ -15,13 +15,16 @@
extern crate futures; extern crate futures;
extern crate http; extern crate http;
extern crate hyper; extern crate hyper;
#[cfg(test)]
extern crate ruma_identifiers; extern crate ruma_identifiers;
#[cfg(test)] #[cfg(test)]
extern crate serde;
#[cfg(test)]
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate serde_json; extern crate serde_json;
extern crate serde_urlencoded; extern crate serde_urlencoded;
#[cfg(test)]
extern crate url;
use std::convert::TryInto; use std::convert::TryInto;
use std::io; use std::io;
@ -33,9 +36,9 @@ use hyper::Body;
/// A Matrix API endpoint. /// A Matrix API endpoint.
pub trait Endpoint<T = Body, U = Body> { pub trait Endpoint<T = Body, U = Body> {
/// Data needed to make a request to the endpoint. /// Data needed to make a request to the endpoint.
type Request: TryInto<Request<T>, Error = Error>; type Request: TryInto<Request<T>, Error = Error> + FutureFrom<Request<T>, Error = Error>;
/// Data returned from the endpoint. /// Data returned from the endpoint.
type Response: FutureFrom<Response<U>, Error = Error>; type Response: FutureFrom<Response<U>, Error = Error> + TryInto<Response<U>>;
/// Metadata about the endpoint. /// Metadata about the endpoint.
const METADATA: Metadata; const METADATA: Metadata;
@ -53,8 +56,12 @@ pub enum Error {
Io(io::Error), Io(io::Error),
/// A Serde JSON error. /// A Serde JSON error.
SerdeJson(serde_json::Error), SerdeJson(serde_json::Error),
/// A Serde URL decoding error.
SerdeUrlEncodedDe(serde_urlencoded::de::Error),
/// A Serde URL encoding error. /// A Serde URL encoding error.
SerdeUrlEncoded(serde_urlencoded::ser::Error), SerdeUrlEncodedSer(serde_urlencoded::ser::Error),
/// A Ruma Identitifiers error.
RumaIdentifiers(ruma_identifiers::Error),
/// An HTTP status code indicating error. /// An HTTP status code indicating error.
StatusCode(StatusCode), StatusCode(StatusCode),
/// Standard hack to prevent exhaustive matching. /// Standard hack to prevent exhaustive matching.
@ -87,9 +94,21 @@ impl From<serde_json::Error> for Error {
} }
} }
impl From<serde_urlencoded::de::Error> for Error {
fn from(error: serde_urlencoded::de::Error) -> Self {
Error::SerdeUrlEncodedDe(error)
}
}
impl From<serde_urlencoded::ser::Error> for Error { impl From<serde_urlencoded::ser::Error> for Error {
fn from(error: serde_urlencoded::ser::Error) -> Self { fn from(error: serde_urlencoded::ser::Error) -> Self {
Error::SerdeUrlEncoded(error) Error::SerdeUrlEncodedSer(error)
}
}
impl From<ruma_identifiers::Error> for Error {
fn from(error: ruma_identifiers::Error) -> Self {
Error::RumaIdentifiers(error)
} }
} }
@ -118,10 +137,13 @@ mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
use futures::future::{err, ok, FutureFrom, FutureResult}; use futures::future::{err, ok, FutureFrom, FutureResult};
use http::header::CONTENT_TYPE;
use http::method::Method; use http::method::Method;
use http::{Request as HttpRequest, Response as HttpResponse}; use http::{Request as HttpRequest, Response as HttpResponse};
use ruma_identifiers::{RoomAliasId, RoomId}; use ruma_identifiers::{RoomAliasId, RoomId};
use serde::de::{Deserialize, IntoDeserializer};
use serde_json; use serde_json;
use url::percent_encoding;
use super::super::{Endpoint as ApiEndpoint, Error, Metadata}; use super::super::{Endpoint as ApiEndpoint, Error, Metadata};
@ -149,7 +171,7 @@ mod tests {
pub room_alias: RoomAliasId, // path pub room_alias: RoomAliasId, // path
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize, Deserialize)]
struct RequestBody { struct RequestBody {
room_id: RoomId, room_id: RoomId,
} }
@ -178,6 +200,36 @@ mod tests {
} }
} }
impl FutureFrom<HttpRequest<Vec<u8>>> for Request {
type Future = FutureResult<Self, Self::Error>;
type Error = Error;
fn future_from(request: HttpRequest<Vec<u8>>) -> Self::Future {
FutureResult::from(Self::try_from(request))
}
}
impl TryFrom<HttpRequest<Vec<u8>>> for Request {
type Error = Error;
fn try_from(request: HttpRequest<Vec<u8>>) -> Result<Request, Self::Error> {
let request_body: RequestBody =
::serde_json::from_slice(request.body().as_slice())?;
let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();
Ok(Request {
room_id: request_body.room_id,
room_alias: {
let segment = path_segments.get(5).unwrap().as_bytes();
let decoded =
percent_encoding::percent_decode(segment)
.decode_utf8_lossy();
RoomAliasId::deserialize(decoded.into_deserializer())
.map_err(|e: serde_json::error::Error| e)?
},
})
}
}
/// The response to a request to create a new room alias. /// The response to a request to create a new room alias.
#[derive(Debug)] #[derive(Debug)]
pub struct Response; pub struct Response;
@ -196,5 +248,17 @@ mod tests {
} }
} }
} }
impl TryFrom<Response> for HttpResponse<Vec<u8>> {
type Error = Error;
fn try_from(_response: Response) -> Result<HttpResponse<Vec<u8>>, Self::Error> {
let response = HttpResponse::builder()
.header(CONTENT_TYPE, "application/json")
.body("{}".as_bytes().to_vec())
.unwrap();
Ok(response)
}
}
} }
} }