summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipfs-api/src/client.rs92
-rw-r--r--ipfs-api/src/request/pin.rs2
2 files changed, 76 insertions, 18 deletions
diff --git a/ipfs-api/src/client.rs b/ipfs-api/src/client.rs
index 203a434..50dfd0d 100644
--- a/ipfs-api/src/client.rs
+++ b/ipfs-api/src/client.rs
@@ -5,6 +5,7 @@ use reqwest::{self, multipart, Method, StatusCode, Url};
use reqwest::unstable::async::{self, Client, ClientBuilder};
use response::{self, Error};
use serde::{Deserialize, Serialize};
+use serde_json;
use std::io::Read;
use tokio_core::reactor::Handle;
@@ -65,21 +66,74 @@ impl IpfsClient {
uri.parse().map_err(From::from)
}
- /// Generates a request, and returns the unprocessed response future.
+ /// Processes a response, returning an error or a deserialized json response.
///
- fn request_raw<Req>(&self, req: &Req) -> ApiResult<async::Chunk>
+ fn process_response<Res>(status: StatusCode, chunk: async::Chunk) -> Result<Res, Error>
where
- Req: ApiRequest + Serialize,
+ for<'de> Res: 'static + Deserialize<'de>,
{
- let url = self.build_url(req)?;
- let mut req = self.client.request(Method::Get, url);
+ match status {
+ StatusCode::Ok => serde_json::from_slice(&chunk).map_err(From::from),
+ _ => {
+ // For error responses, the error can either be a json error,
+ // or can just be a string message.
+ //
+ match serde_json::from_slice(&chunk) {
+ Ok(e) => Err(Error::Api(e)),
+ Err(_) => Err(Error::Uncategorized(String::from_utf8(chunk.to_vec())?)),
+ }
+ }
+ }
+ }
+
+ /// Sends a request and returns the raw response.
+ ///
+ /// Methods prefixed with `send_` work on a raw reqwest `RequestBuilder`
+ /// instance.
+ ///
+ fn send_request(
+ &self,
+ mut req: async::RequestBuilder,
+ ) -> ApiResult<(StatusCode, async::Chunk)> {
let res = req.send()
- .and_then(move |res| res.into_body().concat2())
+ .and_then(|res| {
+ let status = res.status();
+
+ res.into_body().concat2().map(move |chunk| (status, chunk))
+ })
.from_err();
Ok(Box::new(res))
}
+ /// Sends a request and deserializes the response into Json.
+ ///
+ /// Methods prefixed with `send_` work on a raw reqwest `RequestBuilder`
+ /// instance.
+ ///
+ fn send_request_json<Res>(&self, req: async::RequestBuilder) -> ApiResult<Res>
+ where
+ for<'de> Res: 'static + Deserialize<'de>,
+ {
+ let res = self.send_request(req)?.and_then(move |(status, chunk)| {
+ IpfsClient::process_response(status, chunk)
+ });
+
+ Ok(Box::new(res))
+ }
+
+ /// Generates a request, and returns the unprocessed response future.
+ ///
+ fn request_raw<Req>(&self, req: &Req) -> ApiResult<(StatusCode, async::Chunk)>
+ where
+ Req: ApiRequest + Serialize,
+ {
+ let url = self.build_url(req)?;
+ let req = self.client.request(Method::Get, url);
+
+ self.send_request(req)
+ }
+
/// Generic method for making a request to the Ipfs server, and getting
/// a deserializable response.
///
@@ -88,11 +142,10 @@ impl IpfsClient {
Req: ApiRequest + Serialize,
for<'de> Res: 'static + Deserialize<'de>,
{
- let res = self.request_raw(req)?.and_then(move |chunk| {
- ::serde_json::from_slice(&chunk).map_err(From::from)
- });
+ let url = self.build_url(req)?;
+ let req = self.client.request(Method::Get, url);
- Ok(Box::new(res))
+ self.send_request_json(req)
}
/// Generic method for making a request to the Ipfs server, and getting
@@ -106,10 +159,9 @@ impl IpfsClient {
{
let url = self.build_url(req)?;
let form = multipart::Form::new().part("file", multipart::Part::reader(data));
- let mut req = self.client.request(Method::Get, url);
- let res = req.send().and_then(move |mut res| res.json()).from_err();
+ let req = self.client.request(Method::Get, url);
- Ok(Box::new(res))
+ self.send_request_json(req)
}
}
@@ -160,9 +212,11 @@ impl IpfsClient {
/// Returns an unparsed json string, due to an unclear spec.
///
pub fn config_show(&self) -> ApiResult<response::ConfigShowResponse> {
- let req = self.request_raw(&request::ConfigShow)?.and_then(|chunk| {
- String::from_utf8(chunk.to_vec()).map_err(From::from)
- });
+ let req = self.request_raw(&request::ConfigShow)?.and_then(
+ |(_, chunk)| {
+ String::from_utf8(chunk.to_vec()).map_err(From::from)
+ },
+ );
Ok(Box::new(req))
}
@@ -200,7 +254,11 @@ impl IpfsClient {
/// Returns a list of pinned objects in local storage.
///
- pub fn pin_ls(&self, key: Option<&str>, typ: Option<&str>) -> ApiResult<response::PinLsResponse> {
+ pub fn pin_ls(
+ &self,
+ key: Option<&str>,
+ typ: Option<&str>,
+ ) -> ApiResult<response::PinLsResponse> {
self.request(&request::PinLs { key, typ })
}
diff --git a/ipfs-api/src/request/pin.rs b/ipfs-api/src/request/pin.rs
index c206f13..def6687 100644
--- a/ipfs-api/src/request/pin.rs
+++ b/ipfs-api/src/request/pin.rs
@@ -7,7 +7,7 @@ pub struct PinLs<'a> {
pub key: Option<&'a str>,
#[serde(rename = "type")]
- pub typ: Option<&'a str>
+ pub typ: Option<&'a str>,
}
impl<'a> ApiRequest for PinLs<'a> {