diff --git a/src/content/read.rs b/src/content/read.rs index 39efbdb..9c307ad 100644 --- a/src/content/read.rs +++ b/src/content/read.rs @@ -118,16 +118,30 @@ pub fn read(cache: &Path, sri: &Integrity) -> Result> { } #[cfg(any(feature = "async-std", feature = "tokio"))] -pub async fn read_async<'a>(cache: &'a Path, sri: &'a Integrity) -> Result> { - let cpath = path::content_path(cache, sri); +pub async fn read_async<'c, 's>(cache: &'c Path, sri: Integrity, verify_integrity: bool) -> Result<(Vec, Integrity)> { + let cpath = path::content_path(&cache, &sri); let ret = crate::async_lib::read(&cpath).await.with_context(|| { format!( "Failed to read contents for file at {}", - path::content_path(cache, sri).display() + path::content_path(&cache, &sri).display() ) })?; - sri.check(&ret)?; - Ok(ret) + Ok(if verify_integrity { + // we require owned Integrity because of the below move which would otherwise try to + // provide a reference to a closure that moves to another thread, i.e. `'s: 'static` which fails + let integrity_check = move || { + sri.check(&ret)?; + Ok::<_, ssri::Error>((sri, ret)) + }; + #[cfg(feature = "tokio")] + let (sri, ret) = tokio::task::spawn_blocking(integrity_check).await??; + #[cfg(feature = "async-std")] + let (sri, ret) = async_std::task::spawn_blocking(integrity_check).await?; + + (ret, sri) + } else { + (ret, sri) + }) } pub fn reflink_unchecked(cache: &Path, sri: &Integrity, to: &Path) -> Result<()> { diff --git a/src/errors.rs b/src/errors.rs index ccb864d..30e1cd5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -31,6 +31,12 @@ pub enum Error { #[error(transparent)] #[diagnostic(code(cacache::integrity_error), url(docsrs))] IntegrityError(#[from] ssri::Error), + + /// Returned when a Tokio join error occured. + #[cfg(feature="tokio")] + #[error(transparent)] + #[diagnostic(code(cacache::tokio_joinerror), url(docsrs))] + TokioJoinError(#[from] tokio::task::JoinError) } /// The result type returned by calls to this library diff --git a/src/get.rs b/src/get.rs index b4f8101..faee3f3 100644 --- a/src/get.rs +++ b/src/get.rs @@ -159,7 +159,40 @@ where { async fn inner(cache: &Path, key: &str) -> Result> { if let Some(entry) = index::find_async(cache, key).await? { - read_hash(cache, &entry.integrity).await + read_hash(cache, entry.integrity).await.map(|(r, _i)| r) + } else { + Err(Error::EntryNotFound(cache.to_path_buf(), key.into())) + } + } + inner(cache.as_ref(), key.as_ref()).await +} + +/// Reads the entire contents of a cache file into a bytes vector, looking the +/// data up by key. Skips integrity checking. Use this for loading large files. +/// +/// ## Example +/// ```no_run +/// use async_std::prelude::*; +/// use async_attributes; +/// +/// #[async_attributes::main] +/// async fn main() -> cacache::Result<()> { +/// let data: Vec = cacache::read_no_integrity("./my-cache", "my-key").await?; +/// Ok(()) +/// } +/// ``` +/// +/// If you have no integrity this function is for you. +#[doc(hidden)] +#[cfg(any(feature = "async-std", feature = "tokio"))] +pub async fn read_no_integrity(cache: P, key: K) -> Result> +where + P: AsRef, + K: AsRef, +{ + async fn inner(cache: &Path, key: &str) -> Result> { + if let Some(entry) = index::find_async(cache, key).await? { + read_hash_no_integrity(cache, entry.integrity).await.map(|(r, _i)| r) } else { Err(Error::EntryNotFound(cache.to_path_buf(), key.into())) } @@ -178,16 +211,42 @@ where /// #[async_attributes::main] /// async fn main() -> cacache::Result<()> { /// let sri = cacache::write("./my-cache", "my-key", b"hello").await?; -/// let data: Vec = cacache::read_hash("./my-cache", &sri).await?; +/// let (data, _): (Vec, _) = cacache::read_hash("./my-cache", sri).await?; /// Ok(()) /// } /// ``` #[cfg(any(feature = "async-std", feature = "tokio"))] -pub async fn read_hash

