systemprompt_traits/
storage.rs1use async_trait::async_trait;
10use std::path::Path;
11
12pub type FileStorageResult<T> = Result<T, FileStorageError>;
13
14#[derive(Debug, thiserror::Error)]
15#[non_exhaustive]
16pub enum FileStorageError {
17 #[error("file not found: {0}")]
18 NotFound(String),
19
20 #[error("validation failed: {0}")]
21 Validation(String),
22
23 #[error("io error: {0}")]
24 Io(#[from] std::io::Error),
25
26 #[error("serialization error: {0}")]
27 Serialization(#[from] serde_json::Error),
28
29 #[error("storage backend error: {0}")]
30 Backend(String),
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct StoredFileId(pub String);
35
36impl StoredFileId {
37 #[must_use]
38 pub fn new(id: impl Into<String>) -> Self {
39 Self(id.into())
40 }
41
42 #[must_use]
43 pub fn as_str(&self) -> &str {
44 &self.0
45 }
46}
47
48impl From<String> for StoredFileId {
49 fn from(s: String) -> Self {
50 Self(s)
51 }
52}
53
54impl From<&str> for StoredFileId {
55 fn from(s: &str) -> Self {
56 Self(s.to_string())
57 }
58}
59
60impl std::fmt::Display for StoredFileId {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 write!(f, "{}", self.0)
63 }
64}
65
66#[derive(Debug, Clone)]
67pub struct StoredFileMetadata {
68 pub id: StoredFileId,
69 pub path: String,
70 pub mime_type: String,
71 pub size_bytes: Option<i64>,
72 pub created_at: chrono::DateTime<chrono::Utc>,
73 pub updated_at: chrono::DateTime<chrono::Utc>,
74}
75
76#[async_trait]
77pub trait FileStorage: Send + Sync {
78 async fn store(&self, path: &Path, content: &[u8]) -> FileStorageResult<StoredFileId>;
79
80 async fn retrieve(&self, id: &StoredFileId) -> FileStorageResult<Vec<u8>>;
81
82 async fn delete(&self, id: &StoredFileId) -> FileStorageResult<()>;
83
84 async fn metadata(&self, id: &StoredFileId) -> FileStorageResult<StoredFileMetadata>;
85
86 async fn exists(&self, id: &StoredFileId) -> FileStorageResult<bool>;
87
88 fn public_url(&self, _id: &StoredFileId) -> Option<String> {
89 None
90 }
91}