use try_future crate to simplify async logic

This commit is contained in:
Sam Rijs 2018-03-06 22:20:23 +11:00
parent b2e8e96142
commit 8ec8952304
6 changed files with 70 additions and 68 deletions

10
Cargo.lock generated
View file

@ -716,6 +716,7 @@ dependencies = [
"tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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]] [[package]]
@ -877,6 +878,14 @@ dependencies = [
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "unicase" name = "unicase"
version = "2.1.0" 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-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 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 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 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 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" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"

View file

@ -25,6 +25,7 @@ slog-json = "2.2.0"
tokio-core = "0.1.12" tokio-core = "0.1.12"
tokio-service = "0.1.0" tokio-service = "0.1.0"
toml = "0.4.5" toml = "0.4.5"
try_future = "0.1.1"
[dependencies.badge] [dependencies.badge]
version = "0.2.0" version = "0.2.0"

View file

@ -71,8 +71,6 @@ impl<S> Service for QueryCrate<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>; type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
fn call(&self, crate_name: CrateName) -> Self::Future { fn call(&self, crate_name: CrateName) -> Self::Future {
let service = self.0.clone();
let lower_name = crate_name.as_ref().to_lowercase(); let lower_name = crate_name.as_ref().to_lowercase();
let path = match lower_name.len() { let path = match lower_name.len() {
@ -82,17 +80,17 @@ impl<S> Service for QueryCrate<S>
_ => format!("{}/{}/{}", &lower_name[0..2], &lower_name[2..4], lower_name), _ => format!("{}/{}/{}", &lower_name[0..2], &lower_name[2..4], lower_name),
}; };
let uri_future = format!("{}/master/{}", CRATES_INDEX_BASE_URI, path) let uri = try_future_box!(format!("{}/master/{}", CRATES_INDEX_BASE_URI, path)
.parse::<Uri>().into_future().from_err(); .parse::<Uri>());
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| { Box::new(self.0.call(request).from_err().and_then(move |response| {
let status = response.status(); let status = response.status();
if !status.is_success() { if !status.is_success() {
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri))) try_future!(Err(format_err!("Status code {} for URI {}", status, uri)));
} else { }
let body_future = response.body().concat2().from_err(); let body_future = response.body().concat2().from_err();
let decode_future = body_future.and_then(move |body| { let decode_future = body_future.and_then(move |body| {
let string_body = str::from_utf8(body.as_ref())?; let string_body = str::from_utf8(body.as_ref())?;
@ -103,10 +101,10 @@ impl<S> Service for QueryCrate<S>
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
Ok(packages) Ok(packages)
}); });
let convert_future = decode_future.and_then(move |pkgs| convert_pkgs(&crate_name, pkgs));
future::Either::B(convert_future) decode_future
} .and_then(move |pkgs| convert_pkgs(&crate_name, pkgs))
}) .into()
})) }))
} }
} }

View file

@ -1,5 +1,5 @@
use failure::Error; use failure::Error;
use futures::{Future, IntoFuture, Stream, future}; use futures::{Future, Stream};
use hyper::{Error as HyperError, Method, Request, Response, Uri}; use hyper::{Error as HyperError, Method, Request, Response, Uri};
use hyper::header::UserAgent; use hyper::header::UserAgent;
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
@ -51,31 +51,27 @@ impl<S> Service for GetPopularRepos<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>; type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
fn call(&self, _req: ()) -> Self::Future { 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::<Uri>());
let uri_future = format!("{}/search/repositories?q=language:rust&sort=stars", GITHUB_API_BASE_URI)
.parse().into_future().from_err();
Box::new(uri_future.and_then(move |uri| {
let mut request = Request::new(Method::Get, uri); let mut request = Request::new(Method::Get, uri);
request.headers_mut().set(UserAgent::new("deps.rs")); request.headers_mut().set(UserAgent::new("deps.rs"));
service.call(request).from_err().and_then(|response| { Box::new(self.0.call(request).from_err().and_then(|response| {
let status = response.status(); let status = response.status();
if !status.is_success() { if !status.is_success() {
future::Either::A(future::err(format_err!("Status code {} for popular repo search", status))) try_future!(Err(format_err!("Status code {} for popular repo search", status)));
} else { }
let body_future = response.body().concat2().from_err(); let body_future = response.body().concat2().from_err();
let decode_future = body_future let decode_future = body_future
.and_then(|body| serde_json::from_slice(body.as_ref()).map_err(|err| err.into())); .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| { decode_future.and_then(|search_response: GithubSearchResponse| {
search_response.items.into_iter().map(|item| { search_response.items.into_iter().map(|item| {
let path = RepoPath::from_parts("github", &item.owner.login, &item.name)?; let path = RepoPath::from_parts("github", &item.owner.login, &item.name)?;
Ok(Repository { path, description: item.description }) Ok(Repository { path, description: item.description })
}).collect::<Result<Vec<_>, _>>() }).collect::<Result<Vec<_>, _>>()
})) }).into()
}
})
})) }))
} }
} }

View file

@ -1,5 +1,5 @@
use failure::Error; use failure::Error;
use futures::{Future, IntoFuture, Stream, future}; use futures::{Future, Stream};
use hyper::{Error as HyperError, Method, Request, Response}; use hyper::{Error as HyperError, Method, Request, Response};
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
use tokio_service::Service; use tokio_service::Service;
@ -25,36 +25,32 @@ impl<S> Service for RetrieveFileAtPath<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>; type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
fn call(&self, req: Self::Request) -> Self::Future { fn call(&self, req: Self::Request) -> Self::Future {
let service = self.0.clone();
let (repo_path, path) = req; let (repo_path, path) = req;
let uri = match &repo_path.site { let uri = match &repo_path.site {
&RepoSite::Github => { &RepoSite::Github => {
github::get_manifest_uri(&repo_path, &path) try_future_box!(github::get_manifest_uri(&repo_path, &path))
}, },
&RepoSite::Gitlab => { &RepoSite::Gitlab => {
gitlab::get_manifest_uri(&repo_path, &path) try_future_box!(gitlab::get_manifest_uri(&repo_path, &path))
}, },
&RepoSite::Bitbucket => { &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| { Box::new(self.0.call(request).from_err().and_then(move |response| {
let status = response.status(); let status = response.status();
if !status.is_success() { if !status.is_success() {
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri))) try_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)
} }
})
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()
})) }))
} }
} }

View file

@ -25,6 +25,7 @@ extern crate slog_json;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_service; extern crate tokio_service;
extern crate toml; extern crate toml;
#[macro_use] extern crate try_future;
mod utils; mod utils;
mod models; mod models;