💄 Switched to a handlebars template for the whole dir index

main
_ 2020-10-31 09:35:18 -05:00
parent 55b3e9f520
commit 1fb0c2aafa
3 changed files with 74 additions and 71 deletions

View File

@ -1,4 +1,5 @@
<ul> <ul>
<li><a href="https://example.com">..</a></li>
{{#each entries}} {{#each entries}}
<li> <li>
<a href="{{this.encoded_file_name}}{{this.trailing_slash}}"> <a href="{{this.encoded_file_name}}{{this.trailing_slash}}">

View File

@ -92,7 +92,12 @@ async fn main () -> Result <(), Box <dyn Error>> {
let mut handlebars = handlebars::Handlebars::new (); let mut handlebars = handlebars::Handlebars::new ();
handlebars.register_template_file ("file_server_dir_entry", "ptth_handlebars/file_server_dir_entry.html")?; for (k, v) in vec! [
("file_server_dir_entry", "ptth_handlebars/file_server_dir_entry.html"),
("file_server_dir", "ptth_handlebars/file_server_dir.html"),
].into_iter () {
handlebars.register_template_file (k, v)?;
}
let handlebars = Arc::new (handlebars); let handlebars = Arc::new (handlebars);

View File

@ -47,26 +47,22 @@ fn parse_range_header (range_str: &str) -> (Option <u64>, Option <u64>) {
(start, end) (start, end)
} }
async fn serve_dir ( use serde::Serialize;
handlebars: Arc <Handlebars <'static>>, use tokio::fs::DirEntry;
mut dir: ReadDir
) -> http_serde::Response {
let (tx, rx) = channel (2);
let handlebars = handlebars.clone (); // This could probably be done with borrows, if I owned the
tokio::spawn (async move { // tokio::fs::DirEntry instead of consuming it
let mut tx = tx;
tx.send (Ok::<_, Infallible> (String::from ("<style>body {font-family:sans;}</style><ul>").into_bytes ())).await.unwrap (); #[derive (Serialize)]
struct TemplateDirEntry {
let handlebars = handlebars.clone (); trailing_slash: &'static str,
while let Ok (entry) = dir.next_entry ().await { file_name: String,
let handlebars = handlebars.clone (); encoded_file_name: String,
let entry: tokio::fs::DirEntry = match entry { error: bool,
Some (x) => x, }
None => break,
};
async fn read_dir_entry (entry: DirEntry) -> TemplateDirEntry
{
let trailing_slash = match entry.file_type ().await { let trailing_slash = match entry.file_type ().await {
Ok (t) => if t.is_dir () { Ok (t) => if t.is_dir () {
"/" "/"
@ -79,51 +75,52 @@ async fn serve_dir (
let file_name = match entry.file_name ().into_string () { let file_name = match entry.file_name ().into_string () {
Ok (x) => x, Ok (x) => x,
Err (_) => { Err (_) => return TemplateDirEntry {
let s = format! ("<li>(file_name error)</li>\n"); trailing_slash: "",
if tx.send (Ok::<_, Infallible> (s.into_bytes ())).await.is_err () file_name: "".into (),
{ encoded_file_name: "".into (),
break; error: true,
} },
continue;
}
}; };
use std::borrow::Cow;
use percent_encoding::*; use percent_encoding::*;
let encoded_file_name: Cow <str> = utf8_percent_encode (&file_name, CONTROLS).into (); let encoded_file_name = utf8_percent_encode (&file_name, CONTROLS).to_string ();
#[derive (serde::Serialize)] TemplateDirEntry {
struct TemplateDirEntry <'a> { trailing_slash: &trailing_slash,
trailing_slash: &'a str, file_name,
file_name: &'a str, encoded_file_name,
encoded_file_name: Cow <'a, str>, error: false,
}
} }
let s = handlebars.render ( async fn serve_dir (
"file_server_dir_entry", handlebars: Arc <Handlebars <'static>>,
&TemplateDirEntry { mut dir: ReadDir
trailing_slash: &trailing_slash, ) -> http_serde::Response
file_name: &file_name, {
encoded_file_name, let mut entries = vec! [];
while let Ok (Some (entry)) = dir.next_entry ().await {
entries.push (read_dir_entry (entry).await);
}
#[derive (Serialize)]
struct TemplateDirPage {
entries: Vec <TemplateDirEntry>,
}
let s = handlebars.render ("file_server_dir", &TemplateDirPage {
entries,
}).unwrap (); }).unwrap ();
if tx.send (Ok::<_, Infallible> (s.into_bytes ())).await.is_err () let mut resp = http_serde::Response::default ();
{ resp
break; .header ("content-type".to_string (), "text/html".to_string ().into_bytes ())
} .body_bytes (s.into_bytes ())
} ;
resp
tx.send (Ok::<_, Infallible> (String::from ("</ul>").into_bytes ())).await.unwrap ();
});
let mut response = http_serde::Response::default ();
response.header ("content-type".into (), String::from ("text/html").into_bytes ());
response.body (rx);
response
} }
async fn serve_file ( async fn serve_file (