1use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct SqliteReplicatorConfig {
33 pub db_path: PathBuf,
35
36 pub s3_bucket: String,
38
39 pub s3_prefix: String,
46
47 pub cache_dir: PathBuf,
52
53 #[serde(default = "default_max_cache_size")]
58 pub max_cache_size: u64,
59
60 #[serde(default = "default_auto_restore")]
65 pub auto_restore: bool,
66
67 #[serde(default = "default_snapshot_interval")]
72 pub snapshot_interval_secs: u64,
73}
74
75fn default_max_cache_size() -> u64 {
76 100 * 1024 * 1024 }
78
79fn default_auto_restore() -> bool {
80 true
81}
82
83fn default_snapshot_interval() -> u64 {
84 3600 }
86
87impl Default for SqliteReplicatorConfig {
88 fn default() -> Self {
89 Self {
90 db_path: PathBuf::new(),
91 s3_bucket: String::new(),
92 s3_prefix: "sqlite-replication/".to_string(),
93 cache_dir: PathBuf::from("/tmp/zlayer-replicator/cache"),
94 max_cache_size: default_max_cache_size(),
95 auto_restore: default_auto_restore(),
96 snapshot_interval_secs: default_snapshot_interval(),
97 }
98 }
99}
100
101impl SqliteReplicatorConfig {
102 pub fn new(
104 db_path: impl Into<PathBuf>,
105 s3_bucket: impl Into<String>,
106 s3_prefix: impl Into<String>,
107 ) -> Self {
108 Self {
109 db_path: db_path.into(),
110 s3_bucket: s3_bucket.into(),
111 s3_prefix: s3_prefix.into(),
112 ..Default::default()
113 }
114 }
115
116 #[must_use]
118 pub fn with_cache_dir(mut self, cache_dir: impl Into<PathBuf>) -> Self {
119 self.cache_dir = cache_dir.into();
120 self
121 }
122
123 #[must_use]
125 pub fn with_max_cache_size(mut self, size: u64) -> Self {
126 self.max_cache_size = size;
127 self
128 }
129
130 #[must_use]
132 pub fn with_auto_restore(mut self, auto_restore: bool) -> Self {
133 self.auto_restore = auto_restore;
134 self
135 }
136
137 #[must_use]
139 pub fn with_snapshot_interval(mut self, interval_secs: u64) -> Self {
140 self.snapshot_interval_secs = interval_secs;
141 self
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct LayerStorageConfig {
152 pub bucket: String,
154
155 #[serde(default = "default_prefix")]
157 pub prefix: String,
158
159 pub region: Option<String>,
161
162 pub endpoint_url: Option<String>,
164
165 pub staging_dir: PathBuf,
167
168 pub state_db_path: PathBuf,
170
171 #[serde(default = "default_part_size")]
173 pub part_size_bytes: u64,
174
175 #[serde(default = "default_concurrent_uploads")]
177 pub max_concurrent_uploads: usize,
178
179 #[serde(default = "default_compression_level")]
181 pub compression_level: i32,
182
183 #[serde(default = "default_sync_interval")]
185 pub sync_interval_secs: u64,
186}
187
188fn default_prefix() -> String {
189 "layers/".to_string()
190}
191
192fn default_part_size() -> u64 {
193 64 * 1024 * 1024 }
195
196fn default_concurrent_uploads() -> usize {
197 4
198}
199
200fn default_compression_level() -> i32 {
201 3
202}
203
204fn default_sync_interval() -> u64 {
205 30
206}
207
208impl Default for LayerStorageConfig {
209 fn default() -> Self {
210 Self {
211 bucket: String::new(),
212 prefix: default_prefix(),
213 region: None,
214 endpoint_url: None,
215 staging_dir: PathBuf::from("/tmp/zlayer-storage/staging"),
216 state_db_path: zlayer_paths::ZLayerDirs::system_default()
217 .data_dir()
218 .join("layer-state.sqlite"),
219 part_size_bytes: default_part_size(),
220 max_concurrent_uploads: default_concurrent_uploads(),
221 compression_level: default_compression_level(),
222 sync_interval_secs: default_sync_interval(),
223 }
224 }
225}
226
227impl LayerStorageConfig {
228 pub fn new(bucket: impl Into<String>) -> Self {
230 Self {
231 bucket: bucket.into(),
232 ..Default::default()
233 }
234 }
235
236 #[must_use]
238 pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
239 self.prefix = prefix.into();
240 self
241 }
242
243 #[must_use]
245 pub fn with_region(mut self, region: impl Into<String>) -> Self {
246 self.region = Some(region.into());
247 self
248 }
249
250 #[must_use]
252 pub fn with_endpoint_url(mut self, url: impl Into<String>) -> Self {
253 self.endpoint_url = Some(url.into());
254 self
255 }
256
257 #[must_use]
259 pub fn with_staging_dir(mut self, path: impl Into<PathBuf>) -> Self {
260 self.staging_dir = path.into();
261 self
262 }
263
264 #[must_use]
266 pub fn with_state_db_path(mut self, path: impl Into<PathBuf>) -> Self {
267 self.state_db_path = path.into();
268 self
269 }
270
271 #[must_use]
273 pub fn object_key(&self, digest: &str) -> String {
274 format!("{}{}.tar.zst", self.prefix, digest)
275 }
276
277 #[must_use]
279 pub fn metadata_key(&self, digest: &str) -> String {
280 format!("{}{}.meta.json", self.prefix, digest)
281 }
282}