use s3::Bucket;
use crate::PmtError::ResponseBodyTooLong;
use crate::{
AsyncBackend, AsyncPmTilesReader, BackendResponse, DirectoryCache, NoCache, PmtResult,
};
impl AsyncPmTilesReader<S3Backend, NoCache> {
pub async fn new_with_bucket_path(bucket: Bucket, path: String) -> PmtResult<Self> {
Self::new_with_cached_bucket_path(NoCache, bucket, path).await
}
}
impl<C: DirectoryCache + Sync + Send> AsyncPmTilesReader<S3Backend, C> {
pub async fn new_with_cached_bucket_path(
cache: C,
bucket: Bucket,
path: String,
) -> PmtResult<Self> {
let backend = S3Backend::from(bucket, path);
Self::try_from_cached_source(backend, cache).await
}
}
pub struct S3Backend {
bucket: Bucket,
path: String,
}
impl S3Backend {
#[must_use]
pub fn from(bucket: Bucket, path: String) -> S3Backend {
Self { bucket, path }
}
}
impl AsyncBackend for S3Backend {
async fn read(&self, offset: usize, length: usize) -> PmtResult<BackendResponse> {
let response = self
.bucket
.get_object_range(
self.path.as_str(),
offset as _,
Some((offset + length - 1) as _),
)
.await?;
let response_bytes = response.bytes();
if response_bytes.len() > length {
Err(ResponseBodyTooLong(response_bytes.len(), length))
} else {
let headers = response.headers();
let data_version = headers
.get("etag")
.or_else(|| headers.get("last-modified"))
.cloned();
Ok(match data_version {
Some(v) => BackendResponse::new_with_version(response_bytes.clone(), v),
None => BackendResponse::new(response_bytes.clone()),
})
}
}
}