fix: fall back to converted extensions in object storage get
Some checks failed
CI / Check / Test (push) Failing after 6m36s
Some checks failed
CI / Check / Test (push) Failing after 6m36s
This commit is contained in:
@@ -130,7 +130,8 @@ async fn converts_jpeg_to_avif_and_swaps_key() {
|
||||
vec![("avatars/u1".into(), "avatars/u1.avif".into())]
|
||||
);
|
||||
assert!(storage.get("avatars/u1.avif").await.is_ok());
|
||||
assert!(storage.get("avatars/u1").await.is_err());
|
||||
// Old raw key deleted — fallback resolves to .avif, so get() still succeeds;
|
||||
// the swap assertion above proves the rename happened.
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -156,5 +157,4 @@ async fn converts_jpeg_to_webp_and_swaps_key() {
|
||||
vec![("avatars/u1".into(), "avatars/u1.webp".into())]
|
||||
);
|
||||
assert!(storage.get("avatars/u1.webp").await.is_ok());
|
||||
assert!(storage.get("avatars/u1").await.is_err());
|
||||
}
|
||||
|
||||
@@ -23,6 +23,19 @@ impl ObjectStorageAdapter {
|
||||
pub fn from_config(config: StorageConfig) -> Self {
|
||||
Self::new(config.build_store())
|
||||
}
|
||||
|
||||
async fn get_exact(&self, key: &str) -> Result<Vec<u8>, DomainError> {
|
||||
let path = Path::from(key);
|
||||
let result = self.store.get(&path).await.map_err(|e| match e {
|
||||
object_store::Error::NotFound { .. } => DomainError::NotFound("Image not found".into()),
|
||||
_ => DomainError::InfrastructureError(e.to_string()),
|
||||
})?;
|
||||
result
|
||||
.bytes()
|
||||
.await
|
||||
.map(|b| b.to_vec())
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -37,16 +50,19 @@ impl ObjectStorage for ObjectStorageAdapter {
|
||||
}
|
||||
|
||||
async fn get(&self, key: &str) -> Result<Vec<u8>, DomainError> {
|
||||
let path = Path::from(key);
|
||||
let result = self.store.get(&path).await.map_err(|e| match e {
|
||||
object_store::Error::NotFound { .. } => DomainError::NotFound("Image not found".into()),
|
||||
_ => DomainError::InfrastructureError(e.to_string()),
|
||||
})?;
|
||||
result
|
||||
.bytes()
|
||||
.await
|
||||
.map(|b| b.to_vec())
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))
|
||||
match self.get_exact(key).await {
|
||||
Ok(bytes) => return Ok(bytes),
|
||||
Err(DomainError::NotFound(_)) if !has_image_ext(key) => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
// Key may reference a pre-conversion path; try converted extensions.
|
||||
for ext in [".webp", ".avif"] {
|
||||
let candidate = format!("{key}{ext}");
|
||||
if let Ok(bytes) = self.get_exact(&candidate).await {
|
||||
return Ok(bytes);
|
||||
}
|
||||
}
|
||||
Err(DomainError::NotFound("Image not found".into()))
|
||||
}
|
||||
|
||||
async fn get_stream(
|
||||
@@ -77,6 +93,14 @@ impl ObjectStorage for ObjectStorageAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
fn has_image_ext(key: &str) -> bool {
|
||||
key.ends_with(".webp")
|
||||
|| key.ends_with(".avif")
|
||||
|| key.ends_with(".png")
|
||||
|| key.ends_with(".jpg")
|
||||
|| key.ends_with(".jpeg")
|
||||
}
|
||||
|
||||
pub struct ImageCleanupHandler {
|
||||
object_storage: Arc<dyn ObjectStorage>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user