From 8ec89523043cfd779bc9b21a453fe85bda2bedda Mon Sep 17 00:00:00 2001 From: Sam Rijs Date: Tue, 6 Mar 2018 22:20:23 +1100 Subject: [PATCH] use try_future crate to simplify async logic --- Cargo.lock | 10 ++++++++ Cargo.toml | 1 + src/interactors/crates.rs | 48 +++++++++++++++++++-------------------- src/interactors/github.rs | 42 ++++++++++++++++------------------ src/interactors/mod.rs | 36 +++++++++++++---------------- src/main.rs | 1 + 6 files changed, 70 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8ad3b8..bd4bfa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -716,6 +716,7 @@ dependencies = [ "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "try_future 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -877,6 +878,14 @@ dependencies = [ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "try_future" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "2.1.0" @@ -1056,6 +1065,7 @@ dependencies = [ "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"checksum try_future 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5991a93204dab99f8f1f8ac657eb070315dbd71a79f15fa4f86d983fa880545" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" diff --git a/Cargo.toml b/Cargo.toml index e3020a3..e4d433c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ slog-json = "2.2.0" tokio-core = "0.1.12" tokio-service = "0.1.0" toml = "0.4.5" +try_future = "0.1.1" [dependencies.badge] version = "0.2.0" diff --git a/src/interactors/crates.rs b/src/interactors/crates.rs index 060b01d..17c06e6 100644 --- a/src/interactors/crates.rs +++ b/src/interactors/crates.rs @@ -71,8 +71,6 @@ impl Service for QueryCrate type Future = Box>; fn call(&self, crate_name: CrateName) -> Self::Future { - let service = self.0.clone(); - let lower_name = crate_name.as_ref().to_lowercase(); let path = match lower_name.len() { @@ -82,31 +80,31 @@ impl Service for QueryCrate _ => format!("{}/{}/{}", &lower_name[0..2], &lower_name[2..4], lower_name), }; - let uri_future = format!("{}/master/{}", CRATES_INDEX_BASE_URI, path) - .parse::().into_future().from_err(); + let uri = try_future_box!(format!("{}/master/{}", CRATES_INDEX_BASE_URI, path) + .parse::()); - Box::new(uri_future.and_then(move |uri| { - let request = Request::new(Method::Get, uri.clone()); + let request = Request::new(Method::Get, uri.clone()); - service.call(request).from_err().and_then(move |response| { - let status = response.status(); - if !status.is_success() { - future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri))) - } else { - let body_future = response.body().concat2().from_err(); - let decode_future = body_future.and_then(move |body| { - let string_body = str::from_utf8(body.as_ref())?; - let packages = string_body.lines() - .map(|s| s.trim()) - .filter(|s| !s.is_empty()) - .map(|s| serde_json::from_str::(s)) - .collect::>()?; - Ok(packages) - }); - let convert_future = decode_future.and_then(move |pkgs| convert_pkgs(&crate_name, pkgs)); - future::Either::B(convert_future) - } - }) + Box::new(self.0.call(request).from_err().and_then(move |response| { + let status = response.status(); + if !status.is_success() { + try_future!(Err(format_err!("Status code {} for URI {}", status, uri))); + } + + let body_future = response.body().concat2().from_err(); + let decode_future = body_future.and_then(move |body| { + let string_body = str::from_utf8(body.as_ref())?; + let packages = string_body.lines() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .map(|s| serde_json::from_str::(s)) + .collect::>()?; + Ok(packages) + }); + + decode_future + .and_then(move |pkgs| convert_pkgs(&crate_name, pkgs)) + .into() })) } } diff --git a/src/interactors/github.rs b/src/interactors/github.rs index 3e90bbd..8252ac0 100644 --- a/src/interactors/github.rs +++ b/src/interactors/github.rs @@ -1,5 +1,5 @@ use failure::Error; -use futures::{Future, IntoFuture, Stream, future}; +use futures::{Future, Stream}; use hyper::{Error as HyperError, Method, Request, Response, Uri}; use hyper::header::UserAgent; use relative_path::RelativePathBuf; @@ -51,31 +51,27 @@ impl Service for GetPopularRepos type Future = Box>; fn call(&self, _req: ()) -> Self::Future { - let service = self.0.clone(); + let uri = try_future_box!(format!("{}/search/repositories?q=language:rust&sort=stars", GITHUB_API_BASE_URI) + .parse::()); - let uri_future = format!("{}/search/repositories?q=language:rust&sort=stars", GITHUB_API_BASE_URI) - .parse().into_future().from_err(); + let mut request = Request::new(Method::Get, uri); + request.headers_mut().set(UserAgent::new("deps.rs")); - Box::new(uri_future.and_then(move |uri| { - let mut request = Request::new(Method::Get, uri); - request.headers_mut().set(UserAgent::new("deps.rs")); + Box::new(self.0.call(request).from_err().and_then(|response| { + let status = response.status(); + if !status.is_success() { + try_future!(Err(format_err!("Status code {} for popular repo search", status))); + } - service.call(request).from_err().and_then(|response| { - let status = response.status(); - if !status.is_success() { - future::Either::A(future::err(format_err!("Status code {} for popular repo search", status))) - } else { - let body_future = response.body().concat2().from_err(); - let decode_future = body_future - .and_then(|body| serde_json::from_slice(body.as_ref()).map_err(|err| err.into())); - future::Either::B(decode_future.and_then(|search_response: GithubSearchResponse| { - search_response.items.into_iter().map(|item| { - let path = RepoPath::from_parts("github", &item.owner.login, &item.name)?; - Ok(Repository { path, description: item.description }) - }).collect::, _>>() - })) - } - }) + let body_future = response.body().concat2().from_err(); + let decode_future = body_future + .and_then(|body| serde_json::from_slice(body.as_ref()).map_err(|err| err.into())); + decode_future.and_then(|search_response: GithubSearchResponse| { + search_response.items.into_iter().map(|item| { + let path = RepoPath::from_parts("github", &item.owner.login, &item.name)?; + Ok(Repository { path, description: item.description }) + }).collect::, _>>() + }).into() })) } } diff --git a/src/interactors/mod.rs b/src/interactors/mod.rs index 105eee6..42b680f 100644 --- a/src/interactors/mod.rs +++ b/src/interactors/mod.rs @@ -1,5 +1,5 @@ use failure::Error; -use futures::{Future, IntoFuture, Stream, future}; +use futures::{Future, Stream}; use hyper::{Error as HyperError, Method, Request, Response}; use relative_path::RelativePathBuf; use tokio_service::Service; @@ -25,36 +25,32 @@ impl Service for RetrieveFileAtPath type Future = Box>; fn call(&self, req: Self::Request) -> Self::Future { - let service = self.0.clone(); - let (repo_path, path) = req; let uri = match &repo_path.site { &RepoSite::Github => { - github::get_manifest_uri(&repo_path, &path) + try_future_box!(github::get_manifest_uri(&repo_path, &path)) }, &RepoSite::Gitlab => { - gitlab::get_manifest_uri(&repo_path, &path) + try_future_box!(gitlab::get_manifest_uri(&repo_path, &path)) }, &RepoSite::Bitbucket => { - bitbucket::get_manifest_uri(&repo_path, &path) + try_future_box!(bitbucket::get_manifest_uri(&repo_path, &path)) } }; - let uri_future = uri.into_future().from_err(); - Box::new(uri_future.and_then(move |uri| { - let request = Request::new(Method::Get, uri.clone()); + let request = Request::new(Method::Get, uri.clone()); - service.call(request).from_err().and_then(move |response| { - let status = response.status(); - if !status.is_success() { - future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri))) - } else { - let body_future = response.body().concat2().from_err(); - let decode_future = body_future - .and_then(|body| String::from_utf8(body.to_vec()).map_err(|err| err.into())); - future::Either::B(decode_future) - } - }) + Box::new(self.0.call(request).from_err().and_then(move |response| { + let status = response.status(); + if !status.is_success() { + try_future!(Err(format_err!("Status code {} for URI {}", status, uri))); + } + + let body_future = response.body().concat2().from_err(); + + body_future + .and_then(|body| String::from_utf8(body.to_vec()).map_err(|err| err.into())) + .into() })) } } diff --git a/src/main.rs b/src/main.rs index 5584621..4811c16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ extern crate slog_json; extern crate tokio_core; extern crate tokio_service; extern crate toml; +#[macro_use] extern crate try_future; mod utils; mod models;