stream books instead of reading them into memory
This commit is contained in:
parent
d7f056f77e
commit
d00a7ef8dc
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1371,6 +1371,7 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -17,6 +17,7 @@ tera = "1.19.1"
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
time = { workspace = true }
|
time = { workspace = true }
|
||||||
tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] }
|
tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] }
|
||||||
|
tokio-util = "0.7.11"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
uuid = { version = "1.8.0", features = ["v4", "fast-rng"] }
|
uuid = { version = "1.8.0", features = ["v4", "fast-rng"] }
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
//! Handle requests for specific formats of a book.
|
//! Handle requests for specific formats of a book.
|
||||||
|
|
||||||
use std::{fs::File, io::Read, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::fs::File;
|
||||||
|
|
||||||
use poem::{
|
use poem::{
|
||||||
error::NotFoundError,
|
error::NotFoundError,
|
||||||
handler,
|
handler,
|
||||||
web::{Data, Path, WithContentType, WithHeader},
|
web::{Data, Path},
|
||||||
IntoResponse,
|
Body, IntoResponse, Response,
|
||||||
};
|
};
|
||||||
|
use tokio_util::io::ReaderStream;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_state::AppState,
|
app_state::AppState,
|
||||||
data::book::{Book, Format},
|
data::book::{Book, Format},
|
||||||
handlers::error::HandlerError,
|
handlers::error::HandlerError,
|
||||||
|
opds::media_type::MediaType,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Handle a request for a book with id `id` in format `format`.
|
/// Handle a request for a book with id `id` in format `format`.
|
||||||
@ -20,7 +24,7 @@ use crate::{
|
|||||||
pub async fn handler(
|
pub async fn handler(
|
||||||
Path((id, format)): Path<(u64, String)>,
|
Path((id, format)): Path<(u64, String)>,
|
||||||
state: Data<&Arc<AppState>>,
|
state: Data<&Arc<AppState>>,
|
||||||
) -> Result<WithHeader<WithContentType<Vec<u8>>>, poem::Error> {
|
) -> Result<Response, poem::Error> {
|
||||||
let book = state
|
let book = state
|
||||||
.calibre
|
.calibre
|
||||||
.scalar_book(id)
|
.scalar_book(id)
|
||||||
@ -33,13 +37,14 @@ pub async fn handler(
|
|||||||
.library_path
|
.library_path
|
||||||
.join(book.data.path)
|
.join(book.data.path)
|
||||||
.join(file_name);
|
.join(file_name);
|
||||||
let mut file = File::open(file_path).map_err(|_| NotFoundError)?;
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
let mut file = File::open(file_path).await.map_err(|_| NotFoundError)?;
|
||||||
file.read_to_end(&mut data).map_err(|_| NotFoundError)?;
|
let stream = ReaderStream::new(file);
|
||||||
let content_type = format.0;
|
let body = Body::from_bytes_stream(stream);
|
||||||
|
|
||||||
Ok(data
|
let content_type: MediaType = format.into();
|
||||||
.with_content_type(content_type)
|
Ok(body
|
||||||
.with_header("Content-Disposition", format!("filename={file_name};")))
|
.with_content_type(format!("{content_type}"))
|
||||||
|
.with_header("Content-Disposition", format!("filename=\"{file_name}\""))
|
||||||
|
.into_response())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user