diff options
Diffstat (limited to 'server/src/helper/cache.rs')
-rw-r--r-- | server/src/helper/cache.rs | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/server/src/helper/cache.rs b/server/src/helper/cache.rs new file mode 100644 index 0000000..d4c0595 --- /dev/null +++ b/server/src/helper/cache.rs @@ -0,0 +1,56 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin <metamuffin.org> +*/ + +use log::debug; +use rocket::{ + http::{Header, Status}, + response::{self, Responder}, + Request, Response, +}; +use std::{ + hash::{DefaultHasher, Hash, Hasher}, + os::unix::fs::MetadataExt, + path::Path, +}; +use tokio::fs::File; + +pub struct CacheControlFile(File, String); +impl CacheControlFile { + pub async fn new_cachekey(p: &Path) -> anyhow::Result<Self> { + let tag = p.file_name().unwrap().to_str().unwrap().to_owned(); + let f = File::open(p).await?; + Ok(Self(f, tag)) + } + pub async fn new_mtime(f: File) -> Self { + let meta = f.metadata().await.unwrap(); + let modified = meta.mtime(); + let mut h = DefaultHasher::new(); + modified.hash(&mut h); + let tag = format!("{:0>16x}", h.finish()); + Self(f, tag) + } +} +impl<'r> Responder<'r, 'static> for CacheControlFile { + fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { + let Self(file, tag) = self; + if req.headers().get_one("if-none-match") == Some(&tag) { + debug!("file cache: not modified"); + Response::build() + .status(Status::NotModified) + .header(Header::new("cache-control", "private")) + .header(Header::new("etag", tag)) + .ok() + } else { + debug!("file cache: transfer"); + Response::build() + .status(Status::Ok) + .header(Header::new("cache-control", "private")) + .header(Header::new("etag", tag)) + .streamed_body(file) + .ok() + } + } +} |