aboutsummaryrefslogtreecommitdiff
path: root/server/src/helper/cache.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/helper/cache.rs')
-rw-r--r--server/src/helper/cache.rs56
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()
+ }
+ }
+}