aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/routes/ui/mod.rs')
-rw-r--r--server/src/routes/ui/mod.rs48
1 files changed, 44 insertions, 4 deletions
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()
+ }
+ }
+}