💄 Switched to a handlebars template for the whole dir index
parent
55b3e9f520
commit
1fb0c2aafa
|
@ -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}}">
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 (
|
||||
|
|
Loading…
Reference in New Issue