diff options
author | metamuffin <metamuffin@disroot.org> | 2023-06-16 21:26:34 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-06-16 21:26:34 +0200 |
commit | 8da7d4f730c4026883a75706920bb9bdd1b0f5e4 (patch) | |
tree | ec79ea50464ec0ef88343b7df4e7fc64eee15740 /server/src/routes | |
parent | 202030972f0c31c208474a23164f0768c9023ad5 (diff) | |
download | jellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar jellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar.bz2 jellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar.zst |
cache images
Diffstat (limited to 'server/src/routes')
-rw-r--r-- | server/src/routes/api/mod.rs | 5 | ||||
-rw-r--r-- | server/src/routes/ui/mod.rs | 48 | ||||
-rw-r--r-- | server/src/routes/ui/node.rs | 11 |
3 files changed, 53 insertions, 11 deletions
diff --git a/server/src/routes/api/mod.rs b/server/src/routes/api/mod.rs index fab60c6..af795f1 100644 --- a/server/src/routes/api/mod.rs +++ b/server/src/routes/api/mod.rs @@ -10,6 +10,7 @@ use std::path::PathBuf; use super::ui::{ account::{login_logic, LoginForm}, node::AssetRole, + CacheControlFile, }; use crate::{ database::Database, @@ -56,7 +57,7 @@ pub async fn r_api_assets_node( path: PathBuf, role: AssetRole, library: &State<Library>, -) -> ApiResult<(ContentType, File)> { +) -> ApiResult<(ContentType, CacheControlFile)> { let node = library .nested_path(&path) .context("retrieving library node")?; @@ -65,7 +66,7 @@ pub async fn r_api_assets_node( let ext = path.extension().unwrap().to_str().unwrap(); Ok(( ContentType::from_extension(ext).unwrap(), - File::open(path).await?, + CacheControlFile::new(File::open(path).await?).await, )) } diff --git a/server/src/routes/ui/mod.rs b/server/src/routes/ui/mod.rs index 62c8aa8..f566f6d 100644 --- a/server/src/routes/ui/mod.rs +++ b/server/src/routes/ui/mod.rs @@ -3,24 +3,32 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin <metamuffin.org> */ +use log::debug; use markup::Render; use rocket::{ futures::FutureExt, - http::ContentType, + http::{ContentType, Header, Status}, response::{self, Responder}, Request, Response, }; -use std::{future::Future, io::Cursor, pin::Pin}; -use tokio::io::AsyncRead; +use std::{ + collections::hash_map::DefaultHasher, + future::Future, + hash::{Hash, Hasher}, + io::Cursor, + os::unix::prelude::MetadataExt, + pin::Pin, +}; +use tokio::{fs::File, io::AsyncRead}; pub mod account; +pub mod browser; pub mod error; pub mod home; pub mod layout; pub mod node; pub mod player; pub mod style; -pub mod browser; pub struct HtmlTemplate<'a>(pub markup::DynRender<'a>); @@ -52,3 +60,35 @@ impl AsyncRead for Defer { } } } + +pub struct CacheControlFile(File, String); +impl CacheControlFile { + pub async fn new(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")) + .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() + } + } +} diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs index 989f655..4d599dc 100644 --- a/server/src/routes/ui/node.rs +++ b/server/src/routes/ui/node.rs @@ -1,10 +1,11 @@ /* - 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) 2023 metamuffin <metamuffin.org> +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) 2023 metamuffin <metamuffin.org> */ use super::error::MyError; use super::player::player_uri; +use super::CacheControlFile; use crate::uri; use crate::{ library::{Directory, Item, Library, Node}, @@ -148,7 +149,7 @@ pub async fn r_item_assets( path: PathBuf, role: AssetRole, library: &State<Library>, -) -> Result<(ContentType, File), MyError> { +) -> Result<(ContentType, CacheControlFile), MyError> { let node = library .nested_path(&path) .context("retrieving library node")?; @@ -157,6 +158,6 @@ pub async fn r_item_assets( let ext = path.extension().unwrap().to_str().unwrap(); Ok(( ContentType::from_extension(ext).unwrap(), - File::open(path).await?, + CacheControlFile::new(File::open(path).await?).await, )) } |