aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-06-16 21:26:34 +0200
committermetamuffin <metamuffin@disroot.org>2023-06-16 21:26:34 +0200
commit8da7d4f730c4026883a75706920bb9bdd1b0f5e4 (patch)
treeec79ea50464ec0ef88343b7df4e7fc64eee15740
parent202030972f0c31c208474a23164f0768c9023ad5 (diff)
downloadjellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar
jellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar.bz2
jellything-8da7d4f730c4026883a75706920bb9bdd1b0f5e4.tar.zst
cache images
-rw-r--r--server/src/routes/api/mod.rs5
-rw-r--r--server/src/routes/ui/mod.rs48
-rw-r--r--server/src/routes/ui/node.rs11
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,
))
}