💄 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>
<li><a href="https://example.com">..</a></li>
{{#each entries}}
<li>
<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 ();
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);

View File

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