refactor status reporting

This commit is contained in:
Sam Rijs 2018-01-27 12:50:22 +11:00
parent adab7fdf74
commit 9dbc9c925c

View file

@ -11,12 +11,17 @@ use slog::Logger;
use tokio_service::Service; use tokio_service::Service;
use ::assets; use ::assets;
use ::engine::Engine; use ::engine::{Engine, AnalyzeDependenciesOutcome};
use ::models::repo::RepoPath; use ::models::repo::RepoPath;
#[derive(Clone, Copy)]
enum StatusFormat {
Json,
Svg
}
enum Route { enum Route {
StatusJson, Status(StatusFormat)
StatusSvg
} }
#[derive(Clone)] #[derive(Clone)]
@ -28,8 +33,8 @@ pub struct Api {
impl Api { impl Api {
pub fn new(engine: Engine) -> Api { pub fn new(engine: Engine) -> Api {
let mut router = Router::new(); let mut router = Router::new();
router.add("/repo/:site/:qual/:name/status.json", Route::StatusJson); router.add("/repo/:site/:qual/:name/status.json", Route::Status(StatusFormat::Json));
router.add("/repo/:site/:qual/:name/status.svg", Route::StatusSvg); router.add("/repo/:site/:qual/:name/status.svg", Route::Status(StatusFormat::Svg));
Api { engine, router: Arc::new(router) } Api { engine, router: Arc::new(router) }
} }
@ -65,14 +70,9 @@ impl Service for Api {
fn call(&self, req: Request) -> Self::Future { fn call(&self, req: Request) -> Self::Future {
if let Ok(route_match) = self.router.recognize(req.uri().path()) { if let Ok(route_match) = self.router.recognize(req.uri().path()) {
match route_match.handler { match route_match.handler {
&Route::StatusJson => { &Route::Status(format) => {
if *req.method() == Method::Get { if *req.method() == Method::Get {
return Box::new(self.status_json(req, route_match.params)); return Box::new(self.status(req, route_match.params, format));
}
},
&Route::StatusSvg => {
if *req.method() == Method::Get {
return Box::new(self.status_svg(req, route_match.params));
} }
} }
} }
@ -85,7 +85,9 @@ impl Service for Api {
} }
impl Api { impl Api {
fn status_json<'r>(&self, _req: Request, params: Params) -> impl Future<Item=Response, Error=HyperError> { fn status<'r>(&self, _req: Request, params: Params, format: StatusFormat) ->
impl Future<Item=Response, Error=HyperError>
{
let engine = self.engine.clone(); let engine = self.engine.clone();
let site = params.find("site").expect("route param 'site' not found"); let site = params.find("site").expect("route param 'site' not found");
@ -101,7 +103,7 @@ impl Api {
future::Either::A(future::ok(response)) future::Either::A(future::ok(response))
}, },
Ok(repo_path) => { Ok(repo_path) => {
future::Either::B(engine.analyze_dependencies(repo_path).then(|analyze_result| { future::Either::B(engine.analyze_dependencies(repo_path).then(move |analyze_result| {
match analyze_result { match analyze_result {
Err(err) => { Err(err) => {
let mut response = Response::new(); let mut response = Response::new();
@ -110,32 +112,7 @@ impl Api {
future::Either::A(future::ok(response)) future::Either::A(future::ok(response))
}, },
Ok(analysis_outcome) => { Ok(analysis_outcome) => {
let single = AnalyzeDependenciesResponseSingle { let response = Api::status_format_analysis(analysis_outcome, format);
dependencies: analysis_outcome.deps.main.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect(),
dev_dependencies: analysis_outcome.deps.dev.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect(),
build_dependencies: analysis_outcome.deps.build.into_iter()
.map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
required: analyzed.required,
latest: analyzed.latest
})).collect()
};
let multi = AnalyzeDependenciesResponse {
crates: vec![(analysis_outcome.name.into(), single)].into_iter().collect()
};
let mut response = Response::new()
.with_header(ContentType::json())
.with_body(serde_json::to_string(&multi).unwrap());
future::Either::B(future::ok(response)) future::Either::B(future::ok(response))
} }
} }
@ -145,44 +122,46 @@ impl Api {
}) })
} }
fn status_svg<'r>(&self, _req: Request, params: Params) -> impl Future<Item=Response, Error=HyperError> { fn status_format_analysis(analysis_outcome: AnalyzeDependenciesOutcome, format: StatusFormat) -> Response {
let engine = self.engine.clone(); match format {
StatusFormat::Json => {
let site = params.find("site").expect("route param 'site' not found"); let single = AnalyzeDependenciesResponseSingle {
let qual = params.find("qual").expect("route param 'qual' not found"); dependencies: analysis_outcome.deps.main.into_iter()
let name = params.find("name").expect("route param 'name' not found"); .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
outdated: analyzed.is_outdated(),
RepoPath::from_parts(site, qual, name).into_future().then(move |repo_path_result| { required: analyzed.required,
match repo_path_result { latest: analyzed.latest
Err(err) => { })).collect(),
let mut response = Response::new(); dev_dependencies: analysis_outcome.deps.dev.into_iter()
response.set_status(StatusCode::BadRequest); .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
response.set_body(format!("{:?}", err)); outdated: analyzed.is_outdated(),
future::Either::A(future::ok(response)) required: analyzed.required,
}, latest: analyzed.latest
Ok(repo_path) => { })).collect(),
future::Either::B(engine.analyze_dependencies(repo_path).then(|analyze_result| { build_dependencies: analysis_outcome.deps.build.into_iter()
match analyze_result { .map(|(name, analyzed)| (name.into(), AnalyzeDependenciesResponseDetail {
Err(err) => { outdated: analyzed.is_outdated(),
let mut response = Response::new(); required: analyzed.required,
response.set_status(StatusCode::InternalServerError); latest: analyzed.latest
response.set_body(format!("{:?}", err)); })).collect()
future::Either::A(future::ok(response)) };
}, let multi = AnalyzeDependenciesResponse {
Ok(analysis_outcome) => { crates: vec![(analysis_outcome.name.into(), single)].into_iter().collect()
let mut response = Response::new() };
.with_header(ContentType("image/svg+xml;charset=utf-8".parse().unwrap())); Response::new()
if analysis_outcome.deps.any_outdated() { .with_header(ContentType::json())
response.set_body(assets::BADGE_OUTDATED_SVG.to_vec()); .with_body(serde_json::to_string(&multi).unwrap())
} else { },
response.set_body(assets::BADGE_UPTODATE_SVG.to_vec()); StatusFormat::Svg => {
} let mut response = Response::new()
future::Either::B(future::ok(response)) .with_header(ContentType("image/svg+xml;charset=utf-8".parse().unwrap()));
} if analysis_outcome.deps.any_outdated() {
} response.set_body(assets::BADGE_OUTDATED_SVG.to_vec());
})) } else {
response.set_body(assets::BADGE_UPTODATE_SVG.to_vec());
} }
response
} }
}) }
} }
} }