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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
#[cfg(not(target_arch = "wasm32"))]
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use failure::Error;
use reqwest::{
header::{RANGE, USER_AGENT},
Client, Url,
};
use async_trait::async_trait;
#[derive(Debug, Clone)]
pub struct Source {
inner: Arc<dyn DataSource + Send + Sync>,
}
impl Source {
pub fn new<T: Into::<Self>>(thing: T) -> Self {
thing.into()
}
pub async fn fetch(&self, start: u64, len: u64) -> Result<Vec<u8>, Error> {
self.inner.fetch(start, len).await
}
}
#[async_trait(?Send)]
trait DataSource: std::fmt::Debug {
async fn fetch(&self, start: u64, len: u64) -> Result<Vec<u8>, Error>;
}
#[derive(Debug, Clone)]
struct LocalDataSource(PathBuf);
#[derive(Debug)]
struct RemoteDataSource {
client: Client,
url: Url,
}
impl From<Url> for Source {
fn from(url: Url) -> Self {
Self {
inner: Arc::new(
RemoteDataSource {
client: Client::new(),
url,
})
}
}
}
#[cfg(not(target_arch = "wasm32"))]
impl From<&Path> for Source {
fn from(path: &Path) -> Self {
Self {
inner: Arc::new(
LocalDataSource(path.to_path_buf())
)
}
}
}
#[cfg(not(target_arch = "wasm32"))]
impl From<PathBuf> for Source {
fn from(path_buf: PathBuf) -> Self {
Self {
inner: Arc::new(
LocalDataSource(path_buf)
)
}
}
}
#[async_trait(?Send)]
impl DataSource for LocalDataSource {
async fn fetch(&self, start: u64, len: u64) -> Result<Vec<u8>, Error> {
let mut f = File::open(&self.0)?;
f.seek(SeekFrom::Start(start))?;
let mut buf = vec![0; len as usize];
f.read_exact(&mut buf)?;
Ok(buf)
}
}
#[async_trait(?Send)]
impl DataSource for RemoteDataSource {
async fn fetch(&self, start: u64, len: u64) -> Result<Vec<u8>, Error> {
let rsp = Client::new()
.get(self.url.clone())
.header(USER_AGENT, "alice-rs")
.header(RANGE, format!("bytes={}-{}", start, start + len - 1))
.send()
.await?;
let bytes = rsp.bytes().await?;
Ok(bytes.as_ref().to_vec())
}
}