breeze/src/view.rs

100 lines
2.9 KiB
Rust
Raw Normal View History

2023-01-30 17:11:30 -06:00
use std::{
2024-05-25 00:21:36 -05:00
ffi::OsStr, path::PathBuf, sync::Arc
2023-01-30 17:11:30 -06:00
};
use axum::{
body::StreamBody,
extract::{Path, State},
response::{IntoResponse, Response},
};
use hyper::{http::HeaderValue, StatusCode};
2023-01-30 17:11:30 -06:00
use tokio_util::io::ReaderStream;
2024-05-25 00:21:36 -05:00
use crate::engine::UploadData;
2023-01-30 17:11:30 -06:00
/// Responses for a failed view operation
2023-01-30 18:14:25 -06:00
pub enum ViewError {
/// Will send status code 404 with a plaintext "not found" message.
NotFound,
/// Will send status code 500 with a plaintext "internal server error" message.
InternalServerError,
2023-01-30 18:14:25 -06:00
}
2024-05-25 00:21:36 -05:00
impl IntoResponse for UploadData {
2023-01-30 17:11:30 -06:00
fn into_response(self) -> Response {
match self {
2024-05-25 00:21:36 -05:00
UploadData::Disk(file, len) => {
// create our content-length header
let len_str = len.to_string();
let content_length = HeaderValue::from_str(&len_str).unwrap();
2023-01-30 17:11:30 -06:00
// create a streamed body response (we want to stream larger files)
let reader = ReaderStream::new(file);
let stream = StreamBody::new(reader);
// 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
2023-01-30 17:11:30 -06:00
}
2024-05-25 00:21:36 -05:00
UploadData::Cache(data) => {
2023-01-30 17:11:30 -06:00
// extract mutable headers from the response
2023-06-28 16:24:07 -05:00
let mut res = data.into_response();
2023-01-30 17:11:30 -06:00
let headers = res.headers_mut();
// clear the headers, let the browser imply it
headers.clear();
res
}
}
}
}
2023-01-30 18:14:25 -06:00
impl IntoResponse for ViewError {
fn into_response(self) -> Response {
match self {
ViewError::NotFound => (
StatusCode::NOT_FOUND,
"not found!"
).into_response(),
ViewError::InternalServerError => (
StatusCode::INTERNAL_SERVER_ERROR,
"internal server error!"
).into_response(),
2023-01-30 18:14:25 -06:00
}
}
}
/// The request handler for /p/* path.
/// All file views are handled here.
2023-01-30 17:11:30 -06:00
#[axum::debug_handler]
pub async fn view(
State(engine): State<Arc<crate::engine::Engine>>,
Path(original_path): Path<PathBuf>,
2024-05-25 00:21:36 -05:00
) -> Result<UploadData, ViewError> {
let saved_name = if let Some(Some(n)) = original_path.file_name().map(OsStr::to_str) {
n
} else {
2023-01-30 18:14:25 -06:00
return Err(ViewError::NotFound);
2024-05-25 00:21:36 -05:00
};
2023-01-30 17:11:30 -06:00
2023-02-01 18:05:13 -06:00
// get result from the engine!
2024-05-25 00:21:36 -05:00
match engine.get(saved_name).await {
Ok(Some(u)) => Ok(u),
Ok(None) => Err(ViewError::NotFound),
Err(_) => Err(ViewError::InternalServerError),
}
2023-01-30 17:11:30 -06:00
}