summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipfs-api/Cargo.toml2
-rw-r--r--ipfs-api/examples/add_file.rs27
-rw-r--r--ipfs-api/examples/get_commands.rs3
-rw-r--r--ipfs-api/examples/get_version.rs9
-rw-r--r--ipfs-api/src/client.rs90
-rw-r--r--ipfs-api/src/lib.rs2
-rw-r--r--ipfs-api/src/request/add.rs11
-rw-r--r--ipfs-api/src/request/mod.rs2
-rw-r--r--ipfs-api/src/response/add.rs2
-rw-r--r--ipfs-api/src/response/error.rs16
10 files changed, 119 insertions, 45 deletions
diff --git a/ipfs-api/Cargo.toml b/ipfs-api/Cargo.toml
index 3e57393..9c5e4f0 100644
--- a/ipfs-api/Cargo.toml
+++ b/ipfs-api/Cargo.toml
@@ -5,7 +5,7 @@ authors = ["Ferris Tseng <ferristseng@fastmail.fm>"]
[dependencies]
futures = "0.1"
-hyper = "0.11"
+reqwest = { version = "0.8", features = ["unstable"] }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
diff --git a/ipfs-api/examples/add_file.rs b/ipfs-api/examples/add_file.rs
new file mode 100644
index 0000000..8ebbddf
--- /dev/null
+++ b/ipfs-api/examples/add_file.rs
@@ -0,0 +1,27 @@
+extern crate ipfs_api;
+extern crate tokio_core;
+
+use ipfs_api::{response, IpfsClient};
+use std::fs::File;
+use tokio_core::reactor::Core;
+
+
+// Creates an Ipfs client, and gets a list of available commands from the
+// Ipfs server.
+//
+fn main() {
+ if let Ok(mut core) = Core::new() {
+ println!("note: this must be run in the root of the project repository");
+ println!("connecting to localhost:5001...");
+
+ let client =
+ IpfsClient::new(&core.handle(), "localhost", 5001).expect("expected a valid url");
+ let file = File::open(file!()).expect("could not read source file");
+ let req = client.add(file).expect("expected a valid request");
+ let add = core.run(req).expect("expected a valid response");
+
+ println!("added file: {:?}", add);
+ } else {
+ println!("failed to create event loop");
+ }
+}
diff --git a/ipfs-api/examples/get_commands.rs b/ipfs-api/examples/get_commands.rs
index 9d03f54..2ac6bbe 100644
--- a/ipfs-api/examples/get_commands.rs
+++ b/ipfs-api/examples/get_commands.rs
@@ -1,7 +1,6 @@
extern crate ipfs_api;
extern crate tokio_core;
-
use ipfs_api::{response, IpfsClient};
use tokio_core::reactor::Core;
@@ -37,7 +36,7 @@ fn main() {
let client =
IpfsClient::new(&core.handle(), "localhost", 5001).expect("expected a valid url");
- let req = client.commands();
+ let req = client.commands().expect("expected a valid request");
print_recursive(0, &core.run(req).expect("expected a valid response"));
} else {
diff --git a/ipfs-api/examples/get_version.rs b/ipfs-api/examples/get_version.rs
index 5e2c608..e605da3 100644
--- a/ipfs-api/examples/get_version.rs
+++ b/ipfs-api/examples/get_version.rs
@@ -1,7 +1,6 @@
extern crate ipfs_api;
extern crate tokio_core;
-
use ipfs_api::IpfsClient;
use tokio_core::reactor::Core;
@@ -14,12 +13,10 @@ fn main() {
let client =
IpfsClient::new(&core.handle(), "localhost", 5001).expect("expected a valid url");
- let req = client.version();
+ let req = client.version().expect("expected a valid request");
+ let version = core.run(req).expect("expected a valid response");
- println!(
- "version: {:?}",
- core.run(req).expect("expected a valid response")
- )
+ println!("version: {:?}", version.version);
} else {
println!("failed to create event loop");
}
diff --git a/ipfs-api/src/client.rs b/ipfs-api/src/client.rs
index fe98b0f..ff3eb52 100644
--- a/ipfs-api/src/client.rs
+++ b/ipfs-api/src/client.rs
@@ -1,95 +1,125 @@
-use futures::Stream;
use futures::future::Future;
-use hyper::{Chunk, Uri};
-use hyper::client::{Client, HttpConnector};
-use hyper::error::UriError;
use request::{self, ApiRequest};
+use reqwest::{self, multipart, Method, Url};
+use reqwest::unstable::async::{Client, ClientBuilder};
use response::{self, Error};
use serde::Deserialize;
-use serde_json;
+use std::io::Read;
use tokio_core::reactor::Handle;
-pub type AsyncResponse<T> = Box<Future<Item = T, Error = Error>>;
+/// A future response returned by the reqwest HTTP client.
+///
+type AsyncResponse<T> = Box<Future<Item = T, Error = Error>>;
/// Asynchronous Ipfs client.
///
pub struct IpfsClient {
- base: Uri,
- client: Client<HttpConnector>,
+ base: Url,
+ client: Client,
}
impl IpfsClient {
/// Creates a new `IpfsClient`.
///
#[inline]
- pub fn new(handle: &Handle, host: &str, port: u16) -> Result<IpfsClient, UriError> {
+ pub fn new(
+ handle: &Handle,
+ host: &str,
+ port: u16,
+ ) -> Result<IpfsClient, Box<::std::error::Error>> {
let base_path = IpfsClient::build_base_path(host, port)?;
Ok(IpfsClient {
base: base_path,
- client: Client::new(handle),
+ client: ClientBuilder::new().build(handle)?,
})
}
- /// Builds the base uri path for the Ipfs API.
+ /// Builds the base url path for the Ipfs api.
///
- fn build_base_path(host: &str, port: u16) -> Result<Uri, UriError> {
+ fn build_base_path(host: &str, port: u16) -> Result<Url, reqwest::UrlError> {
format!("http://{}:{}/api/v0", host, port).parse()
}
- /// Generic method for making a request to the Ipfs server.
+ /// Builds the url for an api call.
///
- /// Returns the raw response.
+ fn build_url<Req>(&self, req: &Req) -> Result<Url, reqwest::UrlError>
+ where
+ Req: ApiRequest,
+ {
+ let uri = format!("{}{}?", self.base, Req::path()).parse()?;
+
+ Ok(uri)
+ }
+
+ /// Generic method for making a request to the Ipfs server, and getting
+ /// a deserializable response.
///
- fn request_raw<Req>(&self, req: &Req) -> AsyncResponse<Chunk>
+ fn request<Req, Res>(&self, req: &Req) -> Result<AsyncResponse<Res>, Error>
where
Req: ApiRequest,
+ for<'de> Res: 'static + Deserialize<'de>,
{
- let uri = format!("{}{}?", self.base, Req::path()).parse().unwrap();
-
- Box::new(
- self.client
- .get(uri)
- .and_then(|res| res.body().concat2())
- .from_err(),
- )
+ let url = self.build_url(req)?;
+ let mut req = self.client.request(Method::Get, url);
+ let res = req.send().and_then(move |mut res| res.json()).from_err();
+
+ Ok(Box::new(res))
}
/// Generic method for making a request to the Ipfs server, and getting
/// a deserializable response.
///
- fn request<Req, Res>(&self, req: &Req) -> AsyncResponse<Res>
+ fn request_with_body<Req, Res, R>(
+ &self,
+ data: R,
+ req: &Req,
+ ) -> Result<AsyncResponse<Res>, Error>
where
Req: ApiRequest,
for<'de> Res: 'static + Deserialize<'de>,
+ R: 'static + Read + Send,
{
- Box::new(self.request_raw(req).and_then(move |body| {
- serde_json::from_slice(&body).map_err(From::from)
- }))
+ 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); //.form(&form);
+ let res = req.send().and_then(move |mut res| res.json()).from_err();
+
+ Ok(Box::new(res))
}
}
impl IpfsClient {
+ /// Add file to Ipfs.
+ ///
+ #[inline]
+ pub fn add<R>(&self, data: R) -> Result<AsyncResponse<response::AddResponse>, Error>
+ where
+ R: 'static + Read + Send,
+ {
+ self.request_with_body(data, &request::Add)
+ }
+
/// List available commands that the server accepts.
///
#[inline]
- pub fn commands(&self) -> AsyncResponse<response::CommandsResponse> {
+ pub fn commands(&self) -> Result<AsyncResponse<response::CommandsResponse>, Error> {
self.request(&request::Commands)
}
/// List the contents of an Ipfs multihash.
///
#[inline]
- pub fn ls(&self, path: Option<&str>) -> AsyncResponse<response::LsResponse> {
+ pub fn ls(&self, path: Option<&str>) -> Result<AsyncResponse<response::LsResponse>, Error> {
self.request(&request::LsRequest(path))
}
/// Returns information about the Ipfs server version.
///
#[inline]
- pub fn version(&self) -> AsyncResponse<response::VersionResponse> {
+ pub fn version(&self) -> Result<AsyncResponse<response::VersionResponse>, Error> {
self.request(&request::Version)
}
}
diff --git a/ipfs-api/src/lib.rs b/ipfs-api/src/lib.rs
index ed0303c..37f0de2 100644
--- a/ipfs-api/src/lib.rs
+++ b/ipfs-api/src/lib.rs
@@ -1,5 +1,5 @@
extern crate futures;
-extern crate hyper;
+extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
diff --git a/ipfs-api/src/request/add.rs b/ipfs-api/src/request/add.rs
new file mode 100644
index 0000000..7237b55
--- /dev/null
+++ b/ipfs-api/src/request/add.rs
@@ -0,0 +1,11 @@
+use request::ApiRequest;
+
+
+pub struct Add;
+
+impl ApiRequest for Add {
+ #[inline]
+ fn path() -> &'static str {
+ "/add"
+ }
+}
diff --git a/ipfs-api/src/request/mod.rs b/ipfs-api/src/request/mod.rs
index 05a6f02..7681a78 100644
--- a/ipfs-api/src/request/mod.rs
+++ b/ipfs-api/src/request/mod.rs
@@ -1,8 +1,10 @@
+pub use self::add::*;
pub use self::commands::*;
pub use self::ls::*;
pub use self::version::*;
+mod add;
mod commands;
mod ls;
mod version;
diff --git a/ipfs-api/src/response/add.rs b/ipfs-api/src/response/add.rs
index 388c2a6..d49d9a3 100644
--- a/ipfs-api/src/response/add.rs
+++ b/ipfs-api/src/response/add.rs
@@ -1,4 +1,4 @@
-#[derive(Deserialize)]
+#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct AddResponse {
pub name: String,
diff --git a/ipfs-api/src/response/error.rs b/ipfs-api/src/response/error.rs
index 3eb8f1b..e56c249 100644
--- a/ipfs-api/src/response/error.rs
+++ b/ipfs-api/src/response/error.rs
@@ -1,18 +1,25 @@
-use hyper;
+use reqwest;
use serde_json;
use std::fmt::{self, Display, Formatter};
#[derive(Debug)]
pub enum Error {
- Http(hyper::error::Error),
+ Http(reqwest::Error),
Parse(serde_json::Error),
+ Url(reqwest::UrlError),
Api(ApiError),
Uncategorized(String),
}
-impl From<hyper::error::Error> for Error {
- fn from(error: hyper::error::Error) -> Self {
+impl From<reqwest::UrlError> for Error {
+ fn from(error: reqwest::UrlError) -> Self {
+ Error::Url(error)
+ }
+}
+
+impl From<reqwest::Error> for Error {
+ fn from(error: reqwest::Error) -> Self {
Error::Http(error)
}
}
@@ -40,6 +47,7 @@ impl ::std::error::Error for Error {
match *self {
Error::Http(_) => "an http error occured",
Error::Parse(_) => "an error occursed while parsing the api response",
+ Error::Url(_) => "an error occured while parsing the request url",
Error::Api(_) => "an api error occured",
Error::Uncategorized(_) => "an unknown error occured",
}