diff --git a/Cargo.toml b/Cargo.toml index 3b80981..0005834 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ num_enum = "0.7.3" # Match the version used by pyo3-object-store # We'll upgrade to object_store 0.12 ASAP when it comes out object_store = { git = "https://github.com/apache/arrow-rs", rev = "7a15e4b47ca97df2edef689c9f2ebd2f3888b79e" } +reqwest = "0.12" thiserror = "1" tokio = { version = "1.43.0", optional = true } weezl = "0.1.0" diff --git a/src/error.rs b/src/error.rs index ff7542d..47e80c5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,6 +30,10 @@ pub enum AsyncTiffError { /// An error during TIFF tag parsing. #[error(transparent)] InternalTIFFError(#[from] crate::tiff::TiffError), + + /// Reqwest error + #[error(transparent)] + ReqwestError(#[from] reqwest::Error), } /// Crate-specific result type. diff --git a/src/reader.rs b/src/reader.rs index c93f1a8..433e3d8 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -133,6 +133,35 @@ impl AsyncFileReader for ObjectReader { } } +/// An AsyncFileReader that reads from a URL using reqwest. +#[derive(Debug, Clone)] +pub struct ReqwestReader { + client: reqwest::Client, + url: reqwest::Url, +} + +impl ReqwestReader { + /// Construct a new ReqwestReader from a reqwest client and URL. + pub fn new(client: reqwest::Client, url: reqwest::Url) -> Self { + Self { client, url } + } +} + +impl AsyncFileReader for ReqwestReader { + fn get_bytes(&self, range: Range) -> BoxFuture<'_, AsyncTiffResult> { + let url = self.url.clone(); + let client = self.client.clone(); + // HTTP range is inclusive, so we need to subtract 1 from the end + let range = format!("bytes={}-{}", range.start, range.end - 1); + async move { + let response = client.get(url).header("Range", range).send().await?; + let bytes = response.bytes().await?; + Ok(bytes) + } + .boxed() + } +} + /// An AsyncFileReader that caches the first `prefetch` bytes of a file. #[derive(Debug)] pub struct PrefetchReader {