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-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"

View file

@ -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"

View file

@ -71,8 +71,6 @@ impl<S> Service for QueryCrate<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
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<S> Service for QueryCrate<S>
_ => format!("{}/{}/{}", &lower_name[0..2], &lower_name[2..4], lower_name),
};
let uri_future = format!("{}/master/{}", CRATES_INDEX_BASE_URI, path)
.parse::<Uri>().into_future().from_err();
let uri = try_future_box!(format!("{}/master/{}", CRATES_INDEX_BASE_URI, path)
.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| {
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::<RegistryPackage>(s))
.collect::<Result<_, _>>()?;
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::<RegistryPackage>(s))
.collect::<Result<_, _>>()?;
Ok(packages)
});
decode_future
.and_then(move |pkgs| convert_pkgs(&crate_name, pkgs))
.into()
}))
}
}

View file

@ -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<S> Service for GetPopularRepos<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
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();
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::<Result<Vec<_>, _>>()
}))
}
})
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::<Result<Vec<_>, _>>()
}).into()
}))
}
}

View file

@ -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<S> Service for RetrieveFileAtPath<S>
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
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()
}))
}
}

View file

@ -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;