From 62c272ff627537db705de10abddb267daa738267 Mon Sep 17 00:00:00 2001
From: liquidev <liquidev@tutanota.com>
Date: Fri, 10 Jan 2025 14:10:23 +0100
Subject: [PATCH] add option to bust cache globally

---
 crates/treehouse/src/config.rs                    |  7 +++++++
 crates/treehouse/src/main.rs                      | 12 +++++++++---
 crates/treehouse/src/vfs/content_version_cache.rs |  9 +++++++--
 static/css/main.css                               |  2 +-
 vfs.toml                                          |  7 +++++++
 5 files changed, 31 insertions(+), 6 deletions(-)
 create mode 100644 vfs.toml

diff --git a/crates/treehouse/src/config.rs b/crates/treehouse/src/config.rs
index 67d7493..48fe361 100644
--- a/crates/treehouse/src/config.rs
+++ b/crates/treehouse/src/config.rs
@@ -17,6 +17,13 @@ use crate::{
     vfs::{self, Content, Dir, DynDir, ImageSize, VPath, VPathBuf},
 };
 
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct VfsConfig {
+    /// Cache salt string. Passed to `Blake3ContentVersionCache` as a salt for content version hashes.
+    /// Can be changed to bust cached assets for all clients.
+    pub cache_salt: String,
+}
+
 #[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct Config {
     /// Website root; used when generating links.
diff --git a/crates/treehouse/src/main.rs b/crates/treehouse/src/main.rs
index e8dcde1..4ccd8b3 100644
--- a/crates/treehouse/src/main.rs
+++ b/crates/treehouse/src/main.rs
@@ -8,6 +8,7 @@ use tracing::{error, info_span};
 use tracing_subscriber::layer::SubscriberExt as _;
 use tracing_subscriber::util::SubscriberInitExt as _;
 use treehouse::cli::serve::serve;
+use treehouse::config::VfsConfig;
 use treehouse::dirs::Dirs;
 use treehouse::generate;
 use treehouse::sources::Sources;
@@ -25,7 +26,7 @@ use treehouse::{
     vfs::{BufferedFile, MemDir, VPath},
 };
 
-fn vfs_sources() -> anyhow::Result<DynDir> {
+fn vfs_sources(config: &VfsConfig) -> anyhow::Result<DynDir> {
     let mut root = MemDir::new();
 
     root.add(
@@ -51,7 +52,7 @@ fn vfs_sources() -> anyhow::Result<DynDir> {
         PhysicalDir::new(PathBuf::from("content")).to_dyn(),
     );
 
-    let root = Blake3ContentVersionCache::new(root);
+    let root = Blake3ContentVersionCache::new(config.cache_salt.as_bytes().to_owned(), root);
     let root = ImageSizeCache::new(root);
 
     Ok(root.to_dyn())
@@ -61,7 +62,12 @@ async fn fallible_main(
     args: ProgramArgs,
     flush_guard: Option<tracing_chrome::FlushGuard>,
 ) -> anyhow::Result<()> {
-    let src = vfs_sources()?;
+    let vfs_config = toml_edit::de::from_str(
+        &fs::read_to_string("vfs.toml").context("failed to read vfs.toml")?,
+    )
+    .context("failed to deserialize vfs.toml")?;
+
+    let src = vfs_sources(&vfs_config)?;
     let dirs = Arc::new(Dirs {
         root: src.clone(),
         content: Cd::new(src.clone(), VPathBuf::new("content")).to_dyn(),
diff --git a/crates/treehouse/src/vfs/content_version_cache.rs b/crates/treehouse/src/vfs/content_version_cache.rs
index f953e2a..17636ee 100644
--- a/crates/treehouse/src/vfs/content_version_cache.rs
+++ b/crates/treehouse/src/vfs/content_version_cache.rs
@@ -6,13 +6,15 @@ use tracing::{info_span, instrument};
 use super::{query, Content, ContentVersion, Dir, Query, VPath, VPathBuf};
 
 pub struct Blake3ContentVersionCache<T> {
+    salt: Vec<u8>,
     inner: T,
     cache: DashMap<VPathBuf, ContentVersion>,
 }
 
 impl<T> Blake3ContentVersionCache<T> {
-    pub fn new(inner: T) -> Self {
+    pub fn new(salt: Vec<u8>, inner: T) -> Self {
         Self {
+            salt,
             inner,
             cache: DashMap::new(),
         }
@@ -29,7 +31,10 @@ where
             let _span = info_span!("cache_miss").entered();
 
             let version = query::<Content>(&self.inner, path).map(|content| {
-                let hash = blake3::hash(&content.bytes()).to_hex();
+                let mut hasher = blake3::Hasher::new();
+                hasher.update(&self.salt);
+                hasher.update(&content.bytes());
+                let hash = hasher.finalize().to_hex();
                 ContentVersion {
                     string: format!("b3-{}", &hash[0..8]),
                 }
diff --git a/static/css/main.css b/static/css/main.css
index fc47fd1..79a0d53 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -126,7 +126,7 @@ body {
        Other assets are referenced rarely enough that caching probably isn't gonna make too much of
        an impact.
        It's unlikely I'll ever update the font anyways, so eh, whatever. */
-    src: url("../font/Recursive_VF_1.085.woff2?v=b3-445487d5");
+    src: url("../font/Recursive_VF_1.085.woff2?v=b3-41236e2f");
 }
 
 body,
diff --git a/vfs.toml b/vfs.toml
new file mode 100644
index 0000000..1b75331
--- /dev/null
+++ b/vfs.toml
@@ -0,0 +1,7 @@
+# treehouse virtual file system settings.
+# These are loaded during VFS construction (earlier than treehouse.toml) and can be used to
+# influence the virtual file system.
+
+# NOTE: As a convention, this string is just an integer.
+# To bust all caches, increment this by 1.
+cache_salt = "1"