cacache_sync/get.rs
1//! Functions for reading from cache.
2use std::path::Path;
3
4use ssri::{Algorithm, Integrity};
5
6use crate::content::read;
7use crate::errors::{Error, Result};
8use crate::index::{self, Metadata};
9
10// ---------------
11// Synchronous API
12// ---------------
13
14/// File handle for reading data synchronously.
15///
16/// Make sure to call `get.check()` when done reading
17/// to verify that the extracted data passes integrity
18/// verification.
19pub struct Reader {
20 reader: read::Reader,
21}
22
23impl std::io::Read for Reader {
24 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
25 self.reader.read(buf)
26 }
27}
28
29impl Reader {
30 /// Checks that data read from disk passes integrity checks. Returns the
31 /// algorithm that was used verified the data. Should be called only after
32 /// all data has been read from disk.
33 ///
34 /// ## Example
35 /// ```no_run
36 /// use std::io::Read;
37 ///
38 /// fn main() -> cacache_sync::Result<()> {
39 /// let mut fd = cacache_sync::Reader::open("./my-cache", "my-key")?;
40 /// let mut str = String::new();
41 /// fd.read_to_string(&mut str).expect("Failed to read to string");
42 /// // Remember to check that the data you got was correct!
43 /// fd.check()?;
44 /// Ok(())
45 /// }
46 /// ```
47 pub fn check(self) -> Result<Algorithm> {
48 self.reader.check()
49 }
50
51 /// Opens a new synchronous file handle into the cache, looking it up in the
52 /// index using `key`.
53 ///
54 /// ## Example
55 /// ```no_run
56 /// use std::io::Read;
57 ///
58 /// fn main() -> cacache_sync::Result<()> {
59 /// let mut fd = cacache_sync::Reader::open("./my-cache", "my-key")?;
60 /// let mut str = String::new();
61 /// fd.read_to_string(&mut str).expect("Failed to parse string");
62 /// // Remember to check that the data you got was correct!
63 /// fd.check()?;
64 /// Ok(())
65 /// }
66 /// ```
67 pub fn open<P, K>(cache: P, key: K) -> Result<Reader>
68 where
69 P: AsRef<Path>,
70 K: AsRef<str>,
71 {
72 if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
73 Reader::open_hash(cache, entry.integrity)
74 } else {
75 return Err(Error::EntryNotFound(
76 cache.as_ref().to_path_buf(),
77 key.as_ref().into(),
78 ));
79 }
80 }
81
82 /// Opens a new synchronous file handle into the cache, based on its integrity address.
83 ///
84 /// ## Example
85 /// ```no_run
86 /// use std::io::Read;
87 ///
88 /// fn main() -> cacache_sync::Result<()> {
89 /// let sri = cacache_sync::write("./my-cache", "key", b"hello world")?;
90 /// let mut fd = cacache_sync::Reader::open_hash("./my-cache", sri)?;
91 /// let mut str = String::new();
92 /// fd.read_to_string(&mut str).expect("Failed to read to string");
93 /// // Remember to check that the data you got was correct!
94 /// fd.check()?;
95 /// Ok(())
96 /// }
97 /// ```
98 pub fn open_hash<P>(cache: P, sri: Integrity) -> Result<Reader>
99 where
100 P: AsRef<Path>,
101 {
102 Ok(Reader {
103 reader: read::open(cache.as_ref(), sri)?,
104 })
105 }
106}
107
108/// Reads the entire contents of a cache file synchronously into a bytes
109/// vector, looking the data up by key.
110///
111/// ## Example
112/// ```no_run
113/// use std::io::Read;
114///
115/// fn main() -> cacache_sync::Result<()> {
116/// let data = cacache_sync::read("./my-cache", "my-key")?;
117/// Ok(())
118/// }
119/// ```
120pub fn read<P, K>(cache: P, key: K) -> Result<Vec<u8>>
121where
122 P: AsRef<Path>,
123 K: AsRef<str>,
124{
125 if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
126 read_hash(cache, &entry.integrity)
127 } else {
128 return Err(Error::EntryNotFound(
129 cache.as_ref().to_path_buf(),
130 key.as_ref().into(),
131 ));
132 }
133}
134
135/// Reads the entire contents of a cache file synchronously into a bytes
136/// vector, looking the data up by its content address.
137///
138/// ## Example
139/// ```no_run
140/// use std::io::Read;
141///
142/// fn main() -> cacache_sync::Result<()> {
143/// let sri = cacache_sync::write("./my-cache", "my-key", b"hello")?;
144/// let data = cacache_sync::read_hash("./my-cache", &sri)?;
145/// Ok(())
146/// }
147/// ```
148pub fn read_hash<P>(cache: P, sri: &Integrity) -> Result<Vec<u8>>
149where
150 P: AsRef<Path>,
151{
152 read::read(cache.as_ref(), sri)
153}
154
155/// Copies a cache entry by key to a specified location. Returns the number of
156/// bytes copied.
157///
158/// ## Example
159/// ```no_run
160/// use std::io::Read;
161///
162/// fn main() -> cacache_sync::Result<()> {
163/// cacache_sync::copy("./my-cache", "my-key", "./my-hello.txt")?;
164/// Ok(())
165/// }
166/// ```
167pub fn copy<P, K, Q>(cache: P, key: K, to: Q) -> Result<u64>
168where
169 P: AsRef<Path>,
170 K: AsRef<str>,
171 Q: AsRef<Path>,
172{
173 if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
174 copy_hash(cache, &entry.integrity, to)
175 } else {
176 return Err(Error::EntryNotFound(
177 cache.as_ref().to_path_buf(),
178 key.as_ref().into(),
179 ));
180 }
181}
182
183/// Copies a cache entry by integrity address to a specified location. Returns
184/// the number of bytes copied.
185///
186/// ## Example
187/// ```no_run
188/// use std::io::Read;
189///
190/// fn main() -> cacache_sync::Result<()> {
191/// let sri = cacache_sync::write("./my-cache", "my-key", b"hello")?;
192/// cacache_sync::copy_hash("./my-cache", &sri, "./my-hello.txt")?;
193/// Ok(())
194/// }
195/// ```
196pub fn copy_hash<P, Q>(cache: P, sri: &Integrity, to: Q) -> Result<u64>
197where
198 P: AsRef<Path>,
199 Q: AsRef<Path>,
200{
201 read::copy(cache.as_ref(), sri, to.as_ref())
202}
203
204/// Gets metadata for a certain key.
205///
206/// Note that the existence of a metadata entry is not a guarantee that the
207/// underlying data exists, since they are stored and managed independently.
208/// To verify that the underlying associated data exists, use `exists()`.
209pub fn metadata<P, K>(cache: P, key: K) -> Result<Option<Metadata>>
210where
211 P: AsRef<Path>,
212 K: AsRef<str>,
213{
214 index::find(cache.as_ref(), key.as_ref())
215}
216
217/// Returns true if the given hash exists in the cache.
218pub fn exists<P: AsRef<Path>>(cache: P, sri: &Integrity) -> bool {
219 read::has_content(cache.as_ref(), sri).is_some()
220}
221
222#[cfg(test)]
223mod tests {
224 use std::fs;
225
226 #[test]
227 fn test_open() {
228 use std::io::prelude::*;
229 let tmp = tempfile::tempdir().unwrap();
230 let dir = tmp.path().to_owned();
231 crate::write(&dir, "my-key", b"hello world").unwrap();
232
233 let mut handle = crate::Reader::open(&dir, "my-key").unwrap();
234 let mut str = String::new();
235 handle.read_to_string(&mut str).unwrap();
236 handle.check().unwrap();
237 assert_eq!(str, String::from("hello world"));
238 }
239
240 #[test]
241 fn test_open_hash() {
242 use std::io::prelude::*;
243 let tmp = tempfile::tempdir().unwrap();
244 let dir = tmp.path().to_owned();
245 let sri = crate::write(&dir, "my-key", b"hello world").unwrap();
246
247 let mut handle = crate::Reader::open_hash(&dir, sri).unwrap();
248 let mut str = String::new();
249 handle.read_to_string(&mut str).unwrap();
250 handle.check().unwrap();
251 assert_eq!(str, String::from("hello world"));
252 }
253
254 #[test]
255 fn test_read() {
256 let tmp = tempfile::tempdir().unwrap();
257 let dir = tmp.path().to_owned();
258 crate::write(&dir, "my-key", b"hello world").unwrap();
259
260 let data = crate::read(&dir, "my-key").unwrap();
261 assert_eq!(data, b"hello world");
262 }
263
264 #[test]
265 fn test_read_hash() {
266 let tmp = tempfile::tempdir().unwrap();
267 let dir = tmp.path().to_owned();
268 let sri = crate::write(&dir, "my-key", b"hello world").unwrap();
269
270 let data = crate::read_hash(&dir, &sri).unwrap();
271 assert_eq!(data, b"hello world");
272 }
273
274 #[test]
275 fn test_copy() {
276 let tmp = tempfile::tempdir().unwrap();
277 let dir = tmp.path();
278 let dest = dir.join("data");
279 crate::write(dir, "my-key", b"hello world").unwrap();
280
281 crate::copy(dir, "my-key", &dest).unwrap();
282 let data = fs::read(&dest).unwrap();
283 assert_eq!(data, b"hello world");
284 }
285
286 #[test]
287 fn test_copy_hash() {
288 let tmp = tempfile::tempdir().unwrap();
289 let dir = tmp.path();
290 let dest = dir.join("data");
291 let sri = crate::write(dir, "my-key", b"hello world").unwrap();
292
293 crate::copy_hash(dir, &sri, &dest).unwrap();
294 let data = fs::read(&dest).unwrap();
295 assert_eq!(data, b"hello world");
296 }
297}