implement redirect for crate report

This commit is contained in:
Sam Rijs 2018-02-17 10:15:15 +11:00
parent 8939b41e32
commit e0352539bd
3 changed files with 86 additions and 7 deletions

View file

@ -9,6 +9,7 @@ use hyper::Client;
use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;
use relative_path::{RelativePath, RelativePathBuf};
use semver::VersionReq;
use slog::Logger;
use tokio_service::Service;
@ -136,6 +137,23 @@ impl Engine {
})
}
pub fn find_latest_crate_release(&self, name: CrateName, req: Option<VersionReq>) ->
impl Future<Item=Option<CrateRelease>, Error=Error>
{
self.query_crate.call(name).from_err().map(move |query_response| {
if let Some(vreq) = req {
query_response.releases.iter()
.filter(|release| vreq.matches(&release.version))
.max_by(|r1, r2| r1.version.cmp(&r2.version))
.cloned()
} else {
query_response.releases.iter()
.max_by(|r1, r2| r1.version.cmp(&r2.version))
.cloned()
}
})
}
fn fetch_releases<I: IntoIterator<Item=CrateName>>(&self, names: I) ->
impl Iterator<Item=impl Future<Item=Vec<CrateRelease>, Error=Error>>
{

View file

@ -1,8 +1,9 @@
use std::env;
use std::sync::Arc;
use futures::{Future, IntoFuture, future};
use hyper::{Error as HyperError, Method, Request, Response, StatusCode};
use hyper::header::ContentType;
use hyper::header::{ContentType, Location};
use route_recognizer::{Params, Router};
use slog::Logger;
use tokio_service::Service;
@ -11,7 +12,7 @@ mod assets;
mod views;
use ::engine::{Engine, AnalyzeDependenciesOutcome};
use ::models::crates::CratePath;
use ::models::crates::{CrateName, CratePath};
use ::models::repo::RepoPath;
use ::models::SubjectPath;
@ -31,6 +32,7 @@ enum Route {
Index,
Static(StaticFile),
RepoStatus(StatusFormat),
CrateRedirect,
CrateStatus(StatusFormat)
}
@ -53,6 +55,7 @@ impl Server {
router.add("/repo/:site/:qual/:name", Route::RepoStatus(StatusFormat::Html));
router.add("/repo/:site/:qual/:name/status.svg", Route::RepoStatus(StatusFormat::Svg));
router.add("/crate/:name", Route::CrateRedirect);
router.add("/crate/:name/:version", Route::CrateStatus(StatusFormat::Html));
router.add("/crate/:name/:version/status.svg", Route::CrateStatus(StatusFormat::Svg));
@ -86,6 +89,11 @@ impl Service for Server {
return Box::new(self.crate_status(req, route_match.params, logger, format));
}
},
&Route::CrateRedirect => {
if *req.method() == Method::Get {
return Box::new(self.crate_redirect(req, route_match.params, logger));
}
},
&Route::Static(file) => {
if *req.method() == Method::Get {
return Box::new(future::ok(Server::static_file(file)));
@ -156,6 +164,55 @@ impl Server {
})
}
fn crate_redirect(&self, _req: Request, params: Params, logger: Logger) ->
impl Future<Item=Response, Error=HyperError>
{
let engine = self.engine.clone();
let name = params.find("name").expect("route param 'name' not found");
name.parse::<CrateName>().into_future().then(move |crate_name_result| {
match crate_name_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Could not parse crate name",
"Please make sure to provide a valid crate name.");
response.set_status(StatusCode::BadRequest);
future::Either::A(future::ok(response))
},
Ok(crate_name) => {
future::Either::B(engine.find_latest_crate_release(crate_name, None).then(move |release_result| {
match release_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Could not fetch crate information",
"Please make sure to provide a valid crate name.");
response.set_status(StatusCode::NotFound);
future::ok(response)
},
Ok(None) => {
let mut response = views::html::error::render("Could not fetch crate information",
"Please make sure to provide a valid crate name.");
response.set_status(StatusCode::NotFound);
future::ok(response)
},
Ok(Some(release)) => {
let mut response = Response::new();
response.set_status(StatusCode::TemporaryRedirect);
let url = format!("{}/crate/{}/{}",
&SELF_BASE_URL as &str,
release.name.as_ref(),
release.version);
response.headers_mut().set(Location::new(url));
future::ok(response)
}
}
}))
}
}
})
}
fn crate_status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) ->
impl Future<Item=Response, Error=HyperError>
{
@ -216,3 +273,10 @@ impl Server {
}
}
}
lazy_static! {
static ref SELF_BASE_URL: String = {
env::var("BASE_URL")
.unwrap_or_else(|_| "http://localhost:8080".to_string())
};
}

View file

@ -9,12 +9,9 @@ pub mod index;
pub mod error;
pub mod status;
lazy_static! {
static ref SELF_BASE_URL: String = {
env::var("BASE_URL")
.unwrap_or_else(|_| "http://localhost:8080".to_string())
};
use super::super::SELF_BASE_URL;
lazy_static! {
static ref GAUGES_SITE_ID: Option<String> = {
env::var("GAUGES_SITE_ID").ok().map(|s| s.to_string())
};