From 066535edaefa2c1f34531d8be5ad280d914a9edd Mon Sep 17 00:00:00 2001 From: boasting-squirrel Date: Tue, 12 Feb 2019 20:20:57 +0100 Subject: Split project into multiple files --- src/listing.rs | 245 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 src/listing.rs (limited to 'src/listing.rs') diff --git a/src/listing.rs b/src/listing.rs new file mode 100644 index 0000000..142018a --- /dev/null +++ b/src/listing.rs @@ -0,0 +1,245 @@ +use actix_web::{fs, HttpRequest, HttpResponse, Result}; +use bytesize::ByteSize; +use htmlescape::encode_minimal as escape_html_entity; +use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; +use std::cmp::Ordering; +use std::fmt::Write as FmtWrite; +use std::io; +use std::path::Path; +use std::str::FromStr; + +#[derive(Clone, Debug)] +pub enum SortingMethods { + Natural, + Alpha, + DirsFirst, +} + +#[derive(PartialEq)] +enum EntryType { + Directory, + File, +} + +impl PartialOrd for EntryType { + fn partial_cmp(&self, other: &EntryType) -> Option { + match (self, other) { + (EntryType::Directory, EntryType::File) => Some(Ordering::Less), + (EntryType::File, EntryType::Directory) => Some(Ordering::Greater), + _ => Some(Ordering::Equal), + } + } +} + +struct Entry { + name: String, + entry_type: EntryType, + link: String, + size: Option, +} + +impl Entry { + fn new( + name: String, + entry_type: EntryType, + link: String, + size: Option, + ) -> Self { + Entry { + name, + entry_type, + link, + size, + } + } +} + +impl FromStr for SortingMethods { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "natural" => Ok(SortingMethods::Natural), + "alpha" => Ok(SortingMethods::Alpha), + "dirsfirst" => Ok(SortingMethods::DirsFirst), + _ => Err(()), + } + } +} + +// ↓ Adapted from https://docs.rs/actix-web/0.7.13/src/actix_web/fs.rs.html#564 +pub fn directory_listing( + dir: &fs::Directory, + req: &HttpRequest, + skip_symlinks: bool, + random_route: Option, + sort_method: SortingMethods, + reverse_sort: bool, +) -> Result { + let index_of = format!("Index of {}", req.path()); + let mut body = String::new(); + let base = Path::new(req.path()); + let random_route = format!("/{}", random_route.unwrap_or_default()); + + if let Some(parent) = base.parent() { + if req.path() != random_route { + let _ = write!( + body, + "..", + parent.display() + ); + } + } + + let mut entries: Vec = Vec::new(); + + for entry in dir.path.read_dir()? { + if dir.is_visible(&entry) { + let entry = entry.unwrap(); + let p = match entry.path().strip_prefix(&dir.path) { + Ok(p) => base.join(p), + Err(_) => continue, + }; + // show file url as relative to static path + let file_url = + utf8_percent_encode(&p.to_string_lossy(), DEFAULT_ENCODE_SET).to_string(); + // " -- " & -- & ' -- ' < -- < > -- > + let file_name = escape_html_entity(&entry.file_name().to_string_lossy()); + + // if file is a directory, add '/' to the end of the name + if let Ok(metadata) = entry.metadata() { + if skip_symlinks && metadata.file_type().is_symlink() { + continue; + } + if metadata.is_dir() { + entries.push(Entry::new(file_name, EntryType::Directory, file_url, None)); + } else { + entries.push(Entry::new( + file_name, + EntryType::File, + file_url, + Some(ByteSize::b(metadata.len())), + )); + } + } else { + continue; + } + } + } + + match sort_method { + SortingMethods::Natural => entries + .sort_by(|e1, e2| alphanumeric_sort::compare_str(e1.name.clone(), e2.name.clone())), + SortingMethods::Alpha => { + entries.sort_by(|e1, e2| e1.entry_type.partial_cmp(&e2.entry_type).unwrap()); + entries.sort_by_key(|e| e.name.clone()) + } + SortingMethods::DirsFirst => { + entries.sort_by_key(|e| e.name.clone()); + entries.sort_by(|e1, e2| e1.entry_type.partial_cmp(&e2.entry_type).unwrap()); + } + }; + + if reverse_sort { + entries.reverse(); + } + + for entry in entries { + match entry.entry_type { + EntryType::Directory => { + let _ = write!( + body, + "{}/", + entry.link, entry.name + ); + } + EntryType::File => { + let _ = write!( + body, + "{}{}", + entry.link, + entry.name, + entry.size.unwrap() + ); + } + } + } + + let html = format!( + "\ + \ + {}\ + \ + \ +