(cache: P, sri: &Integrity) -> Result> +pub async fn read_hash

(cache: P, sri: Integrity) -> Result<(Vec, Integrity)> where P: AsRef, { - read::read_async(cache.as_ref(), sri).await + read::read_async(cache.as_ref(), sri, true).await +} + +/// Reads the entire contents of a cache file into a bytes vector, looking the +/// data up by its content address. Skips integrity checking. Use this for large files. +/// +/// ## Example +/// ```no_run +/// use async_std::prelude::*; +/// use async_attributes; +/// +/// #[async_attributes::main] +/// async fn main() -> cacache::Result<()> { +/// let sri = cacache::write("./my-cache", "my-key", b"hello").await?; +/// let (data, _): (Vec, _) = cacache::read_hash_no_integrity("./my-cache", sri).await?; +/// Ok(()) +/// } +/// ``` +/// +/// If you have no integrity this function is for you. +#[doc(hidden)] +#[cfg(any(feature = "async-std", feature = "tokio"))] +pub async fn read_hash_no_integrity

(cache: P, sri: Integrity) -> Result<(Vec, Integrity)> +where + P: AsRef, +{ + read::read_async(cache.as_ref(), sri, false).await } /// Copies cache data to a specified location. Returns the number of bytes @@ -995,7 +1054,7 @@ mod tests { let dir = tmp.path().to_owned(); let sri = crate::write(&dir, "my-key", b"hello world").await.unwrap(); - let data = crate::read_hash(&dir, &sri).await.unwrap(); + let (data, _) = crate::read_hash(&dir, sri).await.unwrap(); assert_eq!(data, b"hello world"); } diff --git a/src/lib.rs b/src/lib.rs index 07f0826..132addd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,7 +66,7 @@ //! let sri = cacache::write("./my-cache", "key", b"hello").await?; //! //! // ...data gets looked up by `sri` ("Subresource Integrity"). -//! let data = cacache::read_hash("./my-cache", &sri).await?; +//! let (data, _) = cacache::read_hash("./my-cache", sri).await?; //! assert_eq!(data, b"hello"); //! //! Ok(()) diff --git a/src/put.rs b/src/put.rs index 5dc7e60..5efc2fc 100644 --- a/src/put.rs +++ b/src/put.rs @@ -652,7 +652,7 @@ mod tests { let integrity = crate::write_hash(&dir, &original) .await .expect("should be able to write a hash asynchronously"); - let bytes = crate::read_hash(&dir, &integrity) + let (bytes, _) = crate::read_hash(&dir, integrity) .await .expect("should be able to read back what we wrote"); let result = diff --git a/src/rm.rs b/src/rm.rs index bc15000..c2d7345 100644 --- a/src/rm.rs +++ b/src/rm.rs @@ -26,7 +26,7 @@ use crate::index; /// cacache::read("./my-cache", "my-key").await?; /// /// // But this succeeds: -/// cacache::read_hash("./my-cache", &sri).await?; +/// cacache::read_hash("./my-cache", sri).await?; /// /// Ok(()) /// } @@ -56,7 +56,7 @@ where /// /// // These fail: /// cacache::read("./my-cache", "my-key").await?; -/// cacache::read_hash("./my-cache", &sri).await?; +/// cacache::read_hash("./my-cache", sri).await?; /// /// // But this succeeds: /// cacache::metadata("./my-cache", "my-key").await?; @@ -86,7 +86,7 @@ pub async fn remove_hash>(cache: P, sri: &Integrity) -> Result<() /// // These all fail: /// cacache::read("./my-cache", "my-key").await?; /// cacache::metadata("./my-cache", "my-key").await?; -/// cacache::read_hash("./my-cache", &sri).await?; +/// cacache::read_hash("./my-cache", sri).await?; /// /// Ok(()) /// }