From 90d3c0a8bb552c249bffb67d20b06869a24bd0a8 Mon Sep 17 00:00:00 2001 From: Ferris Tseng Date: Tue, 26 Jun 2018 21:40:37 -0400 Subject: upgrade dependencies --- ipfs-api/Cargo.toml | 11 ++++++----- ipfs-api/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ipfs-api/Cargo.toml b/ipfs-api/Cargo.toml index c01d5dd..ea84310 100644 --- a/ipfs-api/Cargo.toml +++ b/ipfs-api/Cargo.toml @@ -15,17 +15,18 @@ travis-ci = { repository = "ferristseng/rust-ipfs-api" } [dependencies] bytes = "0.4" -error-chain = "0.11" +error-chain = "0.12" futures = "0.1" -hyper = "0.11" -hyper-multipart-rfc7578 = "0.1.0-alpha" +hyper = "0.12" +hyper-multipart-rfc7578 = "0.2.0-alpha1" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" serde_urlencoded = "0.5" -tokio-core = "0.1" +tokio = "0.1" +tokio-codec = "0.1" tokio-io = "0.1" [dev-dependencies] -tokio-timer = "0.1" +tokio-timer = "0.2" tar = "0.4" diff --git a/ipfs-api/src/lib.rs b/ipfs-api/src/lib.rs index 2aeebae..1e584c3 100644 --- a/ipfs-api/src/lib.rs +++ b/ipfs-api/src/lib.rs @@ -84,7 +84,7 @@ extern crate serde; extern crate serde_derive; extern crate serde_json; extern crate serde_urlencoded; -extern crate tokio_core; +extern crate tokio; extern crate tokio_io; pub use client::IpfsClient; -- cgit v1.2.3 From 148b989784b47a4034ff82be1760e73a1429dbeb Mon Sep 17 00:00:00 2001 From: Ferris Tseng Date: Wed, 27 Jun 2018 00:22:50 -0400 Subject: get ipfs-api compiling --- ipfs-api/Cargo.toml | 3 +- ipfs-api/src/client.rs | 98 +++++++++++++++++++++--------------------- ipfs-api/src/header.rs | 74 +------------------------------ ipfs-api/src/lib.rs | 4 ++ ipfs-api/src/read.rs | 26 ++++------- ipfs-api/src/request/add.rs | 2 +- ipfs-api/src/request/block.rs | 2 +- ipfs-api/src/request/config.rs | 2 +- ipfs-api/src/request/dag.rs | 2 +- ipfs-api/src/request/files.rs | 2 +- ipfs-api/src/request/mod.rs | 2 +- ipfs-api/src/request/tar.rs | 2 +- ipfs-api/src/response/error.rs | 13 +++++- 13 files changed, 85 insertions(+), 147 deletions(-) diff --git a/ipfs-api/Cargo.toml b/ipfs-api/Cargo.toml index ea84310..e869e93 100644 --- a/ipfs-api/Cargo.toml +++ b/ipfs-api/Cargo.toml @@ -6,7 +6,7 @@ documentation = "https://docs.rs/ipfs-api" repository = "https://github.com/ferristseng/rust-ipfs-api" keywords = ["ipfs"] categories = ["filesystem", "web-programming"] -version = "0.4.0-alpha.3" +version = "0.5.0-alpha1" readme = "../README.md" license = "MIT OR Apache-2.0" @@ -17,6 +17,7 @@ travis-ci = { repository = "ferristseng/rust-ipfs-api" } bytes = "0.4" error-chain = "0.12" futures = "0.1" +http = "0.1" hyper = "0.12" hyper-multipart-rfc7578 = "0.2.0-alpha1" serde = "1.0" diff --git a/ipfs-api/src/client.rs b/ipfs-api/src/client.rs index da68919..30a4461 100644 --- a/ipfs-api/src/client.rs +++ b/ipfs-api/src/client.rs @@ -6,20 +6,18 @@ // copied, modified, or distributed except according to those terms. // -use futures::future::{Future, IntoFuture}; -use futures::stream::{self, Stream}; -use header::Trailer; +use futures::{Future, IntoFuture, stream::{self, Stream}}; +use header::TRAILER; use read::{JsonLineDecoder, LineDecoder, StreamReader}; use request::{self, ApiRequest}; use response::{self, Error, ErrorKind}; -use hyper::{self, Chunk, Request, Response, StatusCode, Uri}; -use hyper::client::{Client, Config, HttpConnector}; +use http::uri::InvalidUri; +use hyper::{self, Chunk, Request, Response, StatusCode, Uri, client::{Client, HttpConnector}}; use hyper_multipart::client::multipart; use serde::{Deserialize, Serialize}; use serde_json; use std::io::Read; -use tokio_core::reactor::Handle; -use tokio_io::codec::{Decoder, FramedRead}; +use tokio_codec::{Decoder, FramedRead}; /// A response returned by the HTTP client. /// @@ -33,38 +31,33 @@ type AsyncStreamResponse = Box>; /// pub struct IpfsClient { base: Uri, - client: Client, + client: Client, +} + +impl Default for IpfsClient { + /// Creates an `IpfsClient` connected to `localhost:5001`. + /// + fn default() -> IpfsClient { + IpfsClient::new("localhost", 5001).unwrap() + } } impl IpfsClient { /// Creates a new `IpfsClient`. /// #[inline] - pub fn new( - handle: &Handle, - host: &str, - port: u16, - ) -> Result { + pub fn new(host: &str, port: u16) -> Result { let base_path = IpfsClient::build_base_path(host, port)?; Ok(IpfsClient { base: base_path, - client: Config::default() - .body::() - .keep_alive(true) - .build(handle), + client: Client::builder().keep_alive(true).build_http(), }) } - /// Creates an `IpfsClient` connected to `localhost:5001`. - /// - pub fn default(handle: &Handle) -> IpfsClient { - IpfsClient::new(handle, "localhost", 5001).unwrap() - } - /// Builds the base url path for the Ipfs api. /// - fn build_base_path(host: &str, port: u16) -> Result { + fn build_base_path(host: &str, port: u16) -> Result { format!("http://{}:{}/api/v0", host, port).parse() } @@ -74,7 +67,7 @@ impl IpfsClient { &self, req: &Req, form: Option, - ) -> Result, Error> + ) -> Result, Error> where Req: ApiRequest + Serialize, { @@ -85,17 +78,18 @@ impl IpfsClient { ::serde_urlencoded::to_string(req)? ); - url.parse::() - .map(move |url| { - let mut req = Request::new(Req::METHOD.clone(), url); + url.parse::().map_err(From::from).and_then(move |url| { + let mut builder = Request::builder(); + let mut builder = builder.method(Req::METHOD.clone()).uri(url); - if let Some(form) = form { - form.set_body(&mut req); - } + let req = if let Some(form) = form { + form.set_body(&mut builder) + } else { + builder.body(hyper::Body::empty()) + }; - req - }) - .map_err(From::from) + req.map_err(From::from) + }) } /// Builds an Api error from a response body. @@ -119,7 +113,7 @@ impl IpfsClient { for<'de> Res: 'static + Deserialize<'de>, { match status { - StatusCode::Ok => serde_json::from_slice(&chunk).map_err(From::from), + StatusCode::OK => serde_json::from_slice(&chunk).map_err(From::from), _ => Err(Self::build_error_from_body(chunk)), } } @@ -128,14 +122,14 @@ impl IpfsClient { /// results. /// fn process_stream_response( - res: Response, + res: Response, decoder: D, ) -> Box> where D: 'static + Decoder, Res: 'static, { - let stream = FramedRead::new(StreamReader::new(res.body().from_err()), decoder); + let stream = FramedRead::new(StreamReader::new(res.into_body().from_err()), decoder); Box::new(stream) } @@ -157,7 +151,7 @@ impl IpfsClient { .and_then(|res| { let status = res.status(); - res.body().concat2().map(move |chunk| (status, chunk)) + res.into_body().concat2().map(move |chunk| (status, chunk)) }) .from_err(); @@ -179,7 +173,7 @@ impl IpfsClient { where Req: ApiRequest + Serialize, Res: 'static, - F: 'static + Fn(hyper::Response) -> AsyncStreamResponse, + F: 'static + Fn(hyper::Response) -> AsyncStreamResponse, { match self.build_base_request(req, form) { Ok(req) => { @@ -188,14 +182,13 @@ impl IpfsClient { .from_err() .map(move |res| { let stream: Box> = match res.status() { - StatusCode::Ok => process(res), - + StatusCode::OK => process(res), // If the server responded with an error status code, the body // still needs to be read so an error can be built. This block will // read the entire body stream, then immediately return an error. // _ => Box::new( - res.body() + res.into_body() .concat2() .from_err() .and_then(|chunk| Err(Self::build_error_from_body(chunk))) @@ -236,7 +229,7 @@ impl IpfsClient { { let res = self.request_raw(req, form) .and_then(|(status, chunk)| match status { - StatusCode::Ok => Ok(()), + StatusCode::OK => Ok(()), _ => Err(Self::build_error_from_body(chunk)), }); @@ -252,7 +245,7 @@ impl IpfsClient { { let res = self.request_raw(req, form) .and_then(|(status, chunk)| match status { - StatusCode::Ok => String::from_utf8(chunk.to_vec()).map_err(From::from), + StatusCode::OK => String::from_utf8(chunk.to_vec()).map_err(From::from), _ => Err(Self::build_error_from_body(chunk)), }); @@ -270,7 +263,7 @@ impl IpfsClient { where Req: ApiRequest + Serialize, { - self.request_stream(req, form, |res| Box::new(res.body().from_err())) + self.request_stream(req, form, |res| Box::new(res.into_body().from_err())) } /// Generic method to return a streaming response of deserialized json @@ -286,13 +279,22 @@ impl IpfsClient { for<'de> Res: 'static + Deserialize<'de>, { self.request_stream(req, form, |res| { - let parse_stream_error = if let Some(trailer) = res.headers().get() { + let parse_stream_error = if let Some(trailer) = res.headers().get(TRAILER) { // Response has the Trailer header set. The StreamError trailer // is used to indicate that there was an error while streaming // data with Ipfs. // - match trailer { - &Trailer::StreamError => true, + if trailer == "X-Stream-Error" { + true + } else { + let err = ErrorKind::UnrecognizedTrailerHeader( + String::from_utf8_lossy(trailer.as_ref()).into(), + ); + + // There was an unrecognized trailer value. If that is the case, + // create a stream that immediately errors. + // + return Box::new(stream::once(Err(err.into()))); } } else { false diff --git a/ipfs-api/src/header.rs b/ipfs-api/src/header.rs index aec3c0a..9943bdb 100644 --- a/ipfs-api/src/header.rs +++ b/ipfs-api/src/header.rs @@ -6,76 +6,6 @@ // copied, modified, or distributed except according to those terms. // -use hyper; -use hyper::header::{self, Header, Raw}; -use std::fmt; +pub use hyper::header::TRAILER; -/// Header that is returned for streaming calls. -/// -/// A `Trailer` header indicates that after a streaming call, there will -/// be some additional information in the response. -/// -#[derive(Debug, Clone, Copy)] -pub enum Trailer { - /// This trailer indicates that an error header will be returned in - /// the stream if there is an error while streaming. - /// - StreamError, -} - -impl Header for Trailer { - fn header_name() -> &'static str { - "Trailer" - } - - fn parse_header(raw: &Raw) -> hyper::Result { - if let Some(bytes) = raw.one() { - let value = String::from_utf8_lossy(bytes); - - match value.as_ref() { - "X-Stream-Error" => Ok(Trailer::StreamError), - _ => Err(hyper::Error::Header), - } - } else { - Err(hyper::Error::Header) - } - } - - fn fmt_header(&self, f: &mut header::Formatter) -> fmt::Result { - let value = match *self { - Trailer::StreamError => "X-Stream-Error", - }; - - f.fmt_line(&value) - } -} - -/// This header is included while streaming if an error occured -/// while streaming the data. -/// -#[derive(Debug, Clone)] -pub struct XStreamError { - pub error: String, -} - -impl Header for XStreamError { - fn header_name() -> &'static str { - "X-Stream-Error" - } - - fn parse_header(raw: &Raw) -> hyper::Result { - if let Some(bytes) = raw.one() { - let value = String::from_utf8_lossy(bytes); - - Ok(XStreamError { - error: value.into_owned(), - }) - } else { - Err(hyper::Error::Header) - } - } - - fn fmt_header(&self, f: &mut header::Formatter) -> fmt::Result { - f.fmt_line(&self.error) - } -} +pub const X_STREAM_ERROR: &str = "x-stream-error"; diff --git a/ipfs-api/src/lib.rs b/ipfs-api/src/lib.rs index 1e584c3..0ef8fe0 100644 --- a/ipfs-api/src/lib.rs +++ b/ipfs-api/src/lib.rs @@ -6,6 +6,8 @@ // copied, modified, or distributed except according to those terms. // +#![recursion_limit = "128"] + //! Rust library for connecting to the IPFS HTTP API using tokio. //! //! ## Usage @@ -77,6 +79,7 @@ extern crate bytes; #[macro_use] extern crate error_chain; extern crate futures; +extern crate http; extern crate hyper; extern crate hyper_multipart_rfc7578 as hyper_multipart; extern crate serde; @@ -85,6 +88,7 @@ extern crate serde_derive; extern crate serde_json; extern crate serde_urlencoded; extern crate tokio; +extern crate tokio_codec; extern crate tokio_io; pub use client::IpfsClient; diff --git a/ipfs-api/src/read.rs b/ipfs-api/src/read.rs index 5a37b08..c0e3dd7 100644 --- a/ipfs-api/src/read.rs +++ b/ipfs-api/src/read.rs @@ -8,17 +8,14 @@ use bytes::BytesMut; use futures::{Async, Stream}; -use header::XStreamError; +use header::X_STREAM_ERROR; use hyper::Chunk; -use hyper::header::{Header, Raw}; use response::{Error, ErrorKind}; use serde::Deserialize; use serde_json; -use std::cmp; -use std::io::{self, Read}; -use std::marker::PhantomData; +use std::{cmp, io::{self, Read}, marker::PhantomData}; +use tokio_codec::Decoder; use tokio_io::AsyncRead; -use tokio_io::codec::Decoder; /// A decoder for a response where each line is a full json object. /// @@ -69,17 +66,12 @@ where Err(e) => { if self.parse_stream_error { match slice.iter().position(|&x| x == b':') { - Some(colon) - if &slice[..colon] == XStreamError::header_name().as_bytes() => - { - let raw = Raw::from(&slice[colon + 2..]); - - match XStreamError::parse_header(&raw) { - Ok(stream_error) => { - Err(ErrorKind::StreamError(stream_error.error).into()) - } - Err(_) => Err(e.into()), - } + Some(colon) if &slice[..colon] == X_STREAM_ERROR.as_bytes() => { + let e = ErrorKind::StreamError( + String::from_utf8_lossy(&slice[colon + 2..]).into(), + ); + + Err(e.into()) } _ => Err(e.into()), } diff --git a/ipfs-api/src/request/add.rs b/ipfs-api/src/request/add.rs index 08ac3b7..be7960d 100644 --- a/ipfs-api/src/request/add.rs +++ b/ipfs-api/src/request/add.rs @@ -16,5 +16,5 @@ impl_skip_serialize!(Add); impl ApiRequest for Add { const PATH: &'static str = "/add"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } diff --git a/ipfs-api/src/request/block.rs b/ipfs-api/src/request/block.rs index a021f61..24f5d39 100644 --- a/ipfs-api/src/request/block.rs +++ b/ipfs-api/src/request/block.rs @@ -26,7 +26,7 @@ impl_skip_serialize!(BlockPut); impl ApiRequest for BlockPut { const PATH: &'static str = "/block/put"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } #[derive(Serialize)] diff --git a/ipfs-api/src/request/config.rs b/ipfs-api/src/request/config.rs index ee6d1c8..e586278 100644 --- a/ipfs-api/src/request/config.rs +++ b/ipfs-api/src/request/config.rs @@ -24,7 +24,7 @@ impl_skip_serialize!(ConfigReplace); impl ApiRequest for ConfigReplace { const PATH: &'static str = "/config/replace"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } pub struct ConfigShow; diff --git a/ipfs-api/src/request/dag.rs b/ipfs-api/src/request/dag.rs index c1a6d0c..78705f9 100644 --- a/ipfs-api/src/request/dag.rs +++ b/ipfs-api/src/request/dag.rs @@ -26,5 +26,5 @@ impl_skip_serialize!(DagPut); impl ApiRequest for DagPut { const PATH: &'static str = "/dag/put"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } diff --git a/ipfs-api/src/request/files.rs b/ipfs-api/src/request/files.rs index 08aa500..179e1a4 100644 --- a/ipfs-api/src/request/files.rs +++ b/ipfs-api/src/request/files.rs @@ -112,5 +112,5 @@ pub struct FilesWrite<'a> { impl<'a> ApiRequest for FilesWrite<'a> { const PATH: &'static str = "/files/write"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } diff --git a/ipfs-api/src/request/mod.rs b/ipfs-api/src/request/mod.rs index dd86757..d8c1660 100644 --- a/ipfs-api/src/request/mod.rs +++ b/ipfs-api/src/request/mod.rs @@ -109,5 +109,5 @@ pub trait ApiRequest { /// Method used to make the request. /// - const METHOD: &'static ::hyper::Method = &::hyper::Method::Get; + const METHOD: &'static ::hyper::Method = &::hyper::Method::GET; } diff --git a/ipfs-api/src/request/tar.rs b/ipfs-api/src/request/tar.rs index 7d68a5e..26772b9 100644 --- a/ipfs-api/src/request/tar.rs +++ b/ipfs-api/src/request/tar.rs @@ -16,7 +16,7 @@ impl_skip_serialize!(TarAdd); impl ApiRequest for TarAdd { const PATH: &'static str = "/tar/add"; - const METHOD: &'static Method = &Method::Post; + const METHOD: &'static Method = &Method::POST; } #[derive(Serialize)] diff --git a/ipfs-api/src/response/error.rs b/ipfs-api/src/response/error.rs index 7075def..4cdd1c1 100644 --- a/ipfs-api/src/response/error.rs +++ b/ipfs-api/src/response/error.rs @@ -6,6 +6,7 @@ // copied, modified, or distributed except according to those terms. // +use http; use hyper; use serde_json; use serde_urlencoded; @@ -20,10 +21,11 @@ pub struct ApiError { error_chain! { foreign_links { - Http(hyper::error::Error); + Client(hyper::Error); + Http(http::Error); Parse(serde_json::Error); ParseUtf8(FromUtf8Error); - Url(hyper::error::UriError); + Url(http::uri::InvalidUri); Io(::std::io::Error); EncodeUrl(serde_urlencoded::ser::Error); } @@ -43,6 +45,13 @@ error_chain! { display("api returned an error while streaming: '{}'", err) } + /// API returned a trailer header with unrecognized value. + /// + UnrecognizedTrailerHeader(value: String) { + description("api returned a trailer header with an unknown value"), + display("api returned a trailer header with value: '{}'", value) + } + Uncategorized(err: String) { description("api returned an unknown error"), display("api returned '{}'", err) -- cgit v1.2.3 From 6acbf0e0f710ca1c897b1242e84a908ca32b45c3 Mon Sep 17 00:00:00 2001 From: Ferris Tseng Date: Wed, 27 Jun 2018 12:21:05 -0400 Subject: add send bounds where necessary --- ipfs-api/src/client.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ipfs-api/src/client.rs b/ipfs-api/src/client.rs index 30a4461..5309270 100644 --- a/ipfs-api/src/client.rs +++ b/ipfs-api/src/client.rs @@ -21,11 +21,11 @@ use tokio_codec::{Decoder, FramedRead}; /// A response returned by the HTTP client. /// -type AsyncResponse = Box>; +type AsyncResponse = Box + Send + 'static>; /// A future that returns a stream of responses. /// -type AsyncStreamResponse = Box>; +type AsyncStreamResponse = Box + Send + 'static>; /// Asynchronous Ipfs client. /// @@ -124,9 +124,9 @@ impl IpfsClient { fn process_stream_response( res: Response, decoder: D, - ) -> Box> + ) -> AsyncStreamResponse where - D: 'static + Decoder, + D: 'static + Decoder + Send, Res: 'static, { let stream = FramedRead::new(StreamReader::new(res.into_body().from_err()), decoder); @@ -172,8 +172,8 @@ impl IpfsClient { ) -> AsyncStreamResponse where Req: ApiRequest + Serialize, - Res: 'static, - F: 'static + Fn(hyper::Response) -> AsyncStreamResponse, + Res: 'static + Send, + F: 'static + Fn(hyper::Response) -> AsyncStreamResponse + Send, { match self.build_base_request(req, form) { Ok(req) => { @@ -181,7 +181,9 @@ impl IpfsClient { .request(req) .from_err() .map(move |res| { - let stream: Box> = match res.status() { + let stream: Box< + Stream + Send + 'static, + > = match res.status() { StatusCode::OK => process(res), // If the server responded with an error status code, the body // still needs to be read so an error can be built. This block will @@ -212,7 +214,7 @@ impl IpfsClient { fn request(&self, req: &Req, form: Option) -> AsyncResponse where Req: ApiRequest + Serialize, - for<'de> Res: 'static + Deserialize<'de>, + for<'de> Res: 'static + Deserialize<'de> + Send, { let res = self.request_raw(req, form) .and_then(|(status, chunk)| IpfsClient::process_json_response(status, chunk)); @@ -276,7 +278,7 @@ impl IpfsClient { ) -> AsyncStreamResponse where Req: ApiRequest + Serialize, - for<'de> Res: 'static + Deserialize<'de>, + for<'de> Res: 'static + Deserialize<'de> + Send, { self.request_stream(req, form, |res| { let parse_stream_error = if let Some(trailer) = res.headers().get(TRAILER) { -- cgit v1.2.3 From b786be1e6087a45f1db236f30d91803710c41274 Mon Sep 17 00:00:00 2001 From: Ferris Tseng Date: Wed, 27 Jun 2018 15:54:50 -0400 Subject: upgrade for hyper 0.12; use macros to build commands --- ipfs-cli/Cargo.toml | 2 +- ipfs-cli/src/command/add.rs | 50 ++++--- ipfs-cli/src/command/bitswap.rs | 173 ++++++++++++----------- ipfs-cli/src/command/block.rs | 128 +++++++++-------- ipfs-cli/src/command/bootstrap.rs | 88 ++++++------ ipfs-cli/src/command/cat.rs | 41 +++--- ipfs-cli/src/command/commands.rs | 38 ++--- ipfs-cli/src/command/config.rs | 67 ++++----- ipfs-cli/src/command/dag.rs | 64 +++++---- ipfs-cli/src/command/dht.rs | 121 ++++++++-------- ipfs-cli/src/command/diag.rs | 117 ++++++++-------- ipfs-cli/src/command/dns.rs | 47 ++++--- ipfs-cli/src/command/file.rs | 92 +++++++------ ipfs-cli/src/command/files.rs | 283 ++++++++++++++++++++------------------ ipfs-cli/src/command/filestore.rs | 103 +++++++------- ipfs-cli/src/command/mod.rs | 118 +++++++++++++++- ipfs-cli/src/command/shutdown.rs | 29 ++-- ipfs-cli/src/command/version.rs | 43 +++--- ipfs-cli/src/main.rs | 82 +++++------ 19 files changed, 942 insertions(+), 744 deletions(-) diff --git a/ipfs-cli/Cargo.toml b/ipfs-cli/Cargo.toml index f7fae2a..e0a11e6 100644 --- a/ipfs-cli/Cargo.toml +++ b/ipfs-cli/Cargo.toml @@ -10,5 +10,5 @@ license = "MIT OR Apache-2.0" [dependencies] clap = "2.27" futures = "0.1" +hyper = "0.12" ipfs-api = { path = "../ipfs-api" } -tokio-core = "0.1" diff --git a/ipfs-cli/src/command/add.rs b/ipfs-cli/src/command/add.rs index d732091..4382231 100644 --- a/ipfs-cli/src/command/add.rs +++ b/ipfs-cli/src/command/add.rs @@ -6,28 +6,38 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::{verify_file, EXPECTED_API, EXPECTED_FILE}; -use ipfs_api::IpfsClient; +use clap::App; +use command::{verify_file, CliCommand, EXPECTED_FILE}; +use futures::Future; use std::fs::File; -use tokio_core::reactor::Core; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand add => - (about: "Add file to IPFS") - (@arg INPUT: +required {verify_file} "File to add") - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "add"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand add => + (about: "Add file to IPFS") + (@arg INPUT: +required {verify_file} "File to add") + ) + } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - let path = args.value_of("INPUT").unwrap(); - let file = File::open(path).expect(EXPECTED_FILE); - let response = core.run(client.add(file)).expect(EXPECTED_API); + handle!( + (args, client) => { + let path = args.value_of("INPUT").unwrap(); + let file = File::open(path).expect(EXPECTED_FILE); - println!(); - println!(" name : {}", response.name); - println!(" hash : {}", response.hash); - println!(" size : {}", response.size); - println!(); + client + .add(file) + .map(|response| { + println!(); + println!(" name : {}", response.name); + println!(" hash : {}", response.hash); + println!(" size : {}", response.size); + println!(); + }) + } + ); } diff --git a/ipfs-cli/src/command/bitswap.rs b/ipfs-cli/src/command/bitswap.rs index a63c21f..95e6752 100644 --- a/ipfs-cli/src/command/bitswap.rs +++ b/ipfs-cli/src/command/bitswap.rs @@ -6,93 +6,106 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; -use tokio_core::reactor::Core; +use clap::App; +use command::CliCommand; +use futures::Future; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand bitswap => - (@setting SubcommandRequiredElseHelp) - (@subcommand ledger => - (about: "Show the current ledger for a peer") - (@arg PEER: +required "Peer to inspect") - ) - (@subcommand reprovide => - (about: "Triggers a reprovide") - ) - (@subcommand stat => - (about: "Show some diagnostic information on the bitswap agent") - ) - (@subcommand unwant => - (about: "Remove a given block from your wantlist") - (@arg KEY: +required "Key of the block to remove") - ) - (@subcommand wantlist => - (about: "Shows blocks currently on the wantlist") - ) - ) -} +pub struct Command; -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("ledger", Some(args)) => { - let peer = args.value_of("PEER").unwrap(); - let ledger = core.run(client.bitswap_ledger(peer)).expect(EXPECTED_API); +impl CliCommand for Command { + const NAME: &'static str = "bitswap"; - println!(); - println!(" peer : {}", ledger.peer); - println!(" value : {}", ledger.value); - println!(" sent : {}", ledger.sent); - println!(" recv : {}", ledger.recv); - println!(" exchanged : {}", ledger.exchanged); - println!(); - } - ("reprovide", _) => { - core.run(client.bitswap_reprovide()).expect(EXPECTED_API); - } - ("stat", _) => { - let stat = core.run(client.bitswap_stat()).expect(EXPECTED_API); + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand bitswap => + (@setting SubcommandRequiredElseHelp) + (@subcommand ledger => + (about: "Show the current ledger for a peer") + (@arg PEER: +required "Peer to inspect") + ) + (@subcommand reprovide => + (about: "Triggers a reprovide") + ) + (@subcommand stat => + (about: "Show some diagnostic information on the bitswap agent") + ) + (@subcommand unwant => + (about: "Remove a given block from your wantlist") + (@arg KEY: +required "Key of the block to remove") + ) + (@subcommand wantlist => + (about: "Shows blocks currently on the wantlist") + ) + ) + } - println!(); - println!(" provide_buf_len : {}", stat.provide_buf_len); - println!(" wantlist :"); - for want in stat.wantlist { - println!(" {}", want); - } - println!(" peers :"); - for peer in stat.peers { - println!(" {}", peer); - } - println!(" blocks_received : {}", stat.blocks_received); - println!(" data_received : {}", stat.data_received); - println!(" blocks_sent : {}", stat.blocks_sent); - println!(" data_sent : {}", stat.data_sent); - println!(" dup_blks_received : {}", stat.dup_blks_received); - println!(" dup_data_received : {}", stat.dup_data_received); - println!(); - } - ("unwant", Some(args)) => { - let key = args.value_of("KEY").unwrap(); + handle!( + client; + ("ledger", args) => { + let peer = args.value_of("PEER").unwrap(); - core.run(client.bitswap_unwant(key)).expect(EXPECTED_API); + client + .bitswap_ledger(peer) + .map(|ledger| { + println!(); + println!(" peer : {}", ledger.peer); + println!(" value : {}", ledger.value); + println!(" sent : {}", ledger.sent); + println!(" recv : {}", ledger.recv); + println!(" exchanged : {}", ledger.exchanged); + println!(); + }) + }, + ("reprovide", _args) => { + client.bitswap_reprovide().map(|_| ()) + }, + ("stat", _args) => { + client + .bitswap_stat() + .map(|stat| { + println!(); + println!(" provide_buf_len : {}", stat.provide_buf_len); + println!(" wantlist :"); + for want in stat.wantlist { + println!(" {}", want); + } + println!(" peers :"); + for peer in stat.peers { + println!(" {}", peer); + } + println!(" blocks_received : {}", stat.blocks_received); + println!(" data_received : {}", stat.data_received); + println!(" blocks_sent : {}", stat.blocks_sent); + println!(" data_sent : {}", stat.data_sent); + println!(" dup_blks_received : {}", stat.dup_blks_received); + println!(" dup_data_received : {}", stat.dup_data_received); + println!(); + }) + }, + ("unwant", args) => { + let key = args.value_of("KEY").unwrap(); - println!(); - println!(" OK"); - println!(); - } - ("wantlist", Some(args)) => { + client + .bitswap_unwant(key) + .map(|_| { + println!(); + println!(" OK"); + println!(); + }) + }, + ("wantlist", args) => { let peer = args.value_of("PEER"); - let wantlist = core.run(client.bitswap_wantlist(peer)).expect(EXPECTED_API); - println!(); - println!(" wantlist :"); - for key in wantlist.keys { - println!(" {}", key); - } - println!(); + client + .bitswap_wantlist(peer) + .map(|wantlist| { + println!(); + println!(" wantlist :"); + for key in wantlist.keys { + println!(" {}", key); + } + println!(); + }) } - _ => unreachable!(), - } + ); } diff --git a/ipfs-cli/src/command/block.rs b/ipfs-cli/src/command/block.rs index 7cccb5b..b4ca887 100644 --- a/ipfs-cli/src/command/block.rs +++ b/ipfs-cli/src/command/block.rs @@ -6,77 +6,87 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::{verify_file, EXPECTED_API, EXPECTED_FILE}; -use futures::stream::Stream; -use ipfs_api::IpfsClient; +use clap::App; +use command::{verify_file, CliCommand, EXPECTED_FILE}; +use futures::{Future, Stream}; use std::fs::File; use std::io::{self, Write}; -use tokio_core::reactor::Core; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand block => - (@setting SubcommandRequiredElseHelp) - (@subcommand get => - (about: "Get a raw IPFS block") - (@arg KEY: +required "The base58 multihash of an existing block") - ) - (@subcommand put => - (about: "Store a file as an IPFS block") - (@arg INPUT: +required {verify_file} "The file to store as an IPFS block") - ) - (@subcommand rm => - (about: "Removes an IPFS block") - (@arg KEY: +required "The base58 multihash of a block to remove") - ) - (@subcommand stat => - (about: "Get information about a raw IPFS block") - (@arg KEY: +required "The base58 multihash of the block to retrieve") - ) - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "block"; -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("get", Some(args)) => { + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand block => + (@setting SubcommandRequiredElseHelp) + (@subcommand get => + (about: "Get a raw IPFS block") + (@arg KEY: +required "The base58 multihash of an existing block") + ) + (@subcommand put => + (about: "Store a file as an IPFS block") + (@arg INPUT: +required {verify_file} "The file to store as an IPFS block") + ) + (@subcommand rm => + (about: "Removes an IPFS block") + (@arg KEY: +required "The base58 multihash of a block to remove") + ) + (@subcommand stat => + (about: "Get information about a raw IPFS block") + (@arg KEY: +required "The base58 multihash of the block to retrieve") + ) + ) + } + + handle!( + client; + ("get", args) => { let key = args.value_of("KEY").unwrap(); - let req = client - .block_get(key) - .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from)); - core.run(req).expect(EXPECTED_API); - } - ("put", Some(args)) => { + client + .block_get(key) + .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from)) + }, + ("put", args) => { let path = args.value_of("INPUT").unwrap(); let file = File::open(path).expect(EXPECTED_FILE); - let block = core.run(client.block_put(file)).expect(EXPECTED_API); - println!(); - println!(" key : {}", block.key); - println!(" size : {}", block.size); - println!(); - } - ("rm", Some(args)) => { + client + .block_put(file) + .map(|block| { + println!(); + println!(" key : {}", block.key); + println!(" size : {}", block.size); + println!(); + }) + }, + ("rm", args) => { let key = args.value_of("KEY").unwrap(); - let rm = core.run(client.block_rm(key)).expect(EXPECTED_API); - println!(); - println!(" hash : {}", rm.hash); - if let Some(error) = rm.error { - println!(" error : {}", error); - } - println!(); - } - ("stat", Some(args)) => { + client + .block_rm(key) + .map(|rm| { + println!(); + println!(" hash : {}", rm.hash); + if let Some(error) = rm.error { + println!(" error : {}", error); + } + println!(); + }) + }, + ("stat", args) => { let key = args.value_of("KEY").unwrap(); - let stat = core.run(client.block_stat(key)).expect(EXPECTED_API); - println!(); - println!(" key : {}", stat.key); - println!(" size : {}", stat.size); - println!(); + client + .block_stat(key) + .map(|stat| { + println!(); + println!(" key : {}", stat.key); + println!(" size : {}", stat.size); + println!(); + }) } - _ => unreachable!(), - } + ); } diff --git a/ipfs-cli/src/command/bootstrap.rs b/ipfs-cli/src/command/bootstrap.rs index dc3014e..af1e406 100644 --- a/ipfs-cli/src/command/bootstrap.rs +++ b/ipfs-cli/src/command/bootstrap.rs @@ -6,32 +6,9 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; -use tokio_core::reactor::Core; - -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand bootstrap => - (@setting SubcommandRequiredElseHelp) - (@subcommand add => - (@setting SubcommandRequiredElseHelp) - (@subcommand default => - (about: "Add default peers to the bootstrap list") - ) - ) - (@subcommand list => - (about: "Show peers in the bootstrap list") - ) - (@subcommand rm => - (@setting SubcommandRequiredElseHelp) - (@subcommand all => - (about: "Remove all peers from the bootstrap list") - ) - ) - ) -} +use clap::App; +use command::CliCommand; +use futures::Future; fn print_peers(peers: &[String]) { println!(); @@ -42,30 +19,47 @@ fn print_peers(peers: &[String]) { println!(); } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("add", Some(add)) => match add.subcommand() { - ("default", _) => { - let peers = core.run(client.bootstrap_add_default()) - .expect(EXPECTED_API); +pub struct Command; - print_peers(&peers.peers); - } - _ => unreachable!(), - }, - ("list", _) => { - let peers = core.run(client.bootstrap_list()).expect(EXPECTED_API); +impl CliCommand for Command { + const NAME: &'static str = "bootstrap"; - print_peers(&peers.peers); - } - ("rm", Some(rm)) => match rm.subcommand() { - ("all", _) => { - let peers = core.run(client.bootstrap_rm_all()).expect(EXPECTED_API); + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand bootstrap => + (@setting SubcommandRequiredElseHelp) + (@subcommand add => + (@setting SubcommandRequiredElseHelp) + (@subcommand default => + (about: "Add default peers to the bootstrap list") + ) + ) + (@subcommand list => + (about: "Show peers in the bootstrap list") + ) + (@subcommand rm => + (@setting SubcommandRequiredElseHelp) + (@subcommand all => + (about: "Remove all peers from the bootstrap list") + ) + ) + ) + } - print_peers(&peers.peers); + handle!( + client; + ("add") => { + ("default", _args) => { + client.bootstrap_add_default().map(|peers| print_peers(&peers.peers)) } - _ => unreachable!(), }, - _ => unreachable!(), - } + ("list", _args) => { + client.bootstrap_list().map(|peers| print_peers(&peers.peers)) + }, + ("rm") => { + ("all", _args) => { + client.bootstrap_rm_all().map(|peers| print_peers(&peers.peers)) + } + } + ); } diff --git a/ipfs-cli/src/command/cat.rs b/ipfs-cli/src/command/cat.rs index 1f77306..6e8a9e7 100644 --- a/ipfs-cli/src/command/cat.rs +++ b/ipfs-cli/src/command/cat.rs @@ -6,26 +6,31 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use futures::stream::Stream; -use ipfs_api::IpfsClient; +use clap::App; +use command::CliCommand; +use futures::{Future, Stream}; use std::io::{self, Write}; -use tokio_core::reactor::Core; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand cat => - (about: "Show IPFS object data") - (@arg PATH: +required "The path of the IPFS object to get") - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "cat"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand cat => + (about: "Show IPFS object data") + (@arg PATH: +required "The path of the IPFS object to get") + ) + } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - let path = args.value_of("PATH").unwrap(); - let req = client - .cat(&path) - .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from)); + handle!( + (args, client) => { + let path = args.value_of("PATH").unwrap(); - core.run(req).expect(EXPECTED_API); + client + .cat(&path) + .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from)) + } + ); } diff --git a/ipfs-cli/src/command/commands.rs b/ipfs-cli/src/command/commands.rs index ffba5f2..4ded502 100644 --- a/ipfs-cli/src/command/commands.rs +++ b/ipfs-cli/src/command/commands.rs @@ -1,5 +1,4 @@ // Copyright 2017 rust-ipfs-api Developers -// // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be @@ -7,17 +6,9 @@ // use clap::App; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; +use command::CliCommand; +use futures::Future; use ipfs_api::response::CommandsResponse; -use tokio_core::reactor::Core; - -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand commands => - (about: "List all available commands") - ) -} fn recursive_print_commands(cmd: CommandsResponse, stack: &mut Vec) { if cmd.subcommands.is_empty() { @@ -35,10 +26,25 @@ fn recursive_print_commands(cmd: CommandsResponse, stack: &mut Vec) { } } -pub fn handle(core: &mut Core, client: &IpfsClient) { - let commands = core.run(client.commands()).expect(EXPECTED_API); +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "commands"; - println!(); - recursive_print_commands(commands, &mut Vec::new()); - println!(); + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand commands => + (about: "List all available commands") + ) + } + + handle!( + (_args, client) => { + client.commands().map(|commands| { + println!(); + recursive_print_commands(commands, &mut Vec::new()); + println!(); + }) + } + ); } diff --git a/ipfs-cli/src/command/config.rs b/ipfs-cli/src/command/config.rs index e778816..1b0cf79 100644 --- a/ipfs-cli/src/command/config.rs +++ b/ipfs-cli/src/command/config.rs @@ -6,43 +6,46 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::{verify_file, EXPECTED_API, EXPECTED_FILE}; -use ipfs_api::IpfsClient; +use clap::App; +use command::{verify_file, CliCommand, EXPECTED_FILE}; +use futures::Future; use std::fs::File; -use tokio_core::reactor::Core; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand config => - (@setting SubcommandRequiredElseHelp) - (@subcommand edit => - (about: "Open the config file for editing") - ) - (@subcommand replace => - (about: "Replace the config file") - (@arg INPUT: +required {verify_file} "Config file to replace with") - ) - (@subcommand show => - (about: "Show the config file") - ) - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "config"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand config => + (@setting SubcommandRequiredElseHelp) + (@subcommand edit => + (about: "Open the config file for editing") + ) + (@subcommand replace => + (about: "Replace the config file") + (@arg INPUT: +required {verify_file} "Config file to replace with") + ) + (@subcommand show => + (about: "Show the config file") + ) + ) + } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("edit", _) => core.run(client.config_edit()).expect(EXPECTED_API), - ("replace", Some(args)) => { + handle!( + client; + ("edit", _args) => { + client.config_edit().map(|_| ()) + }, + ("replace", args) => { let path = args.value_of("INPUT").unwrap(); let config = File::open(path).expect(EXPECTED_FILE); - core.run(client.config_replace(config)).expect(EXPECTED_API); + client.config_replace(config).map(|_| ()) + }, + ("show", _args) => { + client.config_show().map(|config| println!("{}", config)) } - ("show", _) => { - let config = core.run(client.config_show()).expect(EXPECTED_API); - - println!("{}", config); - } - _ => unreachable!(), - } + ); } diff --git a/ipfs-cli/src/command/dag.rs b/ipfs-cli/src/command/dag.rs index c2b4f39..cd070ac 100644 --- a/ipfs-cli/src/command/dag.rs +++ b/ipfs-cli/src/command/dag.rs @@ -6,39 +6,43 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; -use tokio_core::reactor::Core; +use clap::App; +use command::CliCommand; +use futures::Future; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand dag => - (@setting SubcommandRequiredElseHelp) - (@subcommand get => - (about: "Get a dag node from IPFS") - (@arg KEY: +required "The key of the object to get") - ) - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "dag"; -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("get", Some(args)) => { + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand dag => + (@setting SubcommandRequiredElseHelp) + (@subcommand get => + (about: "Get a dag node from IPFS") + (@arg KEY: +required "The key of the object to get") + ) + ) + } + + handle!( + client; + ("get", args) => { let key = args.value_of("KEY").unwrap(); - let dag = core.run(client.dag_get(key)).expect(EXPECTED_API); - println!(); - if let Some(data) = dag.data { - println!(" data :"); - println!("{}", data); - } - println!(" links :"); - for link in dag.links { - println!(" {} ({}) ({:?})", link.name, link.size, link.cid); - } - println!(); + client.dag_get(key).map(|dag| { + println!(); + if let Some(data) = dag.data { + println!(" data :"); + println!("{}", data); + } + println!(" links :"); + for link in dag.links { + println!(" {} ({}) ({:?})", link.name, link.size, link.cid); + } + println!(); + }) } - _ => unreachable!(), - } + ); } diff --git a/ipfs-cli/src/command/dht.rs b/ipfs-cli/src/command/dht.rs index 9f95d3a..0e13f22 100644 --- a/ipfs-cli/src/command/dht.rs +++ b/ipfs-cli/src/command/dht.rs @@ -6,44 +6,10 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use futures::stream::Stream; -use ipfs_api::IpfsClient; +use clap::App; +use command::CliCommand; +use futures::{Future, Stream}; use ipfs_api::response::DhtMessage; -use tokio_core::reactor::Core; - -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand dht => - (@setting SubcommandRequiredElseHelp) - (@subcommand findpeer => - (about: "Query the DHT for all of the multiaddresses associated with a Peer ID") - (@arg PEER: +required "Peer to search for") - ) - (@subcommand findprovs => - (about: "Find peers in the DHT that can provide the given key") - (@arg KEY: +required "Key to search for") - ) - (@subcommand get => - (about: "Given a key, query the DHT for its best value") - (@arg KEY: +required "The key search for") - ) - (@subcommand provide => - (about: "Announce to the network that you are providing the given values") - (@arg KEY: +required "The key you are providing") - ) - (@subcommand put => - (about: "Write a key/value pair to the DHT") - (@arg KEY: +required "The key to store the value at") - (@arg VALUE: +required "The value to store") - ) - (@subcommand query => - (about: "Find the closest peer to a given peer by querying the DHT") - (@arg PEER: +required "The peer to run the query against") - ) - ) -} fn print_dht_response(res: DhtMessage) -> Result<(), E> { println!(); @@ -64,42 +30,75 @@ fn print_dht_response(res: DhtMessage) -> Result<(), E> { Ok(()) } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - let req = match args.subcommand() { - ("findpeer", Some(args)) => { +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "dht"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand dht => + (@setting SubcommandRequiredElseHelp) + (@subcommand findpeer => + (about: "Query the DHT for all of the multiaddresses associated with a Peer ID") + (@arg PEER: +required "Peer to search for") + ) + (@subcommand findprovs => + (about: "Find peers in the DHT that can provide the given key") + (@arg KEY: +required "Key to search for") + ) + (@subcommand get => + (about: "Given a key, query the DHT for its best value") + (@arg KEY: +required "The key search for") + ) + (@subcommand provide => + (about: "Announce to the network that you are providing the given values") + (@arg KEY: +required "The key you are providing") + ) + (@subcommand put => + (about: "Write a key/value pair to the DHT") + (@arg KEY: +required "The key to store the value at") + (@arg VALUE: +required "The value to store") + ) + (@subcommand query => + (about: "Find the closest peer to a given peer by querying the DHT") + (@arg PEER: +required "The peer to run the query against") + ) + ) + } + + handle!( + client; + ("findpeer", args) => { let peer = args.value_of("PEER").unwrap(); - client.dht_findpeer(peer) - } - ("findprovs", Some(args)) => { + client.dht_findpeer(peer).for_each(print_dht_response) + }, + ("findprovs", args) => { let key = args.value_of("KEY").unwrap(); - client.dht_findprovs(key) - } - ("get", Some(args)) => { + client.dht_findprovs(key).for_each(print_dht_response) + }, + ("get", args) => { let key = args.value_of("KEY").unwrap(); - client.dht_get(key) - } - ("provide", Some(args)) => { + client.dht_get(key).for_each(print_dht_response) + }, + ("provide", args) => { let key = args.value_of("KEY").unwrap(); - client.dht_provide(&key) - } - ("put", Some(args)) => { + client.dht_provide(&key).for_each(print_dht_response) + }, + ("put", args) => { let key = args.value_of("KEY").unwrap(); let val = args.value_of("VALUE").unwrap(); - client.dht_put(key, val) - } - ("query", Some(args)) => { + client.dht_put(key, val).for_each(print_dht_response) + }, + ("query", args) => { let peer = args.value_of("PEER").unwrap(); - client.dht_query(peer) + client.dht_query(peer).for_each(print_dht_response) } - _ => unreachable!(), - }; - - core.run(req.for_each(print_dht_response)) - .expect(EXPECTED_API); + ); } diff --git a/ipfs-cli/src/command/diag.rs b/ipfs-cli/src/command/diag.rs index 7ce6c22..1c5dee9 100644 --- a/ipfs-cli/src/command/diag.rs +++ b/ipfs-cli/src/command/diag.rs @@ -6,69 +6,76 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, Arg, ArgMatches, SubCommand}; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; -use tokio_core::reactor::Core; +use clap::{App, Arg, SubCommand}; +use command::CliCommand; +use futures::Future; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - // The clap macro does not allow hyphenated command names, - // so the `set-time` command has to be manually instantiated. - // - let set_time_command = SubCommand::with_name("set-time") - .about("Set how long to keep inactive requests in the log") - .arg( - Arg::with_name("TIME") - .required(true) - .index(1) - .help("Time to keep inactive requests in the log"), - ); +pub struct Command; - clap_app!( - @subcommand diag => - (@setting SubcommandRequiredElseHelp) - (@subcommand cmds => +impl CliCommand for Command { + const NAME: &'static str = "diag"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + // The clap macro does not allow hyphenated command names, + // so the `set-time` command has to be manually instantiated. + // + let set_time_command = SubCommand::with_name("set-time") + .about("Set how long to keep inactive requests in the log") + .arg( + Arg::with_name("TIME") + .required(true) + .index(1) + .help("Time to keep inactive requests in the log"), + ); + + clap_app!( + @subcommand diag => (@setting SubcommandRequiredElseHelp) - (@subcommand clear => - (about: "Clear inactive requests from the log") + (@subcommand cmds => + (@setting SubcommandRequiredElseHelp) + (@subcommand clear => + (about: "Clear inactive requests from the log") + ) + (subcommand: set_time_command) ) - (subcommand: set_time_command) - ) - (@subcommand sys => - (about: "Print system diagnostic information") - ) - ) -} - -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - match args.subcommand() { - ("cmds", Some(args)) => match args.subcommand() { - ("clear", _) => { - core.run(client.diag_cmds_clear()).expect(EXPECTED_API); + (@subcommand sys => + (about: "Print system diagnostic information") + ) + ) + } - println!(""); - println!(" OK"); - println!(""); - } - ("set-time", Some(args)) => { + handle!( + client; + ("cmds") => { + ("clear", _args) => { + client + .diag_cmds_clear() + .map(|_| { + println!(""); + println!(" OK"); + println!(""); + }) + }, + ("set-time", args) => { let time = args.value_of("TIME").unwrap(); - core.run(client.diag_cmds_set_time(&time)) - .expect(EXPECTED_API); - - println!(""); - println!(" OK"); - println!(""); + client + .diag_cmds_set_time(&time) + .map(|_| { + println!(""); + println!(" OK"); + println!(""); + }) } - _ => unreachable!(), }, - ("sys", _) => { - let sys = core.run(client.diag_sys()).expect(EXPECTED_API); - - println!(); - println!(" {}", sys); - println!(); + ("sys", _args) => { + client + .diag_sys() + .map(|sys| { + println!(); + println!(" {}", sys); + println!(); + }) } - _ => unreachable!(), - } + ); } diff --git a/ipfs-cli/src/command/dns.rs b/ipfs-cli/src/command/dns.rs index ba5ab94..5f60d09 100644 --- a/ipfs-cli/src/command/dns.rs +++ b/ipfs-cli/src/command/dns.rs @@ -6,26 +6,35 @@ // copied, modified, or distributed except according to those terms. // -use clap::{App, ArgMatches}; -use command::EXPECTED_API; -use ipfs_api::IpfsClient; -use tokio_core::reactor::Core; +use clap::App; +use command::CliCommand; +use futures::Future; -pub fn signature<'a, 'b>() -> App<'a, 'b> { - clap_app!( - @subcommand dns => - (about: "Resolve a DNS link") - (@arg PATH: +required "The domain name to resolve") - (@arg recursive: -r --recursive "Resolve until the result is not a DNS link") - ) -} +pub struct Command; + +impl CliCommand for Command { + const NAME: &'static str = "dns"; + + fn signature<'a, 'b>() -> App<'a, 'b> { + clap_app!( + @subcommand dns => + (about: "Resolve a DNS link") + (@arg PATH: +required "The domain name to resolve") + (@arg recursive: -r --recursive "Resolve until the result is not a DNS link") + ) + } -pub fn handle(core: &mut Core, client: &IpfsClient, args: &ArgMatches) { - let path = args.value_of("PATH").unwrap(); - let req = client.dns(path, args.is_present("recursive")); - let res = core.run(req).expect(EXPECTED_API); + handle!( + (args, client) => { + let path = args.value_of("PATH").unwrap(); - println!(); -