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