Skip to main content

perfgate_server/storage/
artifacts.rs

1//! Artifact storage implementations using object_store.
2
3use super::{ArtifactMeta, ArtifactStore};
4use crate::error::StoreError;
5use async_trait::async_trait;
6use futures::TryStreamExt;
7use object_store::{ObjectStore, path::Path};
8use std::sync::Arc;
9
10/// Artifact storage using a generic ObjectStore (S3, GCS, Azure, Local).
11#[derive(Debug)]
12pub struct ObjectArtifactStore {
13    inner: Arc<dyn ObjectStore>,
14}
15
16impl ObjectArtifactStore {
17    /// Creates a new ObjectArtifactStore from an existing ObjectStore.
18    pub fn new(inner: Arc<dyn ObjectStore>) -> Self {
19        Self { inner }
20    }
21}
22
23#[async_trait]
24impl ArtifactStore for ObjectArtifactStore {
25    async fn put(&self, path: &str, data: Vec<u8>) -> Result<(), StoreError> {
26        let path = Path::from(path);
27        self.inner
28            .put(&path, data.into())
29            .await
30            .map_err(|e| StoreError::Other(format!("ObjectStore put failed: {}", e)))?;
31        Ok(())
32    }
33
34    async fn get(&self, path: &str) -> Result<Vec<u8>, StoreError> {
35        let path = Path::from(path);
36        let result = self
37            .inner
38            .get(&path)
39            .await
40            .map_err(|e| StoreError::Other(format!("ObjectStore get failed: {}", e)))?;
41
42        let bytes = result
43            .bytes()
44            .await
45            .map_err(|e| StoreError::Other(format!("ObjectStore bytes failed: {}", e)))?;
46
47        Ok(bytes.to_vec())
48    }
49
50    async fn delete(&self, path: &str) -> Result<(), StoreError> {
51        let path = Path::from(path);
52        self.inner
53            .delete(&path)
54            .await
55            .map_err(|e| StoreError::Other(format!("ObjectStore delete failed: {}", e)))?;
56        Ok(())
57    }
58
59    async fn list(&self, prefix: Option<&str>) -> Result<Vec<ArtifactMeta>, StoreError> {
60        let prefix = prefix.map(Path::from);
61        let stream = self.inner.list(prefix.as_ref());
62
63        let objects: Vec<_> = stream
64            .try_collect()
65            .await
66            .map_err(|e| StoreError::Other(format!("ObjectStore list failed: {}", e)))?;
67
68        Ok(objects
69            .into_iter()
70            .map(|meta| ArtifactMeta {
71                path: meta.location.to_string(),
72                last_modified: meta.last_modified,
73                size: meta.size as u64,
74            })
75            .collect())
76    }
77}