Add size and modified date

This commit is contained in:
Matteo Settenvini 2023-07-12 16:52:23 +02:00
parent 3ebb73959b
commit 161f4f1b1d
4 changed files with 108 additions and 22 deletions

8
Cargo.lock generated
View File

@ -763,6 +763,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "human-size"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9994b79e8c1a39b3166c63ae7823bb2b00831e2a96a31399c50fe69df408eaeb"
[[package]] [[package]]
name = "humansize" name = "humansize"
version = "2.1.3" version = "2.1.3"
@ -1979,10 +1985,12 @@ name = "serves3"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"config", "config",
"human-size",
"lazy_static", "lazy_static",
"rocket", "rocket",
"rocket_dyn_templates", "rocket_dyn_templates",
"rust-s3", "rust-s3",
"serde",
"tempdir", "tempdir",
] ]

View File

@ -12,8 +12,10 @@ license = "EUPL-1.2"
[dependencies] [dependencies]
config = "0.13" config = "0.13"
human-size = "0.4"
lazy_static = "1.4" lazy_static = "1.4"
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "v0.5.0-rc.3" } rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "v0.5.0-rc.3" }
rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "v0.5.0-rc.3", features = ["tera"] } rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket.git", rev = "v0.5.0-rc.3", features = ["tera"] }
rust-s3 = { version = "0.32", default-features = false, features = ["tokio-rustls-tls"] } rust-s3 = { version = "0.32", default-features = false, features = ["tokio-rustls-tls"] }
tempdir = "0.3" serde = { version = "1.0" }
tempdir = { version = "0.3" }

View File

@ -4,6 +4,7 @@
use { use {
lazy_static::lazy_static, lazy_static::lazy_static,
rocket::response::Responder, rocket::response::Responder,
rocket::serde::Serialize,
rocket_dyn_templates::{context, Template}, rocket_dyn_templates::{context, Template},
std::path::PathBuf, std::path::PathBuf,
}; };
@ -75,6 +76,14 @@ enum FileView {
File(Vec<u8>), File(Vec<u8>),
} }
#[derive(Serialize)]
struct FileViewItem {
path: String,
size: String,
size_bytes: u64,
last_modification: String,
}
#[derive(Responder, Debug)] #[derive(Responder, Debug)]
enum Error { enum Error {
#[response(status = 404)] #[response(status = 404)]
@ -136,7 +145,7 @@ async fn s3_serve_file(path: &PathBuf) -> Result<FileView, Error> {
} }
} }
async fn s3_fileview(path: &PathBuf) -> Result<Vec<String>, Error> { async fn s3_fileview(path: &PathBuf) -> Result<Vec<FileViewItem>, Error> {
/* /*
if listing a folder: if listing a folder:
- folders will be under 'common_prefixes' - folders will be under 'common_prefixes'
@ -156,33 +165,64 @@ async fn s3_fileview(path: &PathBuf) -> Result<Vec<String>, Error> {
let objects = s3_objects let objects = s3_objects
.iter() .iter()
.flat_map(|list| -> Vec<Option<&str>> { .flat_map(|list| -> Vec<Option<FileViewItem>> {
let prefix = if let Some(p) = &list.prefix { let prefix = if let Some(p) = &list.prefix {
p.as_str() p.as_str()
} else { } else {
"" ""
}; };
let folders = list let folders = list.common_prefixes.iter().flatten().map(|dir| {
.common_prefixes let path = dir.prefix.strip_prefix(&prefix);
.iter() path.map(|path| FileViewItem {
.flatten() path: path.to_owned(),
.map(|dir| dir.prefix.strip_prefix(&prefix)); size_bytes: 0,
size: "[DIR]".to_owned(),
last_modification: String::default(),
})
});
let files = list let files = list.contents.iter().map(|obj| {
.contents let path = obj.key.strip_prefix(&prefix);
.iter() path.map(|path| FileViewItem {
.map(|obj| obj.key.strip_prefix(&prefix)); path: path.to_owned(),
size_bytes: obj.size,
size: size_bytes_to_human(obj.size),
last_modification: obj.last_modified.clone(),
})
});
folders.chain(files).collect() folders.chain(files).collect()
}) })
.flatten() .flatten()
.map(str::to_owned)
.collect(); .collect();
Ok(objects) Ok(objects)
} }
fn size_bytes_to_human(bytes: u64) -> String {
use human_size::{Any, SpecificSize};
let size: f64 = bytes as f64;
let digits = size.log10().floor() as u32;
let mut order = digits / 3;
let unit = match order {
0 => Any::Byte,
1 => Any::Kilobyte,
2 => Any::Megabyte,
_ => {
order = 3; // Let's stop here.
Any::Gigabyte
}
};
format!(
"{:.3}",
SpecificSize::new(size / 10u64.pow(order * 3) as f64, unit)
.unwrap_or(SpecificSize::new(0., Any::Byte).unwrap())
)
}
#[rocket::launch] #[rocket::launch]
fn rocket() -> _ { fn rocket() -> _ {
eprintln!("Proxying to {} for {}", BUCKET.host(), BUCKET.name()); eprintln!("Proxying to {} for {}", BUCKET.host(), BUCKET.name());

View File

@ -4,17 +4,53 @@
SPDX-License-Identifier: EUPL-1.2 SPDX-License-Identifier: EUPL-1.2
--> -->
<html> <html>
<head></head> <head>
<style>
body {
font-family: monospace;
}
th, td {
padding: .3em;
}
thead th {
border-bottom: 1px dotted black;
}
a {
text-decoration: none;
}
</style>
</head>
<body> <body>
<h1>{{ path }}</h1> <h1>{{ path }}</h1>
<ul> <table>
{% if path != "/" %} <thead>
<li><a href="../">..</a></li> <tr>
{% endif %} <th scope="col">Filename</th>
<th scope="col">Size</th>
<th scope="col">Modified</th>
</tr>
</thead>
<tbody>
{% if path != "/" %}
<tr>
<td><a href="../">..</a></td>
<td></td>
<td></td>
</tr>
{% endif %}
{% for object in objects %} {% for object in objects %}
<li><a href="{{ object | urlencode }}">{{ object }}</a></li> <tr>
{% endfor %} <td><a href="{{ object.path | urlencode }}" data-size-bytes="{{ object.size_bytes }}">{{ object.path }}</a></td>
</ul> <td>{{ object.size }}</td>
<td>{{ object.last_modification}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body> </body>
</html </html