From 731cb96c9a691fe0165b396bdd8dd8dd6a09d8f1 Mon Sep 17 00:00:00 2001 From: Ferris Tseng Date: Sun, 8 Oct 2017 17:31:44 -0400 Subject: implement simple client --- Cargo.toml | 2 ++ src/client.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 6 ++++++ src/response/error.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++--- src/response/ls.rs | 2 +- src/response/mod.rs | 4 ++++ src/response/version.rs | 8 +++---- 7 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 src/client.rs diff --git a/Cargo.toml b/Cargo.toml index 3020f9e..e25da0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,9 @@ authors = ["Ferris Tseng "] [dependencies] base58 = "0.1" +futures = "0.1" hyper = "0.11" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" +tokio-core = "0.1" diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..5328a2d --- /dev/null +++ b/src/client.rs @@ -0,0 +1,55 @@ +use futures::Stream; +use futures::future::Future; +use hyper::Uri; +use hyper::client::{Client, HttpConnector}; +use hyper::error::UriError; +use response::{self, Error}; +use serde_json; +use tokio_core::reactor::Handle; + + +pub type AsyncResponse = Box>; + + +pub struct IpfsClient { + base: Uri, + client: Client, +} + +impl IpfsClient { + /// Creates a new `IpfsClient`. + /// + #[inline] + pub fn new(handle: &Handle, host: &str, port: u16) -> Result { + let base_path = IpfsClient::build_base_path(host, port)?; + + Ok(IpfsClient { + base: base_path, + client: Client::new(handle), + }) + } + + /// Builds the base uri path for the Ipfs API. + /// + fn build_base_path(host: &str, port: u16) -> Result { + format!("http://{}:{}/api/v0", host, port).parse() + } +} + +impl IpfsClient { + /// Returns information about the Ipfs server version. + /// + pub fn version(&self) -> AsyncResponse { + let uri = format!("{}/version", self.base).parse().unwrap(); + + Box::new( + self.client + .get(uri) + .and_then(|res| res.body().concat2()) + .from_err() + .and_then(move |body| { + serde_json::from_slice(&body).map_err(From::from) + }), + ) + } +} diff --git a/src/lib.rs b/src/lib.rs index 892e7c2..999a596 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,15 @@ extern crate base58; +extern crate futures; extern crate hyper; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +extern crate tokio_core; + + +pub use client::IpfsClient; pub mod response; +mod client; diff --git a/src/response/error.rs b/src/response/error.rs index 252adef..3eb8f1b 100644 --- a/src/response/error.rs +++ b/src/response/error.rs @@ -1,6 +1,55 @@ -#[derive(Deserialize)] +use hyper; +use serde_json; +use std::fmt::{self, Display, Formatter}; + + +#[derive(Debug)] +pub enum Error { + Http(hyper::error::Error), + Parse(serde_json::Error), + Api(ApiError), + Uncategorized(String), +} + +impl From for Error { + fn from(error: hyper::error::Error) -> Self { + Error::Http(error) + } +} + +impl From for Error { + fn from(error: serde_json::Error) -> Self { + Error::Parse(error) + } +} + +impl From for Error { + fn from(error: ApiError) -> Self { + Error::Api(error) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl ::std::error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Http(_) => "an http error occured", + Error::Parse(_) => "an error occursed while parsing the api response", + Error::Api(_) => "an api error occured", + Error::Uncategorized(_) => "an unknown error occured", + } + } +} + + +#[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] -pub struct Error { +pub struct ApiError { pub message: String, - pub code: u8 + pub code: u8, } diff --git a/src/response/ls.rs b/src/response/ls.rs index 29bc42e..de8efb9 100644 --- a/src/response/ls.rs +++ b/src/response/ls.rs @@ -5,7 +5,7 @@ use response::{serde, IpfsFile}; #[serde(rename_all = "PascalCase")] pub struct LsResponse { #[serde(deserialize_with = "serde::deserialize_vec")] - pub objects: Vec + pub objects: Vec, } diff --git a/src/response/mod.rs b/src/response/mod.rs index 49056ab..317f20f 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -16,6 +16,7 @@ pub use self::filestore::*; pub use self::id::*; pub use self::key::*; pub use self::log::*; +pub use self::ls::*; pub use self::mount::*; pub use self::name::*; pub use self::object::*; @@ -28,6 +29,7 @@ pub use self::resolve::*; pub use self::stats::*; pub use self::swarm::*; pub use self::tar::*; +pub use self::version::*; /// Create a test to deserialize a file to the given instance. @@ -67,6 +69,7 @@ mod get; mod id; mod key; mod log; +mod ls; mod mount; mod name; mod object; @@ -80,6 +83,7 @@ mod serde; mod stats; mod swarm; mod tar; +mod version; #[derive(Deserialize)] diff --git a/src/response/version.rs b/src/response/version.rs index 05178d5..8c91ce8 100644 --- a/src/response/version.rs +++ b/src/response/version.rs @@ -1,15 +1,15 @@ -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] -pub struct Version { +pub struct VersionResponse { pub version: String, pub commit: String, pub repo: String, pub system: String, - pub golang: String + pub golang: String, } #[cfg(test)] mod tests { - deserialize_test!(v0_version_0, Version); + deserialize_test!(v0_version_0, VersionResponse); } -- cgit v1.2.3