Use ructe static file support to serve static files with hashes and caching

This commit is contained in:
Valentin Brandl 2022-08-21 13:47:07 +02:00
parent c93c83f004
commit 391bb6faeb
6 changed files with 35 additions and 11 deletions

2
Cargo.lock generated
View File

@ -880,6 +880,7 @@ dependencies = [
"futures", "futures",
"git2", "git2",
"lazy_static", "lazy_static",
"mime",
"number_prefix", "number_prefix",
"openssl-probe", "openssl-probe",
"reqwest", "reqwest",
@ -1647,6 +1648,7 @@ dependencies = [
"bytecount", "bytecount",
"itertools", "itertools",
"md5", "md5",
"mime",
"nom", "nom",
] ]

View File

@ -22,6 +22,7 @@ dotenv = "0.15.0"
futures = "0.3.21" futures = "0.3.21"
git2 = "0.15.0" git2 = "0.15.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
mime = "0.3"
number_prefix = "0.4.0" number_prefix = "0.4.0"
openssl-probe = "0.1.5" openssl-probe = "0.1.5"
reqwest = "0.11.11" reqwest = "0.11.11"
@ -36,7 +37,7 @@ tracing-log = "0.1.3"
tracing-subscriber = { version = "0.3.15", features = ["registry", "env-filter"] } tracing-subscriber = { version = "0.3.15", features = ["registry", "env-filter"] }
[build-dependencies] [build-dependencies]
ructe = "0.14.0" ructe = { version = "0.14.0", features = ["mime03"] }
vergen = { version = "7.3.1", default-features = false, features = ["git"] } vergen = { version = "7.3.1", default-features = false, features = ["git"] }
[dev-dependencies] [dev-dependencies]

View File

@ -8,5 +8,8 @@ fn main() -> Result<(), RucteError> {
let mut config = Config::default(); let mut config = Config::default();
*config.git_mut().sha_kind_mut() = ShaKind::Short; *config.git_mut().sha_kind_mut() = ShaKind::Short;
vergen(config).expect("Unable to generate static repo info"); vergen(config).expect("Unable to generate static repo info");
Ructe::from_env()?.compile_templates("templates") let mut ructe = Ructe::from_env()?;
let mut statics = ructe.statics()?;
statics.add_files("static")?;
ructe.compile_templates("templates")
} }

View File

@ -23,7 +23,7 @@ use crate::{
config::Settings, config::Settings,
error::{Error, Result}, error::{Error, Result},
service::{Bitbucket, FormService, GitHub, Gitlab, Service, Sourcehut}, service::{Bitbucket, FormService, GitHub, Gitlab, Service, Sourcehut},
statics::{CLIENT, CSS, FAVICON, VERSION_INFO}, statics::{CLIENT, VERSION_INFO},
template::RepoInfo, template::RepoInfo,
}; };
use actix_web::{ use actix_web::{
@ -46,6 +46,7 @@ use std::{
sync::atomic::Ordering, sync::atomic::Ordering,
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
use templates::statics::{self as template_statics, StaticFile};
use tracing::Instrument; use tracing::Instrument;
include!(concat!(env!("OUT_DIR"), "/templates.rs")); include!(concat!(env!("OUT_DIR"), "/templates.rs"));
@ -462,14 +463,32 @@ async fn async_p404(repo_count: web::Data<AtomicUsize>) -> Result<HttpResponse>
p404(repo_count) p404(repo_count)
} }
#[get("/tacit-css.min.css")] /// A duration to add to current time for a far expires header.
async fn css() -> HttpResponse { static FAR: Duration = Duration::from_secs(180 * 24 * 60 * 60);
HttpResponse::Ok().content_type("text/css").body(CSS)
#[get("/static/{filename}")]
async fn static_file(
path: web::Path<String>,
repo_count: web::Data<AtomicUsize>,
) -> Result<HttpResponse> {
StaticFile::get(&path)
.map(|data| {
let far_expires = SystemTime::now() + FAR;
HttpResponse::Ok()
.insert_header(Expires(far_expires.into()))
.content_type(data.mime.clone())
.body(data.content)
})
.map(Result::Ok)
.unwrap_or_else(|| p404(repo_count))
} }
#[get("/favicon.ico")] #[get("/favicon.ico")]
async fn favicon32() -> HttpResponse { async fn favicon32() -> HttpResponse {
HttpResponse::Ok().content_type("image/png").body(FAVICON) let data = &template_statics::favicon32_png;
HttpResponse::Ok()
.content_type(data.mime.clone())
.body(data.content)
} }
async fn start_server(listener: TcpListener, settings: Settings) -> std::io::Result<Server> { async fn start_server(listener: TcpListener, settings: Settings) -> std::io::Result<Server> {
@ -486,7 +505,7 @@ async fn start_server(listener: TcpListener, settings: Settings) -> std::io::Res
.wrap(middleware::NormalizePath::new(TrailingSlash::Trim)) .wrap(middleware::NormalizePath::new(TrailingSlash::Trim))
.service(index) .service(index)
.service(health_check) .service(health_check)
.service(css) .service(static_file)
.service(favicon32) .service(favicon32)
.service(generate) .service(generate)
.default_service(web::to(async_p404)); .default_service(web::to(async_p404));

View File

@ -7,8 +7,6 @@ pub(crate) const VERSION_INFO: VersionInfo = VersionInfo {
commit: env!("VERGEN_GIT_SHA_SHORT"), commit: env!("VERGEN_GIT_SHA_SHORT"),
version: env!("CARGO_PKG_VERSION"), version: env!("CARGO_PKG_VERSION"),
}; };
pub(crate) const CSS: &str = include_str!("../static/tacit-css.min.css");
pub(crate) const FAVICON: &[u8] = include_bytes!("../static/favicon32.png");
lazy_static! { lazy_static! {
pub(crate) static ref CLIENT: reqwest::Client = reqwest::Client::new(); pub(crate) static ref CLIENT: reqwest::Client = reqwest::Client::new();

View File

@ -1,3 +1,4 @@
@use super::statics::*;
@use crate::statics::VersionInfo; @use crate::statics::VersionInfo;
@(title: &str, header: &str, content: Content, version_info: VersionInfo, repo_count: usize) @(title: &str, header: &str, content: Content, version_info: VersionInfo, repo_count: usize)
@ -9,7 +10,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="keywords" content="Hits-of-Code, GitHub, Badge" /> <meta name="keywords" content="Hits-of-Code, GitHub, Badge" />
<meta name="description" content="Hits-of-Code Badges for Git repositories" /> <meta name="description" content="Hits-of-Code Badges for Git repositories" />
<link rel="stylesheet" href="/tacit-css.min.css" /> <link rel="stylesheet" href="/static/@tacit_css_min_css.name" />
<title>@title</title> <title>@title</title>
</head> </head>
<body> <body>