diff --git a/Cargo.lock b/Cargo.lock index 100a82253..128980377 100644 Binary files a/Cargo.lock and b/Cargo.lock differ diff --git a/apps/desktop/src-tauri/src/tauri_plugins.rs b/apps/desktop/src-tauri/src/tauri_plugins.rs index a6f73dbb9..156e92719 100644 --- a/apps/desktop/src-tauri/src/tauri_plugins.rs +++ b/apps/desktop/src-tauri/src/tauri_plugins.rs @@ -1,4 +1,8 @@ -use std::{io, net::TcpListener, sync::Arc}; +use std::{ + io, + net::{Ipv4Addr, TcpListener}, + sync::Arc, +}; use axum::{ extract::{Query, State, TypedHeader}, @@ -45,8 +49,13 @@ pub fn sd_server_plugin(node: Arc) -> io::Result metadata.len() { + return Ok(resp + .header( + header::CONTENT_RANGE, + HeaderValue::from_str(&format!("bytes */{}", metadata.len())) + .map_err(internal_server_error)?, + ) + .status(StatusCode::RANGE_NOT_SATISFIABLE) + .body(body::boxed(Full::from("")))); + } + file.seek(SeekFrom::Start(range.start)) .await .map_err(internal_server_error)?; - // TODO: Serve using streaming body instead of loading the entire chunk. - Right now my impl is not working correctly - let mut buf = Vec::with_capacity(range.length as usize); - file.take(range.length) - .read_to_end(&mut buf) - .await - .map_err(internal_server_error)?; - return Ok(resp - .status(StatusCode::PARTIAL_CONTENT) + .status(status_code) .header( "Content-Range", HeaderValue::from_str(&format!( @@ -392,12 +424,11 @@ async fn serve_file( HeaderValue::from_str(&range.length.to_string()) .map_err(internal_server_error)?, ) - .body(body::boxed(Full::from(buf)))); - // TODO: Serve as stream instead of fixed set of bytes -> Show allow only loading part in the chunk into memory at a time. This will also be probs be required or P2P over custom URI. - // .body(body::boxed(Limited::new( - // StreamBody::new(ReaderStream::new(file)), - // range.length.try_into().expect("integer overflow"), - // ))); + .body(body::boxed(AsyncReadBody::with_capacity_limited( + file, + DEFAULT_CAPACITY, + range.length, + )))); } } } @@ -534,6 +565,54 @@ async fn plz_for_the_love_of_all_that_is_good_replace_this_with_the_db_instead_o }) } +// This code was taken from: https://github.com/tower-rs/tower-http/blob/e8eb54966604ea7fa574a2a25e55232f5cfe675b/tower-http/src/services/fs/mod.rs#L30 +pin_project! { + // NOTE: This could potentially be upstreamed to `http-body`. + /// Adapter that turns an [`impl AsyncRead`][tokio::io::AsyncRead] to an [`impl Body`][http_body::Body]. + #[derive(Debug)] + pub struct AsyncReadBody { + #[pin] + reader: ReaderStream, + } +} + +impl AsyncReadBody +where + T: AsyncRead, +{ + fn with_capacity_limited( + read: T, + capacity: usize, + max_read_bytes: u64, + ) -> AsyncReadBody> { + AsyncReadBody { + reader: ReaderStream::with_capacity(read.take(max_read_bytes), capacity), + } + } +} + +impl HttpBody for AsyncReadBody +where + T: AsyncRead, +{ + type Data = Bytes; + type Error = io::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + self.project().reader.poll_next(cx) + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll, Self::Error>> { + Poll::Ready(Ok(None)) + } +} + /// Allowing wrapping an `mpsc::Sender` into an `AsyncWrite` pub struct MpscToAsyncWrite(PollSender>);