mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Fix wallet owner_api on new Hyper (#1312)
Fixes [#1308]. The main change is to switch from Core to Runtime inside the client. I also used this as an opportunity to provide async methods for get and post, so we can use it in places where futures are acceptable, which is not the case for the wallet.
This commit is contained in:
parent
3df050cc93
commit
6a1d0e3354
1 changed files with 112 additions and 52 deletions
|
@ -23,10 +23,12 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use futures::future::{err, ok, Either};
|
use futures::future::{err, ok, Either};
|
||||||
use tokio_core::reactor::Core;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use rest::{Error, ErrorKind};
|
use rest::{Error, ErrorKind};
|
||||||
|
|
||||||
|
pub type ClientResponseFuture<T> = Box<Future<Item = T, Error = Error> + Send>;
|
||||||
|
|
||||||
/// Helper function to easily issue a HTTP GET request against a given URL that
|
/// Helper function to easily issue a HTTP GET request against a given URL that
|
||||||
/// returns a JSON object. Handles request building, JSON deserialization and
|
/// returns a JSON object. Handles request building, JSON deserialization and
|
||||||
/// response code checking.
|
/// response code checking.
|
||||||
|
@ -34,19 +36,20 @@ pub fn get<'a, T>(url: &'a str) -> Result<T, Error>
|
||||||
where
|
where
|
||||||
for<'de> T: Deserialize<'de>,
|
for<'de> T: Deserialize<'de>,
|
||||||
{
|
{
|
||||||
let uri = url.parse::<Uri>().map_err::<Error, _>(|e: InvalidUri| {
|
handle_request(build_request(url, "GET", None)?)
|
||||||
e.context(ErrorKind::Argument(format!("Invalid url {}", url)))
|
}
|
||||||
.into()
|
|
||||||
})?;
|
|
||||||
let req = Request::builder()
|
|
||||||
.method("GET")
|
|
||||||
.uri(uri)
|
|
||||||
.header(USER_AGENT, "grin-client")
|
|
||||||
.header(ACCEPT, "application/json")
|
|
||||||
.body(Body::empty())
|
|
||||||
.map_err(|_e| ErrorKind::RequestError("Bad request".to_owned()))?;
|
|
||||||
|
|
||||||
handle_request(req)
|
/// Helper function to easily issue an async HTTP GET request against a given
|
||||||
|
/// URL that returns a future. Handles request building, JSON deserialization
|
||||||
|
/// and response code checking.
|
||||||
|
pub fn get_async<'a, T>(url: &'a str) -> ClientResponseFuture<T>
|
||||||
|
where
|
||||||
|
for<'de> T: Deserialize<'de> + Send + 'static,
|
||||||
|
{
|
||||||
|
match build_request(url, "GET", None) {
|
||||||
|
Ok(req) => Box::new(handle_request_async(req)),
|
||||||
|
Err(e) => Box::new(err(e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to easily issue a HTTP POST request with the provided JSON
|
/// Helper function to easily issue a HTTP POST request with the provided JSON
|
||||||
|
@ -62,6 +65,22 @@ where
|
||||||
handle_request(req)
|
handle_request(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to easily issue an async HTTP POST request with the
|
||||||
|
/// provided JSON object as body on a given URL that returns a future. Handles
|
||||||
|
/// request building, JSON serialization and deserialization, and response code
|
||||||
|
/// checking.
|
||||||
|
pub fn post_async<IN, OUT>(url: &str, input: &IN) -> ClientResponseFuture<OUT>
|
||||||
|
where
|
||||||
|
IN: Serialize,
|
||||||
|
OUT: Send + 'static,
|
||||||
|
for<'de> OUT: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
match create_post_request(url, input) {
|
||||||
|
Ok(req) => Box::new(handle_request_async(req)),
|
||||||
|
Err(e) => Box::new(err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper function to easily issue a HTTP POST request with the provided JSON
|
/// Helper function to easily issue a HTTP POST request with the provided JSON
|
||||||
/// object as body on a given URL that returns nothing. Handles request
|
/// object as body on a given URL that returns nothing. Handles request
|
||||||
/// building, JSON serialization, and response code
|
/// building, JSON serialization, and response code
|
||||||
|
@ -75,6 +94,43 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to easily issue an async HTTP POST request with the
|
||||||
|
/// provided JSON object as body on a given URL that returns a future. Handles
|
||||||
|
/// request building, JSON serialization and deserialization, and response code
|
||||||
|
/// checking.
|
||||||
|
pub fn post_no_ret_async<IN>(url: &str, input: &IN) -> ClientResponseFuture<()>
|
||||||
|
where
|
||||||
|
IN: Serialize,
|
||||||
|
{
|
||||||
|
match create_post_request(url, input) {
|
||||||
|
Ok(req) => Box::new(send_request_async(req).and_then(|_| ok(()))),
|
||||||
|
Err(e) => Box::new(err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_request<'a>(
|
||||||
|
url: &'a str,
|
||||||
|
method: &str,
|
||||||
|
body: Option<String>,
|
||||||
|
) -> Result<Request<Body>, Error> {
|
||||||
|
let uri = url.parse::<Uri>().map_err::<Error, _>(|e: InvalidUri| {
|
||||||
|
e.context(ErrorKind::Argument(format!("Invalid url {}", url)))
|
||||||
|
.into()
|
||||||
|
})?;
|
||||||
|
Request::builder()
|
||||||
|
.method(method)
|
||||||
|
.uri(uri)
|
||||||
|
.header(USER_AGENT, "grin-client")
|
||||||
|
.header(ACCEPT, "application/json")
|
||||||
|
.body(match body {
|
||||||
|
None => Body::empty(),
|
||||||
|
Some(json) => json.into(),
|
||||||
|
})
|
||||||
|
.map_err(|e| {
|
||||||
|
ErrorKind::RequestError(format!("Bad request {} {}: {}", method, url, e)).into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn create_post_request<IN>(url: &str, input: &IN) -> Result<Request<Body>, Error>
|
fn create_post_request<IN>(url: &str, input: &IN) -> Result<Request<Body>, Error>
|
||||||
where
|
where
|
||||||
IN: Serialize,
|
IN: Serialize,
|
||||||
|
@ -82,20 +138,7 @@ where
|
||||||
let json = serde_json::to_string(input).context(ErrorKind::Internal(
|
let json = serde_json::to_string(input).context(ErrorKind::Internal(
|
||||||
"Could not serialize data to JSON".to_owned(),
|
"Could not serialize data to JSON".to_owned(),
|
||||||
))?;
|
))?;
|
||||||
let uri = url.parse::<Uri>().map_err::<Error, _>(|e: InvalidUri| {
|
build_request(url, "POST", Some(json))
|
||||||
e.context(ErrorKind::Argument(format!("Invalid url {}", url)))
|
|
||||||
.into()
|
|
||||||
})?;
|
|
||||||
Request::builder()
|
|
||||||
.method("POST")
|
|
||||||
.uri(uri)
|
|
||||||
.header(USER_AGENT, "grin-client")
|
|
||||||
.header(ACCEPT, "application/json")
|
|
||||||
.body(json.into())
|
|
||||||
.map_err::<Error, _>(|e| {
|
|
||||||
e.context(ErrorKind::RequestError("Bad request".to_owned()))
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request<T>(req: Request<Body>) -> Result<T, Error>
|
fn handle_request<T>(req: Request<Body>) -> Result<T, Error>
|
||||||
|
@ -109,29 +152,46 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_request(req: Request<Body>) -> Result<String, Error> {
|
fn handle_request_async<T>(req: Request<Body>) -> ClientResponseFuture<T>
|
||||||
let mut event_loop = Core::new().unwrap();
|
where
|
||||||
let client = Client::new();
|
for<'de> T: Deserialize<'de> + Send + 'static,
|
||||||
|
{
|
||||||
let task = client
|
Box::new(send_request_async(req).and_then(|data| {
|
||||||
.request(req)
|
serde_json::from_str(&data).map_err(|e| {
|
||||||
.map_err(|_e| ErrorKind::RequestError("Cannot make request".to_owned()))
|
e.context(ErrorKind::ResponseError("Cannot parse response".to_owned()))
|
||||||
.and_then(|resp| {
|
.into()
|
||||||
if !resp.status().is_success() {
|
})
|
||||||
Either::A(err(ErrorKind::RequestError(
|
}))
|
||||||
"Wrong response code".to_owned(),
|
}
|
||||||
)))
|
|
||||||
} else {
|
fn send_request_async(req: Request<Body>) -> Box<Future<Item = String, Error = Error> + Send> {
|
||||||
Either::B(
|
let client = Client::new();
|
||||||
resp.into_body()
|
Box::new(
|
||||||
.map_err(|_e| {
|
client
|
||||||
ErrorKind::RequestError("Cannot read response body".to_owned())
|
.request(req)
|
||||||
})
|
.map_err(|e| ErrorKind::RequestError(format!("Cannot make request: {}", e)).into())
|
||||||
.concat2()
|
.and_then(|resp| {
|
||||||
.and_then(|ch| ok(String::from_utf8_lossy(&ch.to_vec()).to_string())),
|
if !resp.status().is_success() {
|
||||||
)
|
Either::A(err(ErrorKind::RequestError(
|
||||||
}
|
"Wrong response code".to_owned(),
|
||||||
});
|
).into()))
|
||||||
|
} else {
|
||||||
Ok(event_loop.run(task)?)
|
Either::B(
|
||||||
|
resp.into_body()
|
||||||
|
.map_err(|e| {
|
||||||
|
ErrorKind::RequestError(format!("Cannot read response body: {}", e))
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.concat2()
|
||||||
|
.and_then(|ch| ok(String::from_utf8_lossy(&ch.to_vec()).to_string())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_request(req: Request<Body>) -> Result<String, Error> {
|
||||||
|
let task = send_request_async(req);
|
||||||
|
let mut rt = Runtime::new().unwrap();
|
||||||
|
Ok(rt.block_on(task)?)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue