feat: show download size on files read from disk

This commit is contained in:
minish 2023-06-28 17:02:40 -04:00
parent b8611e6415
commit b44fa6c4a1
Signed by: min
GPG Key ID: FEECFF24EF0CE9E9
3 changed files with 89 additions and 9 deletions

38
Cargo.lock generated
View File

@ -43,13 +43,13 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.59"
version = "0.1.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.104",
"syn 2.0.22",
]
[[package]]
@ -135,6 +135,7 @@ dependencies = [
"async-recursion",
"axum",
"bytes",
"futures",
"hyper",
"log",
"pretty_env_logger",
@ -213,6 +214,21 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "futures"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.28"
@ -220,6 +236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
@ -228,6 +245,17 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.28"
@ -263,9 +291,13 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",

View File

@ -14,6 +14,7 @@ bytes = "1"
rand = "0.8.5"
async-recursion = "1.0.0"
walkdir = "2"
futures = "0.3"
log = "0.4"
pretty_env_logger = "0.5.0"
archived = { path = "./archived" }

View File

@ -10,8 +10,8 @@ use axum::{
};
use bytes::Bytes;
use hyper::StatusCode;
use tokio::fs::File;
use hyper::{http::HeaderValue, StatusCode};
use tokio::{fs::File, runtime::Handle};
use tokio_util::io::ReaderStream;
pub enum ViewSuccess {
@ -20,7 +20,7 @@ pub enum ViewSuccess {
}
pub enum ViewError {
NotFound, // 404
NotFound, // 404
InternalServerError, // 500
}
@ -28,20 +28,67 @@ impl IntoResponse for ViewSuccess {
fn into_response(self) -> Response {
match self {
ViewSuccess::FromDisk(file) => {
// get handle to current runtime
// i use this to block on futures here (not async)
let handle = Handle::current();
let _ = handle.enter();
// read the metadata of the file on disk
// this function isn't async
// .. so we have to use handle.block_on() to get the metadata
let metadata = futures::executor::block_on(file.metadata());
// if we error then return 500
if metadata.is_err() {
error!("failed to read metadata from disk");
return ViewError::InternalServerError.into_response();
}
// unwrap (which we know is safe) and read the file size as a string
let metadata = metadata.unwrap();
let len_str = metadata.len().to_string();
debug!("file is {} bytes on disk", &len_str);
// HeaderValue::from_str will never error if only visible ASCII characters are passed (32-127)
// .. so unwrapping this should be fine
let content_length = HeaderValue::from_str(&len_str).unwrap();
// create a streamed body response (we want to stream larger files)
let reader = ReaderStream::new(file);
let stream = StreamBody::new(reader);
stream.into_response()
// extract mutable headers from the response
let mut res = stream.into_response();
let headers = res.headers_mut();
// clear headers, browser can imply content type
headers.clear();
// insert Content-Length header
// that way the browser shows how big a file is when it's being downloaded
headers.insert("Content-Length", content_length);
res
}
ViewSuccess::FromCache(data) => {
// extract mutable headers from the response
let mut res = data.into_response();
let mut res = data.clone().into_response();
let headers = res.headers_mut();
// clear the headers, let the browser imply it
headers.clear();
/* // we do not need this for FromCache because it works fine
// read the length of the data as a string
let len_str = data.len().to_string();
// HeaderValue::from_str will never error if only visible ASCII characters are passed (32-127)
// .. so this should be fine
let content_length = HeaderValue::from_str(&len_str).unwrap();
headers.append("Content-Length", content_length);
*/
res
}
}
@ -61,7 +108,7 @@ impl IntoResponse for ViewError {
ViewError::InternalServerError => {
// convert string into response, change status code
let mut res = "internal server error!".into_response();
*res.status_mut() = StatusCode::NOT_FOUND;
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res
}