diff options
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,      ))  } | 
