76 lines
1.7 KiB
Rust
76 lines
1.7 KiB
Rust
use std::{
|
|
io::{
|
|
self,
|
|
Read,
|
|
Seek,
|
|
SeekFrom,
|
|
},
|
|
};
|
|
|
|
use anyhow::{
|
|
Result,
|
|
anyhow,
|
|
};
|
|
|
|
pub struct NetReader {
|
|
client: reqwest::blocking::Client,
|
|
url: String,
|
|
len: u64,
|
|
cursor: u64,
|
|
}
|
|
|
|
impl NetReader {
|
|
pub fn new (url: String) -> Result <Self> {
|
|
let client = reqwest::blocking::Client::new ();
|
|
let len = client.head (&url).send ()?.content_length ().ok_or_else (|| anyhow! ("Couldn't get content-length of URL"))?;
|
|
|
|
Ok (NetReader {
|
|
client,
|
|
url,
|
|
cursor: 0,
|
|
len,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Read for NetReader {
|
|
fn read (&mut self, dest: &mut [u8]) -> io::Result <usize>
|
|
{
|
|
tracing::trace! ("NetReader reading {}-{}", self.cursor, self.cursor + dest.len () as u64);
|
|
|
|
let range_hdr = format! ("bytes={}-{}", self.cursor, self.cursor + dest.len () as u64 - 1);
|
|
|
|
let mut resp = self.client.get (&self.url)
|
|
.header (reqwest::header::RANGE, range_hdr)
|
|
.send ()
|
|
.map_err (|e| io::Error::new (io::ErrorKind::ConnectionRefused, e))?;
|
|
|
|
let mut cursor = std::io::Cursor::new (dest);
|
|
let bytes_moved = resp.copy_to (&mut cursor)
|
|
.map_err (|e| io::Error::new (io::ErrorKind::ConnectionReset, e))?;
|
|
|
|
self.cursor += bytes_moved;
|
|
tracing::trace! ("NetReader read {} bytes", bytes_moved);
|
|
Ok (bytes_moved.try_into ().unwrap ())
|
|
}
|
|
}
|
|
|
|
impl Seek for NetReader {
|
|
fn seek (&mut self, pos: SeekFrom) -> io::Result <u64>
|
|
{
|
|
// If your data is as big as 63 bits you'll just have
|
|
// to suffer I guess
|
|
|
|
let new_cursor = match pos {
|
|
SeekFrom::Start (x) => x as i64,
|
|
SeekFrom::Current (x) => self.cursor as i64 + x,
|
|
SeekFrom::End (x) => self.len as i64 + x,
|
|
};
|
|
|
|
let new_cursor = u64::try_from (new_cursor).map_err (|e| io::Error::new (io::ErrorKind::InvalidInput, e))?;
|
|
self.cursor = new_cursor;
|
|
|
|
Ok (self.cursor)
|
|
}
|
|
}
|