1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! File / object storage abstraction.
//!
//! `FormMultipartData::parse()` hands back raw bytes with no place to put
//! them. This module gives handlers a single `Storage` trait so the same
//! upload code works against local disk in development and an S3-compatible
//! bucket (AWS S3, Cloudflare R2, MinIO) or Azure Blob Storage in production.
//!
//! # Local disk (requires the `storage-local` feature)
//!
//! ```rust
//! # #[cfg(feature = "storage-local")]
//! # fn example() -> Result<(), rust_web_server::storage::StorageError> {
//! use rust_web_server::storage::{LocalStorage, Storage};
//!
//! let dir = std::env::temp_dir().join("rws-storage-doctest");
//! let store = LocalStorage::new(dir.to_str().unwrap()).with_base_url("/uploads");
//!
//! let key = store.put("avatars/42.png", b"...png bytes...", "image/png")?;
//! assert_eq!("/uploads/avatars/42.png", store.url(&key));
//!
//! let bytes = store.get(&key)?;
//! store.delete(&key)?;
//! # std::fs::remove_dir_all(&dir).ok();
//! # Ok(())
//! # }
//! ```
//!
//! # S3-compatible object storage (requires the `storage-s3` feature)
//!
//! ```rust,no_run
//! # #[cfg(feature = "storage-s3")]
//! # fn example() -> Result<(), rust_web_server::storage::StorageError> {
//! use rust_web_server::storage::{S3Storage, Storage};
//!
//! // Reads RWS_S3_BUCKET, RWS_S3_REGION, RWS_S3_ACCESS_KEY, RWS_S3_SECRET_KEY,
//! // and optionally RWS_S3_ENDPOINT (for R2 / MinIO / any S3-compatible host).
//! let store = S3Storage::from_env()?;
//!
//! store.put("avatars/42.png", b"...png bytes...", "image/png")?;
//! let bytes = store.get("avatars/42.png")?;
//! store.delete("avatars/42.png")?;
//! # Ok(())
//! # }
//! ```
//!
//! # Azure Blob Storage (requires the `storage-azure` feature)
//!
//! ```rust,no_run
//! # #[cfg(feature = "storage-azure")]
//! # fn example() -> Result<(), rust_web_server::storage::StorageError> {
//! use rust_web_server::storage::{AzureBlobStorage, Storage};
//!
//! // Reads RWS_AZURE_ACCOUNT, RWS_AZURE_CONTAINER, and optionally
//! // RWS_AZURE_ACCOUNT_KEY (falls back to Managed Identity when unset) and
//! // RWS_AZURE_ENDPOINT (for Azurite / a private endpoint).
//! let store = AzureBlobStorage::from_env()?;
//!
//! store.put("avatars/42.png", b"...png bytes...", "image/png")?;
//! let bytes = store.get("avatars/42.png")?;
//! store.delete("avatars/42.png")?;
//! # Ok(())
//! # }
//! ```
pub use LocalStorage;
pub use ;
pub use ;
// ── StorageError ─────────────────────────────────────────────────────────────
/// Error returned by all `Storage` operations.
;
// ── Storage ──────────────────────────────────────────────────────────────────
/// Backend-independent object storage.
///
/// Implement this trait to plug a custom backend (GCS, a database-backed
/// store, ...) into the same handler code that already works against
/// [`LocalStorage`], [`S3Storage`], and [`AzureBlobStorage`].