replace lazy-static with once-cell

This commit is contained in:
Rob Ede 2020-09-28 23:50:12 +01:00
parent 1d5fdd5dc5
commit 63a8355543
No known key found for this signature in database
GPG key ID: C2A3B36E841A91E6
5 changed files with 190 additions and 131 deletions

1
Cargo.lock generated
View file

@ -1249,7 +1249,6 @@ dependencies = [
"hyper 0.11.27",
"hyper-tls",
"indexmap",
"lazy_static 1.4.0",
"lru-cache",
"maud",
"once_cell",

View file

@ -19,9 +19,9 @@ futures = "0.1.18"
hyper = "0.11.15"
hyper-tls = "0.1.2"
indexmap = { version = "1.0.0", features = ["serde-1"] }
lazy_static = "1.0.0"
lru-cache = "0.1.1"
maud = "0.22"
once_cell = "1.4"
relative-path = { version = "0.3.7", features = ["serde"] }
route-recognizer = "0.1.12"
rustsec = "0.6.0"
@ -36,7 +36,6 @@ tokio-core = "0.1.12"
tokio-service = "0.1.0"
toml = "0.4.5"
try_future = "0.1.1"
once_cell = "1.4"
[build-dependencies]

View file

@ -1,11 +1,8 @@
#![deny(bare_trait_objects)]
#![allow(unused)]
#![deny(rust_2018_idioms)]
#[macro_use]
extern crate failure;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate slog;

View file

@ -1,9 +1,10 @@
use std::env;
use std::sync::Arc;
use futures::{Future, IntoFuture, future};
use hyper::{Error as HyperError, Method, Request, Response, StatusCode};
use futures::{future, Future, IntoFuture};
use hyper::header::{ContentType, Location};
use hyper::{Error as HyperError, Method, Request, Response, StatusCode};
use once_cell::sync::Lazy;
use route_recognizer::{Params, Router};
use semver::VersionReq;
use slog::Logger;
@ -12,7 +13,7 @@ use tokio_service::Service;
mod assets;
mod views;
use crate::engine::{Engine, AnalyzeDependenciesOutcome};
use crate::engine::{AnalyzeDependenciesOutcome, Engine};
use crate::models::crates::{CrateName, CratePath};
use crate::models::repo::RepoPath;
use crate::models::SubjectPath;
@ -20,13 +21,13 @@ use crate::models::SubjectPath;
#[derive(Clone, Copy, PartialEq)]
enum StatusFormat {
Html,
Svg
Svg,
}
#[derive(Clone, Copy)]
enum StaticFile {
StyleCss,
FaviconPng
FaviconPng,
}
enum Route {
@ -34,14 +35,14 @@ enum Route {
Static(StaticFile),
RepoStatus(StatusFormat),
CrateRedirect,
CrateStatus(StatusFormat)
CrateStatus(StatusFormat),
}
#[derive(Clone)]
pub struct Server {
logger: Logger,
engine: Engine,
router: Arc<Router<Route>>
router: Arc<Router<Route>>,
}
impl Server {
@ -53,14 +54,30 @@ impl Server {
router.add("/static/style.css", Route::Static(StaticFile::StyleCss));
router.add("/static/favicon.png", Route::Static(StaticFile::FaviconPng));
router.add("/repo/:site/:qual/:name", Route::RepoStatus(StatusFormat::Html));
router.add("/repo/:site/:qual/:name/status.svg", Route::RepoStatus(StatusFormat::Svg));
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));
router.add(
"/crate/:name/:version",
Route::CrateStatus(StatusFormat::Html),
);
router.add(
"/crate/:name/:version/status.svg",
Route::CrateStatus(StatusFormat::Svg),
);
Server { logger, engine, router: Arc::new(router) }
Server {
logger,
engine,
router: Arc::new(router),
}
}
}
@ -68,10 +85,12 @@ impl Service for Server {
type Request = Request;
type Response = Response;
type Error = HyperError;
type Future = Box<dyn Future<Item=Response, Error=HyperError>>;
type Future = Box<dyn Future<Item = Response, Error = HyperError>>;
fn call(&self, req: Request) -> Self::Future {
let logger = self.logger.new(o!("http_path" => req.uri().path().to_owned()));
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 {
@ -79,28 +98,32 @@ impl Service for Server {
if *req.method() == Method::Get {
return Box::new(self.index(req, route_match.params, logger));
}
},
}
&Route::RepoStatus(format) => {
if *req.method() == Method::Get {
return Box::new(self.repo_status(req, route_match.params, logger, format));
}
},
}
&Route::CrateStatus(format) => {
if *req.method() == Method::Get {
return Box::new(self.crate_status(req, route_match.params, logger, format));
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)));
}
}
}
}
@ -111,175 +134,216 @@ impl Service for Server {
}
impl Server {
fn index(&self, _req: Request, _params: Params, logger: Logger) ->
impl Future<Item=Response, Error=HyperError>
{
self.engine.get_popular_repos()
fn index(
&self,
_req: Request,
_params: Params,
logger: Logger,
) -> impl Future<Item = Response, Error = HyperError> {
self.engine
.get_popular_repos()
.join(self.engine.get_popular_crates())
.then(move |popular_result| {
match popular_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Could not retrieve popular items", "");
response.set_status(StatusCode::InternalServerError);
future::ok(response)
},
Ok((popular_repos, popular_crates)) =>
future::ok(views::html::index::render(popular_repos, popular_crates))
.then(move |popular_result| match popular_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response =
views::html::error::render("Could not retrieve popular items", "");
response.set_status(StatusCode::InternalServerError);
future::ok(response)
}
Ok((popular_repos, popular_crates)) => {
future::ok(views::html::index::render(popular_repos, popular_crates))
}
})
}
fn repo_status(&self, _req: Request, params: Params, logger: Logger, format: StatusFormat) ->
impl Future<Item=Response, Error=HyperError>
{
fn repo_status(
&self,
_req: Request,
params: Params,
logger: Logger,
format: StatusFormat,
) -> impl Future<Item = Response, Error = HyperError> {
let server = self.clone();
let site = params.find("site").expect("route param 'site' not found");
let qual = params.find("qual").expect("route param 'qual' not found");
let name = params.find("name").expect("route param 'name' not found");
RepoPath::from_parts(site, qual, name).into_future().then(move |repo_path_result| {
match repo_path_result {
RepoPath::from_parts(site, qual, name)
.into_future()
.then(move |repo_path_result| match repo_path_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Could not parse repository path",
"Please make sure to provide a valid repository path.");
let mut response = views::html::error::render(
"Could not parse repository path",
"Please make sure to provide a valid repository path.",
);
response.set_status(StatusCode::BadRequest);
future::Either::A(future::ok(response))
},
Ok(repo_path) => {
future::Either::B(server.engine.analyze_repo_dependencies(repo_path.clone()).then(move |analyze_result| {
match analyze_result {
}
Ok(repo_path) => future::Either::B(
server
.engine
.analyze_repo_dependencies(repo_path.clone())
.then(move |analyze_result| match analyze_result {
Err(err) => {
error!(logger, "error: {}", err);
let response = Server::status_format_analysis(None, format, SubjectPath::Repo(repo_path));
future::ok(response)
},
Ok(analysis_outcome) => {
let response = Server::status_format_analysis(Some(analysis_outcome), format, SubjectPath::Repo(repo_path));
let response = Server::status_format_analysis(
None,
format,
SubjectPath::Repo(repo_path),
);
future::ok(response)
}
}
}))
}
}
})
Ok(analysis_outcome) => {
let response = Server::status_format_analysis(
Some(analysis_outcome),
format,
SubjectPath::Repo(repo_path),
);
future::ok(response)
}
}),
),
})
}
fn crate_redirect(&self, _req: Request, params: Params, logger: Logger) ->
impl Future<Item=Response, Error=HyperError>
{
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 {
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.");
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, VersionReq::any()).then(move |release_result| {
match release_result {
}
Ok(crate_name) => future::Either::B(
engine
.find_latest_crate_release(crate_name, VersionReq::any())
.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.");
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.");
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/{}/{}",
let url = format!(
"{}/crate/{}/{}",
&SELF_BASE_URL as &str,
release.name.as_ref(),
release.version);
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>
{
fn crate_status(
&self,
_req: Request,
params: Params,
logger: Logger,
format: StatusFormat,
) -> impl Future<Item = Response, Error = HyperError> {
let server = self.clone();
let name = params.find("name").expect("route param 'name' not found");
let version = params.find("version").expect("route param 'version' not found");
let version = params
.find("version")
.expect("route param 'version' not found");
CratePath::from_parts(name, version).into_future().then(move |crate_path_result| {
match crate_path_result {
CratePath::from_parts(name, version)
.into_future()
.then(move |crate_path_result| match crate_path_result {
Err(err) => {
error!(logger, "error: {}", err);
let mut response = views::html::error::render("Could not parse crate path",
"Please make sure to provide a valid crate name and version.");
let mut response = views::html::error::render(
"Could not parse crate path",
"Please make sure to provide a valid crate name and version.",
);
response.set_status(StatusCode::BadRequest);
future::Either::A(future::ok(response))
},
Ok(crate_path) => {
future::Either::B(server.engine.analyze_crate_dependencies(crate_path.clone()).then(move |analyze_result| {
match analyze_result {
}
Ok(crate_path) => future::Either::B(
server
.engine
.analyze_crate_dependencies(crate_path.clone())
.then(move |analyze_result| match analyze_result {
Err(err) => {
error!(logger, "error: {}", err);
let response = Server::status_format_analysis(None, format, SubjectPath::Crate(crate_path));
future::ok(response)
},
Ok(analysis_outcome) => {
let response = Server::status_format_analysis(Some(analysis_outcome), format, SubjectPath::Crate(crate_path));
let response = Server::status_format_analysis(
None,
format,
SubjectPath::Crate(crate_path),
);
future::ok(response)
}
}
}))
}
}
})
Ok(analysis_outcome) => {
let response = Server::status_format_analysis(
Some(analysis_outcome),
format,
SubjectPath::Crate(crate_path),
);
future::ok(response)
}
}),
),
})
}
fn status_format_analysis(analysis_outcome: Option<AnalyzeDependenciesOutcome>, format: StatusFormat, subject_path: SubjectPath) -> Response {
fn status_format_analysis(
analysis_outcome: Option<AnalyzeDependenciesOutcome>,
format: StatusFormat,
subject_path: SubjectPath,
) -> Response {
match format {
StatusFormat::Svg =>
views::badge::response(analysis_outcome.as_ref()),
StatusFormat::Html =>
views::html::status::render(analysis_outcome, subject_path)
StatusFormat::Svg => views::badge::response(analysis_outcome.as_ref()),
StatusFormat::Html => views::html::status::render(analysis_outcome, subject_path),
}
}
fn static_file(file: StaticFile) -> Response {
match file {
StaticFile::StyleCss => {
Response::new()
.with_header(ContentType("text/css".parse().unwrap()))
.with_body(assets::STATIC_STYLE_CSS)
},
StaticFile::FaviconPng => {
Response::new()
.with_header(ContentType("image/png".parse().unwrap()))
.with_body(assets::STATIC_FAVICON_PNG.to_vec())
}
StaticFile::StyleCss => Response::new()
.with_header(ContentType("text/css".parse().unwrap()))
.with_body(assets::STATIC_STYLE_CSS),
StaticFile::FaviconPng => Response::new()
.with_header(ContentType("image/png".parse().unwrap()))
.with_body(assets::STATIC_FAVICON_PNG.to_vec()),
}
}
}
lazy_static! {
static ref SELF_BASE_URL: String = {
env::var("BASE_URL")
.unwrap_or_else(|_| "http://localhost:8080".to_string())
};
}
static SELF_BASE_URL: Lazy<String> =
Lazy::new(|| env::var("BASE_URL").unwrap_or_else(|_| "http://localhost:8080".to_string()));

View file

@ -24,7 +24,7 @@ impl<S> Debug for Cache<S>
where S: Service<Error=Error> + Debug,
S::Request: Hash + Eq
{
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
fmt.debug_struct("Cache")
.field("inner", &self.inner)
.field("duration", &self.duration)
@ -76,7 +76,7 @@ impl<F> Debug for Cached<F>
where F: Future<Error=Error> + Debug,
F::Item: Debug
{
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
self.0.fmt(fmt)
}
}