diff --git a/src/main.rs b/src/main.rs index a7ec00a..8866563 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,7 +69,7 @@ fn main() { let engine = Engine::new(client.clone(), logger.clone()); - let server = Server::new(engine); + let server = Server::new(logger.clone(), engine); let serve = http.serve_addr_handle(&addr, &handle, move || Ok(server.clone())) .expect("failed to bind server"); diff --git a/src/server/mod.rs b/src/server/mod.rs index 759d2e3..6491386 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -34,12 +34,13 @@ enum Route { #[derive(Clone)] pub struct Server { + logger: Logger, engine: Engine, router: Arc> } impl Server { - pub fn new(engine: Engine) -> Server { + pub fn new(logger: Logger, engine: Engine) -> Server { let mut router = Router::new(); router.add("/", Route::Index); @@ -51,7 +52,7 @@ impl Server { router.add("/repo/:site/:qual/:name/status.json", Route::Status(StatusFormat::Json)); router.add("/repo/:site/:qual/:name/status.svg", Route::Status(StatusFormat::Svg)); - Server { engine, router: Arc::new(router) } + Server { logger, engine, router: Arc::new(router) } } } @@ -62,16 +63,18 @@ impl Service for Server { type Future = Box>; fn call(&self, req: Request) -> Self::Future { + let logger = self.logger.new(o!("http_path" => req.uri().path().to_owned())); + if let Ok(route_match) = self.router.recognize(req.uri().path()) { match route_match.handler { &Route::Index => { if *req.method() == Method::Get { - return Box::new(self.index(req, route_match.params)); + return Box::new(self.index(req, route_match.params, logger)); } }, &Route::Status(format) => { if *req.method() == Method::Get { - return Box::new(self.status(req, route_match.params, format)); + return Box::new(self.status(req, route_match.params, logger, format)); } }, &Route::Static(file) => { @@ -90,15 +93,15 @@ impl Service for Server { } impl Server { - fn index(&self, _req: Request, _params: Params) -> + fn index(&self, _req: Request, _params: Params, logger: Logger) -> impl Future { - self.engine.get_popular_repos().then(|popular_result| { + self.engine.get_popular_repos().then(move |popular_result| { match popular_result { Err(err) => { - let mut response = Response::new(); - response.set_status(StatusCode::BadRequest); - response.set_body(format!("Error: {}", err)); + error!(logger, "error: {}", err); + let mut response = views::html::error::render("Could not retrieve popular repositories", ""); + response.set_status(StatusCode::InternalServerError); future::ok(response) }, Ok(popular) => @@ -107,7 +110,7 @@ impl Server { }) } - fn status(&self, _req: Request, params: Params, format: StatusFormat) -> + fn status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) -> impl Future { let server = self.clone(); @@ -119,9 +122,9 @@ impl Server { RepoPath::from_parts(site, qual, name).into_future().then(move |repo_path_result| { match repo_path_result { Err(err) => { - let mut response = Response::new(); + error!(logger, "error: {}", err); + let mut response = views::html::error::render("Could not parse repository URL", ""); response.set_status(StatusCode::BadRequest); - response.set_body(format!("Error: {}", err)); future::Either::A(future::ok(response)) }, Ok(repo_path) => { @@ -129,9 +132,10 @@ impl Server { match analyze_result { Err(err) => { if format != StatusFormat::Svg { - let mut response = Response::new(); - response.set_status(StatusCode::BadRequest); - response.set_body(format!("Error: {}", err)); + error!(logger, "error: {}", err); + let mut response = views::html::error::render("Failed to analyze repository", + "The repository you requested might be structured in an uncommon way that is not yet supported."); + response.set_status(StatusCode::InternalServerError); future::Either::A(future::ok(response)) } else { future::Either::A(future::ok(views::status_svg(None))) diff --git a/src/server/views/html/error.rs b/src/server/views/html/error.rs new file mode 100644 index 0000000..ba9088c --- /dev/null +++ b/src/server/views/html/error.rs @@ -0,0 +1,16 @@ +use hyper::Response; +use maud::html; + +pub fn render(title: &str, descr: &str) -> Response { + super::render_html(title, html! { + section class="hero is-light" { + div class="hero-head" (super::render_navbar()) + div class="hero-body" { + div class="container" { + p class="title is-1" (title) + p (descr) + } + } + } + }) +} diff --git a/src/server/views/html/index.rs b/src/server/views/html/index.rs index fa787c7..4e3e057 100644 --- a/src/server/views/html/index.rs +++ b/src/server/views/html/index.rs @@ -33,7 +33,7 @@ fn popular_table(popular: Vec) -> Markup { } pub fn render(popular: Vec) -> Response { - super::render_html("Keep your dependencies up-to-date - Deps.rs", html! { + super::render_html("Keep your dependencies up-to-date", html! { section class="hero is-light" { div class="hero-head" (super::render_navbar()) div class="hero-body" { diff --git a/src/server/views/html/mod.rs b/src/server/views/html/mod.rs index a4be773..000f479 100644 --- a/src/server/views/html/mod.rs +++ b/src/server/views/html/mod.rs @@ -5,6 +5,7 @@ use hyper::header::ContentType; use maud::{Markup, Render, html}; pub mod index; +pub mod error; pub mod status; lazy_static! { @@ -20,7 +21,7 @@ fn render_html(title: &str, body: B) -> Response { head { meta charset="utf-8"; meta name="viewport" content="width=device-width, initial-scale=1"; - title (title) + title (format!("{} - Deps.rs", title)) link rel="icon" type="image/png" href="/static/favicon.png"; link rel="stylesheet" type="text/css" href="/static/style.css"; link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Fira+Sans:400,500,600"; diff --git a/src/server/views/html/status.rs b/src/server/views/html/status.rs index 108d539..11710ae 100644 --- a/src/server/views/html/status.rs +++ b/src/server/views/html/status.rs @@ -63,7 +63,7 @@ fn dependency_table(title: &str, deps: BTreeMap) pub fn render(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Response { let self_path = format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref()); let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path); - let title = format!("{} / {} - Deps.rs", repo_path.qual.as_ref(), repo_path.name.as_ref()); + let title = format!("{} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()); let (hero_class, status_asset) = if analysis_outcome.deps.any_outdated() { ("is-warning", assets::BADGE_OUTDATED_SVG.as_ref())