root_io/core/
data_source.rs1use std::fs::File;
2use std::io::{Read, Seek, SeekFrom};
3#[cfg(not(target_arch = "wasm32"))]
4use std::path::Path;
5use std::path::PathBuf;
6
7use failure::Error;
8use reqwest::{
9 header::{RANGE, USER_AGENT},
10 Client, Url,
11};
12
13#[derive(Debug, Clone)]
17pub struct Source(SourceInner);
18
19#[derive(Debug, Clone)]
22enum SourceInner {
23 Local(PathBuf),
25 Remote {
26 client: Client,
27 url: Url,
28 },
29}
30
31impl Source {
32 pub fn new<T: Into<Self>>(thing: T) -> Self {
33 thing.into()
34 }
35
36 pub async fn fetch(&self, start: u64, len: u64) -> Result<Vec<u8>, Error> {
37 match &self.0 {
38 SourceInner::Local(path) => {
39 let mut f = File::open(&path)?;
40 f.seek(SeekFrom::Start(start))?;
41 let mut buf = vec![0; len as usize];
42 f.read_exact(&mut buf)?;
43 Ok(buf)
44 }
45 SourceInner::Remote { client, url } => {
46 let rsp = client
47 .get(url.clone())
48 .header(USER_AGENT, "alice-rs")
49 .header(RANGE, format!("bytes={}-{}", start, start + len - 1))
50 .send()
51 .await?
52 .error_for_status()?;
53 let bytes = rsp.bytes().await?;
54 Ok(bytes.as_ref().to_vec())
55 }
56 }
57 }
58}
59
60impl From<Url> for Source {
61 fn from(url: Url) -> Self {
62 Self(SourceInner::Remote {
63 client: Client::new(),
64 url,
65 })
66 }
67}
68
69#[cfg(not(target_arch = "wasm32"))]
72impl From<&Path> for Source {
73 fn from(path: &Path) -> Self {
74 path.to_path_buf().into()
75 }
76}
77
78#[cfg(not(target_arch = "wasm32"))]
79impl From<PathBuf> for Source {
80 fn from(path_buf: PathBuf) -> Self {
81 Self(SourceInner::Local(path_buf))
82 }
83}