{}

\ + \ + \ + \ + {}\ +
NameSize
\n", + index_of, index_of, body + ); + Ok(HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(html)) +} -- cgit v1.2.3 From 690990911ed9911ee2dd3dfd485faa0aae66c0d1 Mon Sep 17 00:00:00 2001 From: boasting-squirrel Date: Tue, 12 Feb 2019 20:25:44 +0100 Subject: Reorganized some imports + removed unused imports --- src/listing.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/listing.rs') diff --git a/src/listing.rs b/src/listing.rs index 142018a..7a13e9b 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -8,6 +8,8 @@ use std::io; use std::path::Path; use std::str::FromStr; +use crate::config; + #[derive(Clone, Debug)] pub enum SortingMethods { Natural, @@ -67,6 +69,11 @@ impl FromStr for SortingMethods { } } +pub fn file_handler(req: &HttpRequest) -> Result { + let path = &req.state().path; + Ok(fs::NamedFile::open(path)?) +} + // ↓ Adapted from https://docs.rs/actix-web/0.7.13/src/actix_web/fs.rs.html#564 pub fn directory_listing( dir: &fs::Directory, -- cgit v1.2.3 From f7b303bd1985cdad111da9aa27f1f164acbb797c Mon Sep 17 00:00:00 2001 From: boasting-squirrel Date: Tue, 12 Feb 2019 20:31:08 +0100 Subject: Fixed Clippy warnings --- src/listing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/listing.rs') diff --git a/src/listing.rs b/src/listing.rs index 7a13e9b..c955191 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -10,7 +10,7 @@ use std::str::FromStr; use crate::config; -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum SortingMethods { Natural, Alpha, -- cgit v1.2.3 From d410b27e85ffa653a64d10bcd6b43cc5f64fe5d9 Mon Sep 17 00:00:00 2001 From: boasting-squirrel Date: Wed, 13 Feb 2019 18:51:51 +0100 Subject: Removed config.rs and put back actix config in main.rs --- src/listing.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/listing.rs') diff --git a/src/listing.rs b/src/listing.rs index c955191..aeddd7d 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -8,8 +8,6 @@ use std::io; use std::path::Path; use std::str::FromStr; -use crate::config; - #[derive(Clone, Copy, Debug)] pub enum SortingMethods { Natural, @@ -69,7 +67,7 @@ impl FromStr for SortingMethods { } } -pub fn file_handler(req: &HttpRequest) -> Result { +pub fn file_handler(req: &HttpRequest) -> Result { let path = &req.state().path; Ok(fs::NamedFile::open(path)?) } -- cgit v1.2.3 From 3e2c3341ee4fd540126f822ef23aa442508cf4b6 Mon Sep 17 00:00:00 2001 From: boasting-squirrel Date: Wed, 13 Feb 2019 19:13:34 +0100 Subject: Added some docstrings --- src/listing.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src/listing.rs') diff --git a/src/listing.rs b/src/listing.rs index aeddd7d..f0662ef 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -9,15 +9,28 @@ use std::path::Path; use std::str::FromStr; #[derive(Clone, Copy, Debug)] +/// Available sorting methods pub enum SortingMethods { + /// Natural sorting method + /// 1 -> 2 -> 3 -> 11 Natural, + + /// Pure alphabetical sorting method + /// 1 -> 11 -> 2 -> 3 Alpha, + + /// Directories are listed first, alphabetical sorting is also applied + /// 1/ -> 2/ -> 3/ -> 11 -> 12 DirsFirst, } #[derive(PartialEq)] +/// Possible entry types enum EntryType { + /// Entry is a directory Directory, + + /// Entry is a file File, } @@ -31,10 +44,18 @@ impl PartialOrd for EntryType { } } +/// Entry struct Entry { + /// Name of the entry name: String, + + /// Type of the entry entry_type: EntryType, + + /// URL of the entry link: String, + + /// Size in byte of the entry. Only available for EntryType::File size: Option, } @@ -72,7 +93,8 @@ pub fn file_handler(req: &HttpRequest) -> Result( dir: &fs::Directory, req: &HttpRequest, -- cgit v1.2.3