1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
mod named_file;
pub use named_file::*;

use futures::Stream;
use hyper::body::Bytes;
use std::fs::File;
use std::io::{Read, Seek};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{cmp, io};

pub struct FileChunk {
    chunk_size: u64,
    read_size: u64,
    buffer_size: u64,
    offset: u64,
    file: File,
}
impl Stream for FileChunk {
    type Item = Result<Bytes, io::Error>;

    fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Option<Self::Item>> {
        let Self {
            chunk_size,
            ref mut read_size,
            ref mut offset,
            buffer_size,
            ref mut file,
        } = *self;

        if chunk_size == *read_size {
            Poll::Ready(None)
        } else {
            let max_bytes: usize;
            max_bytes = cmp::min(chunk_size.saturating_sub(*read_size), buffer_size) as usize;
            let mut buf = Vec::with_capacity(max_bytes);
            file.seek(io::SeekFrom::Start(*offset))?;
            let nbytes = file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?;
            if nbytes == 0 {
                Poll::Ready(Some(Err(std::io::ErrorKind::UnexpectedEof.into())))
            } else {
                *offset += nbytes as u64;
                *read_size += nbytes as u64;
                Poll::Ready(Some(Ok(Bytes::from(buf))))
            }
        }
    }
}