2021-10-13 04:16:31 +00:00
|
|
|
#[cfg(feature = "io-uring")]
|
|
|
|
pub(crate) use io_uring::File;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "io-uring"))]
|
2021-10-14 00:06:53 +00:00
|
|
|
pub(crate) use tokio_file::File;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
#[cfg(not(feature = "io-uring"))]
|
|
|
|
mod tokio_file {
|
2023-08-23 16:59:42 +00:00
|
|
|
use crate::{store::file_store::FileError, stream::IntoStreamer, Either};
|
2021-10-14 00:06:53 +00:00
|
|
|
use actix_web::web::{Bytes, BytesMut};
|
2023-08-23 16:59:42 +00:00
|
|
|
use futures_core::Stream;
|
|
|
|
use futures_util::TryStreamExt;
|
2021-11-01 02:11:35 +00:00
|
|
|
use std::{io::SeekFrom, path::Path};
|
2021-10-14 00:06:53 +00:00
|
|
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, AsyncWrite, AsyncWriteExt};
|
|
|
|
use tokio_util::codec::{BytesCodec, FramedRead};
|
|
|
|
|
|
|
|
pub(crate) struct File {
|
|
|
|
inner: tokio::fs::File,
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
impl File {
|
|
|
|
pub(crate) async fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
|
|
|
Ok(File {
|
2022-04-07 17:56:40 +00:00
|
|
|
inner: tracing::trace_span!(parent: None, "Open File")
|
|
|
|
.in_scope(|| tokio::fs::File::open(path))
|
|
|
|
.await?,
|
2021-10-14 00:06:53 +00:00
|
|
|
})
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
pub(crate) async fn create(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
|
|
|
Ok(File {
|
2022-04-07 17:56:40 +00:00
|
|
|
inner: tracing::trace_span!(parent: None, "Create File")
|
|
|
|
.in_scope(|| tokio::fs::File::create(path))
|
|
|
|
.await?,
|
2021-10-14 00:06:53 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
pub(crate) async fn write_from_bytes(&mut self, mut bytes: Bytes) -> std::io::Result<()> {
|
2021-10-14 00:06:53 +00:00
|
|
|
self.inner.write_all_buf(&mut bytes).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-11-01 02:11:35 +00:00
|
|
|
pub(crate) async fn write_from_stream<S>(&mut self, stream: S) -> std::io::Result<()>
|
2021-10-23 19:14:12 +00:00
|
|
|
where
|
|
|
|
S: Stream<Item = std::io::Result<Bytes>>,
|
|
|
|
{
|
2023-08-23 16:59:42 +00:00
|
|
|
let stream = std::pin::pin!(stream);
|
|
|
|
let mut stream = stream.into_streamer();
|
2021-10-23 19:14:12 +00:00
|
|
|
|
|
|
|
while let Some(res) = stream.next().await {
|
|
|
|
let mut bytes = res?;
|
|
|
|
|
|
|
|
self.inner.write_all_buf(&mut bytes).await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
pub(crate) async fn write_from_async_read<R>(
|
|
|
|
&mut self,
|
2021-10-14 00:06:53 +00:00
|
|
|
mut reader: R,
|
|
|
|
) -> std::io::Result<()>
|
|
|
|
where
|
|
|
|
R: AsyncRead + Unpin,
|
|
|
|
{
|
|
|
|
tokio::io::copy(&mut reader, &mut self.inner).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-23 19:14:12 +00:00
|
|
|
pub(crate) async fn close(self) -> std::io::Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
pub(crate) async fn read_to_async_write<W>(&mut self, writer: &mut W) -> std::io::Result<()>
|
2021-10-14 00:06:53 +00:00
|
|
|
where
|
2021-10-23 04:48:56 +00:00
|
|
|
W: AsyncWrite + Unpin + ?Sized,
|
2021-10-14 00:06:53 +00:00
|
|
|
{
|
|
|
|
tokio::io::copy(&mut self.inner, writer).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) async fn read_to_stream(
|
|
|
|
mut self,
|
|
|
|
from_start: Option<u64>,
|
|
|
|
len: Option<u64>,
|
2021-10-23 04:48:56 +00:00
|
|
|
) -> Result<impl Stream<Item = std::io::Result<Bytes>>, FileError> {
|
2021-10-14 00:06:53 +00:00
|
|
|
let obj = match (from_start, len) {
|
|
|
|
(Some(lower), Some(upper)) => {
|
|
|
|
self.inner.seek(SeekFrom::Start(lower)).await?;
|
2021-10-18 23:02:33 +00:00
|
|
|
Either::left(self.inner.take(upper))
|
2021-10-14 00:06:53 +00:00
|
|
|
}
|
2021-10-18 23:02:33 +00:00
|
|
|
(None, Some(upper)) => Either::left(self.inner.take(upper)),
|
2021-10-14 00:06:53 +00:00
|
|
|
(Some(lower), None) => {
|
|
|
|
self.inner.seek(SeekFrom::Start(lower)).await?;
|
2021-10-18 23:02:33 +00:00
|
|
|
Either::right(self.inner)
|
2021-10-14 00:06:53 +00:00
|
|
|
}
|
2021-10-18 23:02:33 +00:00
|
|
|
(None, None) => Either::right(self.inner),
|
2021-10-14 00:06:53 +00:00
|
|
|
};
|
|
|
|
|
2022-03-29 19:28:08 +00:00
|
|
|
Ok(FramedRead::new(obj, BytesCodec::new()).map_ok(BytesMut::freeze))
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-14 00:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "io-uring")]
|
|
|
|
mod io_uring {
|
2023-08-23 16:59:42 +00:00
|
|
|
use crate::{store::file_store::FileError, stream::IntoStreamer};
|
2022-01-14 00:11:46 +00:00
|
|
|
use actix_web::web::{Bytes, BytesMut};
|
2023-08-23 16:59:42 +00:00
|
|
|
use futures_core::Stream;
|
2021-10-14 00:06:53 +00:00
|
|
|
use std::{
|
|
|
|
convert::TryInto,
|
|
|
|
fs::Metadata,
|
|
|
|
future::Future,
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
|
|
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
|
|
|
use tokio_uring::{
|
2021-10-14 00:50:07 +00:00
|
|
|
buf::{IoBuf, IoBufMut},
|
2021-10-14 00:06:53 +00:00
|
|
|
BufResult,
|
|
|
|
};
|
2021-10-13 04:16:31 +00:00
|
|
|
|
|
|
|
pub(crate) struct File {
|
|
|
|
path: PathBuf,
|
2021-10-14 00:06:53 +00:00
|
|
|
inner: tokio_uring::fs::File,
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl File {
|
|
|
|
pub(crate) async fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
2022-10-02 02:17:18 +00:00
|
|
|
tracing::debug!("Opening io-uring file: {:?}", path.as_ref());
|
2021-10-13 04:16:31 +00:00
|
|
|
Ok(File {
|
|
|
|
path: path.as_ref().to_owned(),
|
2022-04-07 17:56:40 +00:00
|
|
|
inner: tracing::trace_span!(parent: None, "Open File")
|
|
|
|
.in_scope(|| tokio_uring::fs::File::open(path))
|
|
|
|
.await?,
|
2021-10-13 04:16:31 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) async fn create(path: impl AsRef<Path>) -> std::io::Result<Self> {
|
2022-10-02 02:17:18 +00:00
|
|
|
tracing::debug!("Creating io-uring file: {:?}", path.as_ref());
|
2021-10-13 04:16:31 +00:00
|
|
|
Ok(File {
|
|
|
|
path: path.as_ref().to_owned(),
|
2022-04-07 17:56:40 +00:00
|
|
|
inner: tracing::trace_span!(parent: None, "Create File")
|
|
|
|
.in_scope(|| tokio_uring::fs::File::create(path))
|
|
|
|
.await?,
|
2021-10-13 04:16:31 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
async fn metadata(&self) -> std::io::Result<Metadata> {
|
2021-10-13 04:16:31 +00:00
|
|
|
tokio::fs::metadata(&self.path).await
|
|
|
|
}
|
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
pub(crate) async fn write_from_bytes(&mut self, mut buf: Bytes) -> std::io::Result<()> {
|
2021-10-14 00:06:53 +00:00
|
|
|
let len: u64 = buf.len().try_into().unwrap();
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let mut cursor: u64 = 0;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
loop {
|
|
|
|
if cursor == len {
|
|
|
|
break;
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let cursor_usize: usize = cursor.try_into().unwrap();
|
|
|
|
let (res, slice) = self.inner.write_at(buf.slice(cursor_usize..), cursor).await;
|
|
|
|
let n: usize = res?;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
if n == 0 {
|
|
|
|
return Err(std::io::ErrorKind::UnexpectedEof.into());
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
buf = slice.into_inner();
|
|
|
|
let n: u64 = n.try_into().unwrap();
|
|
|
|
cursor += n;
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
2021-10-14 00:06:53 +00:00
|
|
|
|
2021-10-14 00:50:07 +00:00
|
|
|
self.inner.sync_all().await?;
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
Ok(())
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 02:11:35 +00:00
|
|
|
pub(crate) async fn write_from_stream<S>(&mut self, stream: S) -> std::io::Result<()>
|
2021-10-23 19:14:12 +00:00
|
|
|
where
|
|
|
|
S: Stream<Item = std::io::Result<Bytes>>,
|
|
|
|
{
|
2023-08-23 16:59:42 +00:00
|
|
|
let stream = std::pin::pin!(stream);
|
|
|
|
let mut stream = stream.into_streamer();
|
2021-10-23 19:14:12 +00:00
|
|
|
let mut cursor: u64 = 0;
|
|
|
|
|
|
|
|
while let Some(res) = stream.next().await {
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut buf = res?;
|
2021-10-23 19:14:12 +00:00
|
|
|
|
|
|
|
let len = buf.len();
|
|
|
|
let mut position = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if position == len {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let position_u64: u64 = position.try_into().unwrap();
|
|
|
|
let (res, slice) = self
|
|
|
|
.write_at(buf.slice(position..len), cursor + position_u64)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let n = res?;
|
|
|
|
if n == 0 {
|
|
|
|
return Err(std::io::ErrorKind::UnexpectedEof.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
position += n;
|
|
|
|
|
|
|
|
buf = slice.into_inner();
|
|
|
|
}
|
|
|
|
|
|
|
|
let position: u64 = position.try_into().unwrap();
|
|
|
|
cursor += position;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.inner.sync_all().await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-07-05 05:35:07 +00:00
|
|
|
#[tracing::instrument(level = "debug", skip_all)]
|
2021-10-23 04:48:56 +00:00
|
|
|
pub(crate) async fn write_from_async_read<R>(
|
|
|
|
&mut self,
|
2021-10-14 00:06:53 +00:00
|
|
|
mut reader: R,
|
|
|
|
) -> std::io::Result<()>
|
|
|
|
where
|
|
|
|
R: AsyncRead + Unpin,
|
|
|
|
{
|
|
|
|
let mut cursor: u64 = 0;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
loop {
|
2021-10-14 00:50:07 +00:00
|
|
|
let max_size = 65_536;
|
2021-10-14 00:06:53 +00:00
|
|
|
let mut buf = Vec::with_capacity(max_size.try_into().unwrap());
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2023-07-05 05:35:07 +00:00
|
|
|
let n = (&mut reader).take(max_size).read_buf(&mut buf).await?;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
if n == 0 {
|
|
|
|
break;
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let mut position = 0;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
loop {
|
2021-10-14 00:50:07 +00:00
|
|
|
if position == n {
|
2021-10-14 00:06:53 +00:00
|
|
|
break;
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:50:07 +00:00
|
|
|
let position_u64: u64 = position.try_into().unwrap();
|
|
|
|
let (res, slice) = self
|
|
|
|
.write_at(buf.slice(position..n), cursor + position_u64)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let n = res?;
|
|
|
|
if n == 0 {
|
|
|
|
return Err(std::io::ErrorKind::UnexpectedEof.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
position += n;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
buf = slice.into_inner();
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let position: u64 = position.try_into().unwrap();
|
|
|
|
cursor += position;
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:50:07 +00:00
|
|
|
self.inner.sync_all().await?;
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
Ok(())
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-23 19:14:12 +00:00
|
|
|
pub(crate) async fn close(self) -> std::io::Result<()> {
|
|
|
|
self.inner.close().await
|
|
|
|
}
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
pub(crate) async fn read_to_async_write<W>(&mut self, writer: &mut W) -> std::io::Result<()>
|
2021-10-14 00:06:53 +00:00
|
|
|
where
|
2021-10-23 04:48:56 +00:00
|
|
|
W: AsyncWrite + Unpin + ?Sized,
|
2021-10-14 00:06:53 +00:00
|
|
|
{
|
|
|
|
let metadata = self.metadata().await?;
|
|
|
|
let size = metadata.len();
|
|
|
|
|
|
|
|
let mut cursor: u64 = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if cursor == size {
|
|
|
|
break;
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let max_size = (size - cursor).min(65_536);
|
2022-01-14 00:11:46 +00:00
|
|
|
let buf = BytesMut::with_capacity(max_size.try_into().unwrap());
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
let (res, buf): (_, BytesMut) = self.read_at(buf, cursor).await;
|
2021-10-14 00:06:53 +00:00
|
|
|
let n: usize = res?;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
if n == 0 {
|
|
|
|
return Err(std::io::ErrorKind::UnexpectedEof.into());
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-28 04:06:03 +00:00
|
|
|
writer.write_all(&buf[0..n]).await?;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
let n: u64 = n.try_into().unwrap();
|
|
|
|
cursor += n;
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
Ok(())
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
pub(crate) async fn read_to_stream(
|
|
|
|
self,
|
|
|
|
from_start: Option<u64>,
|
|
|
|
len: Option<u64>,
|
2021-10-23 04:48:56 +00:00
|
|
|
) -> Result<impl Stream<Item = std::io::Result<Bytes>>, FileError> {
|
2021-10-14 00:06:53 +00:00
|
|
|
let size = self.metadata().await?.len();
|
|
|
|
|
|
|
|
let cursor = from_start.unwrap_or(0);
|
|
|
|
let size = len.unwrap_or(size - cursor) + cursor;
|
|
|
|
|
2021-10-23 04:48:56 +00:00
|
|
|
Ok(BytesStream {
|
2022-01-14 00:11:46 +00:00
|
|
|
state: ReadFileState::File {
|
|
|
|
file: Some(self),
|
|
|
|
bytes: Some(BytesMut::new()),
|
|
|
|
},
|
2021-10-23 04:48:56 +00:00
|
|
|
size,
|
|
|
|
cursor,
|
|
|
|
callback: read_file,
|
2021-10-18 23:02:33 +00:00
|
|
|
})
|
2021-10-14 00:06:53 +00:00
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
async fn read_at<T: IoBufMut>(&self, buf: T, pos: u64) -> BufResult<usize, T> {
|
|
|
|
self.inner.read_at(buf, pos).await
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
async fn write_at<T: IoBuf>(&self, buf: T, pos: u64) -> BufResult<usize, T> {
|
|
|
|
self.inner.write_at(buf, pos).await
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
pin_project_lite::pin_project! {
|
|
|
|
struct BytesStream<F, Fut> {
|
|
|
|
#[pin]
|
|
|
|
state: ReadFileState<Fut>,
|
|
|
|
size: u64,
|
|
|
|
cursor: u64,
|
|
|
|
#[pin]
|
|
|
|
callback: F,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pin_project_lite::pin_project! {
|
|
|
|
#[project = ReadFileStateProj]
|
|
|
|
#[project_replace = ReadFileStateProjReplace]
|
|
|
|
enum ReadFileState<Fut> {
|
|
|
|
File {
|
|
|
|
file: Option<File>,
|
2022-01-14 00:11:46 +00:00
|
|
|
bytes: Option<BytesMut>,
|
2021-10-18 23:02:33 +00:00
|
|
|
},
|
|
|
|
Future {
|
|
|
|
#[pin]
|
|
|
|
fut: Fut,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn read_file(
|
|
|
|
file: File,
|
2022-01-14 00:11:46 +00:00
|
|
|
buf: BytesMut,
|
2021-10-14 00:06:53 +00:00
|
|
|
cursor: u64,
|
2022-01-14 00:11:46 +00:00
|
|
|
) -> (File, BufResult<usize, BytesMut>) {
|
2021-10-18 23:02:33 +00:00
|
|
|
let buf_res = file.read_at(buf, cursor).await;
|
|
|
|
|
|
|
|
(file, buf_res)
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
impl<F, Fut> Stream for BytesStream<F, Fut>
|
|
|
|
where
|
2022-01-14 00:11:46 +00:00
|
|
|
F: Fn(File, BytesMut, u64) -> Fut,
|
|
|
|
Fut: Future<Output = (File, BufResult<usize, BytesMut>)> + 'static,
|
2021-10-18 23:02:33 +00:00
|
|
|
{
|
2021-10-14 00:06:53 +00:00
|
|
|
type Item = std::io::Result<Bytes>;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-14 00:06:53 +00:00
|
|
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
2021-10-18 23:02:33 +00:00
|
|
|
let mut this = self.as_mut().project();
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
match this.state.as_mut().project() {
|
2022-01-14 00:11:46 +00:00
|
|
|
ReadFileStateProj::File { file, bytes } => {
|
2021-10-18 23:02:33 +00:00
|
|
|
let cursor = *this.cursor;
|
|
|
|
let max_size = *this.size - *this.cursor;
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
if max_size == 0 {
|
|
|
|
return Poll::Ready(None);
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
let capacity = max_size.min(65_356) as usize;
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut bytes = bytes.take().unwrap();
|
2021-10-18 23:02:33 +00:00
|
|
|
let file = file.take().unwrap();
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
if bytes.capacity() < capacity {
|
|
|
|
bytes.reserve(capacity - bytes.capacity());
|
|
|
|
}
|
|
|
|
|
|
|
|
let fut = (this.callback)(file, bytes, cursor);
|
2021-10-13 04:16:31 +00:00
|
|
|
|
2021-10-18 23:02:33 +00:00
|
|
|
this.state.project_replace(ReadFileState::Future { fut });
|
|
|
|
self.poll_next(cx)
|
2021-10-14 00:06:53 +00:00
|
|
|
}
|
2021-10-18 23:02:33 +00:00
|
|
|
ReadFileStateProj::Future { fut } => match fut.poll(cx) {
|
|
|
|
Poll::Pending => Poll::Pending,
|
|
|
|
Poll::Ready((file, (Ok(n), mut buf))) => {
|
2022-01-14 00:11:46 +00:00
|
|
|
let bytes = buf.split_off(n);
|
|
|
|
|
|
|
|
this.state.project_replace(ReadFileState::File {
|
|
|
|
file: Some(file),
|
|
|
|
bytes: Some(bytes),
|
|
|
|
});
|
2021-10-18 23:02:33 +00:00
|
|
|
|
|
|
|
let n: u64 = match n.try_into() {
|
|
|
|
Ok(n) => n,
|
|
|
|
Err(_) => {
|
|
|
|
return Poll::Ready(Some(Err(std::io::ErrorKind::Other.into())))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
*this.cursor += n;
|
|
|
|
|
|
|
|
Poll::Ready(Some(Ok(buf.into())))
|
|
|
|
}
|
|
|
|
Poll::Ready((_, (Err(e), _))) => Poll::Ready(Some(Err(e))),
|
|
|
|
},
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-14 00:50:07 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::io::Read;
|
|
|
|
|
|
|
|
macro_rules! test_on_arbiter {
|
|
|
|
($fut:expr) => {
|
|
|
|
actix_rt::System::new().block_on(async move {
|
|
|
|
let arbiter = actix_rt::Arbiter::new();
|
|
|
|
|
|
|
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
|
|
|
|
|
|
|
arbiter.spawn(async move {
|
|
|
|
let handle = actix_rt::spawn($fut);
|
|
|
|
|
|
|
|
let _ = tx.send(handle.await.unwrap());
|
|
|
|
});
|
|
|
|
|
|
|
|
rx.await.unwrap()
|
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const EARTH_GIF: &'static str = "client-examples/earth.gif";
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn read() {
|
|
|
|
let tmp = "/tmp/read-test";
|
|
|
|
|
|
|
|
test_on_arbiter!(async move {
|
|
|
|
let mut file = super::File::open(EARTH_GIF).await.unwrap();
|
|
|
|
let mut tmp_file = tokio::fs::File::create(tmp).await.unwrap();
|
|
|
|
file.read_to_async_write(&mut tmp_file).await.unwrap();
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut source = std::fs::File::open(EARTH_GIF).unwrap();
|
|
|
|
let mut dest = std::fs::File::open(tmp).unwrap();
|
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut source_bytes = Vec::new();
|
|
|
|
source.read_to_end(&mut source_bytes).unwrap();
|
2021-10-14 00:50:07 +00:00
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut dest_bytes = Vec::new();
|
|
|
|
dest.read_to_end(&mut dest_bytes).unwrap();
|
2021-10-14 00:50:07 +00:00
|
|
|
|
|
|
|
drop(dest);
|
|
|
|
std::fs::remove_file(tmp).unwrap();
|
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
assert_eq!(source_bytes.len(), dest_bytes.len());
|
|
|
|
assert_eq!(source_bytes, dest_bytes);
|
2021-10-14 00:50:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn write() {
|
|
|
|
let tmp = "/tmp/write-test";
|
|
|
|
|
|
|
|
test_on_arbiter!(async move {
|
|
|
|
let mut file = tokio::fs::File::open(EARTH_GIF).await.unwrap();
|
|
|
|
let mut tmp_file = super::File::create(tmp).await.unwrap();
|
|
|
|
tmp_file.write_from_async_read(&mut file).await.unwrap();
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut source = std::fs::File::open(EARTH_GIF).unwrap();
|
|
|
|
let mut dest = std::fs::File::open(tmp).unwrap();
|
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut source_bytes = Vec::new();
|
|
|
|
source.read_to_end(&mut source_bytes).unwrap();
|
2021-10-14 00:50:07 +00:00
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
let mut dest_bytes = Vec::new();
|
|
|
|
dest.read_to_end(&mut dest_bytes).unwrap();
|
2021-10-14 00:50:07 +00:00
|
|
|
|
|
|
|
drop(dest);
|
|
|
|
std::fs::remove_file(tmp).unwrap();
|
|
|
|
|
2022-01-14 00:11:46 +00:00
|
|
|
assert_eq!(source_bytes.len(), dest_bytes.len());
|
|
|
|
assert_eq!(source_bytes, dest_bytes);
|
2021-10-14 00:50:07 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-13 04:16:31 +00:00
|
|
|
}
|