Skip to content

Commit 192786a

Browse files
committed
WIP
1 parent 2f0353e commit 192786a

File tree

12 files changed

+375
-74
lines changed

12 files changed

+375
-74
lines changed

Cargo.lock

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,15 @@ fn-error-context = "0.2.0"
102102
# Templating
103103
askama = "0.14.0"
104104
walkdir = "2"
105+
phf = "0.13.1"
105106

106107
# Date and Time utilities
107108
chrono = { version = "0.4.11", default-features = false, features = ["clock", "serde"] }
108109

109110
# Transitive dependencies we don't use directly but need to have specific versions of
110111
thread_local = "1.1.3"
111112
constant_time_eq = "0.4.2"
113+
md5 = "0.8.0"
112114

113115
[dev-dependencies]
114116
criterion = "0.7.0"
@@ -131,8 +133,10 @@ debug = "line-tables-only"
131133

132134
[build-dependencies]
133135
time = "0.3"
136+
md5 = "0.8.0"
134137
gix = { version = "0.74.0", default-features = false }
135138
string_cache_codegen = "0.6.1"
139+
phf_codegen = "0.13"
136140
walkdir = "2"
137141
anyhow = { version = "1.0.42", features = ["backtrace"] }
138142
grass = { version = "0.13.1", default-features = false }

build.rs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::{Context as _, Error, Result};
2-
use std::{env, path::Path};
2+
use std::{env, fs::File, io::Write as _, path::Path};
33

44
mod tracked {
55
use std::{
@@ -68,13 +68,27 @@ mod tracked {
6868
}
6969
}
7070

71+
type ETagMap<'a> = phf_codegen::Map<'a, String>;
72+
7173
fn main() -> Result<()> {
7274
let out_dir = env::var("OUT_DIR").context("missing OUT_DIR")?;
7375
let out_dir = Path::new(&out_dir);
7476
read_git_version()?;
75-
compile_sass(out_dir)?;
77+
78+
let mut etag_map: ETagMap = ETagMap::new();
79+
80+
compile_sass(out_dir, &mut etag_map)?;
7681
write_known_targets(out_dir)?;
7782
compile_syntax(out_dir).context("could not compile syntax files")?;
83+
calculate_static_etags(&mut etag_map)?;
84+
85+
let mut etag_file = File::create(out_dir.join("static_etag_map.rs"))?;
86+
writeln!(
87+
&mut etag_file,
88+
"pub static STATIC_ETAG_MAP: ::phf::Map<&'static str, &'static str> = {};",
89+
etag_map.build()
90+
)?;
91+
etag_file.sync_all()?;
7892

7993
// trigger recompilation when a new migration is added
8094
println!("cargo:rerun-if-changed=migrations");
@@ -118,6 +132,16 @@ fn get_git_hash() -> Result<Option<String>> {
118132
}
119133
}
120134

135+
fn etag_from_path(path: impl AsRef<Path>) -> Result<String> {
136+
Ok(etag_from_content(std::fs::read(&path)?))
137+
}
138+
139+
fn etag_from_content(content: impl AsRef<[u8]>) -> String {
140+
let digest = md5::compute(content);
141+
let md5_hex = format!("{:x}", digest);
142+
format!(r#""\"{md5_hex}\"""#)
143+
}
144+
121145
fn compile_sass_file(src: &Path, dest: &Path) -> Result<()> {
122146
let css = grass::from_path(
123147
src.to_str()
@@ -133,7 +157,7 @@ fn compile_sass_file(src: &Path, dest: &Path) -> Result<()> {
133157
Ok(())
134158
}
135159

136-
fn compile_sass(out_dir: &Path) -> Result<()> {
160+
fn compile_sass(out_dir: &Path, etag_map: &mut ETagMap) -> Result<()> {
137161
const STYLE_DIR: &str = "templates/style";
138162

139163
for entry in walkdir::WalkDir::new(STYLE_DIR) {
@@ -152,6 +176,9 @@ fn compile_sass(out_dir: &Path) -> Result<()> {
152176
compile_sass_file(entry.path(), &dest).with_context(|| {
153177
format!("compiling {} to {}", entry.path().display(), dest.display())
154178
})?;
179+
180+
let rel_str = dest.file_name().unwrap().to_string_lossy().to_string();
181+
etag_map.entry(rel_str, etag_from_path(&dest)?);
155182
}
156183
}
157184
}
@@ -160,7 +187,32 @@ fn compile_sass(out_dir: &Path) -> Result<()> {
160187
let pure = tracked::read_to_string("vendor/pure-css/css/pure-min.css")?;
161188
let grids = tracked::read_to_string("vendor/pure-css/css/grids-responsive-min.css")?;
162189
let vendored = pure + &grids;
163-
std::fs::write(out_dir.join("vendored").with_extension("css"), vendored)?;
190+
std::fs::write(out_dir.join("vendored").with_extension("css"), &vendored)?;
191+
192+
etag_map.entry(
193+
"vendored.css".to_owned(),
194+
etag_from_content(vendored.as_bytes()),
195+
);
196+
197+
Ok(())
198+
}
199+
200+
fn calculate_static_etags(etag_map: &mut ETagMap) -> Result<()> {
201+
const STATIC_DIRS: &[&str] = &["static", "vendor"];
202+
203+
for static_dir in STATIC_DIRS {
204+
for entry in walkdir::WalkDir::new(static_dir) {
205+
let entry = entry?;
206+
let path = entry.path();
207+
if !path.is_file() {
208+
continue;
209+
}
210+
211+
let rel = path.strip_prefix(static_dir).unwrap();
212+
let rel_str = rel.to_string_lossy().replace('\\', "/");
213+
etag_map.entry(rel_str, etag_from_path(path)?);
214+
}
215+
}
164216

165217
Ok(())
166218
}

src/storage/database.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{Blob, FileRange, StorageMetrics, StreamingBlob};
2-
use crate::{InstanceMetrics, db::Pool, error::Result};
2+
use crate::{InstanceMetrics, db::Pool, error::Result, web::headers::compute_etag};
33
use chrono::{DateTime, Utc};
44
use futures_util::stream::{Stream, TryStreamExt};
55
use sqlx::Acquire;
@@ -123,13 +123,16 @@ impl DatabaseBackend {
123123
});
124124
let content = result.content.unwrap_or_default();
125125
let content_len = content.len();
126+
127+
let etag = compute_etag(&content);
126128
Ok(StreamingBlob {
127129
path: result.path,
128130
mime: result
129131
.mime
130132
.parse()
131133
.unwrap_or(mime::APPLICATION_OCTET_STREAM),
132134
date_updated: result.date_updated,
135+
etag: Some(etag),
133136
content: Box::new(io::Cursor::new(content)),
134137
content_length: content_len,
135138
compression,

0 commit comments

Comments
 (0)