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: zlayer_paths::ZLayerDirs::system_default()
94 .data_dir()
95 .join("sqlite-replicator/cache"),
96 max_cache_size: default_max_cache_size(),
97 auto_restore: default_auto_restore(),
98 snapshot_interval_secs: default_snapshot_interval(),
99 }
100 }
101}
102
103impl SqliteReplicatorConfig {
104 pub fn new(
106 db_path: impl Into<PathBuf>,
107 s3_bucket: impl Into<String>,
108 s3_prefix: impl Into<String>,
109 ) -> Self {
110 Self {
111 db_path: db_path.into(),
112 s3_bucket: s3_bucket.into(),
113 s3_prefix: s3_prefix.into(),
114 ..Default::default()
115 }
116 }
117
118 #[must_use]
120 pub fn with_cache_dir(mut self, cache_dir: impl Into<PathBuf>) -> Self {
121 self.cache_dir = cache_dir.into();
122 self
123 }
124
125 #[must_use]
127 pub fn with_max_cache_size(mut self, size: u64) -> Self {
128 self.max_cache_size = size;
129 self
130 }
131
132 #[must_use]
134 pub fn with_auto_restore(mut self, auto_restore: bool) -> Self {
135 self.auto_restore = auto_restore;
136 self
137 }
138
139 #[must_use]
141 pub fn with_snapshot_interval(mut self, interval_secs: u64) -> Self {
142 self.snapshot_interval_secs = interval_secs;
143 self
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct LayerStorageConfig {
154 pub bucket: String,
156
157 #[serde(default = "default_prefix")]
159 pub prefix: String,
160
161 pub region: Option<String>,
163
164 pub endpoint_url: Option<String>,
166
167 pub staging_dir: PathBuf,
169
170 pub state_db_path: PathBuf,
172
173 #[serde(default = "default_part_size")]
175 pub part_size_bytes: u64,
176
177 #[serde(default = "default_concurrent_uploads")]
179 pub max_concurrent_uploads: usize,
180
181 #[serde(default = "default_compression_level")]
183 pub compression_level: i32,
184
185 #[serde(default = "default_sync_interval")]
187 pub sync_interval_secs: u64,
188}
189
190fn default_prefix() -> String {
191 "layers/".to_string()
192}
193
194fn default_part_size() -> u64 {
195 64 * 1024 * 1024 }
197
198fn default_concurrent_uploads() -> usize {
199 4
200}
201
202fn default_compression_level() -> i32 {
203 3
204}
205
206fn default_sync_interval() -> u64 {
207 30
208}
209
210impl Default for LayerStorageConfig {
211 fn default() -> Self {
212 Self {
213 bucket: String::new(),
214 prefix: default_prefix(),
215 region: None,
216 endpoint_url: None,
217 staging_dir: zlayer_paths::ZLayerDirs::system_default()
218 .data_dir()
219 .join("layer-staging"),
220 state_db_path: zlayer_paths::ZLayerDirs::system_default()
221 .data_dir()
222 .join("layer-state.sqlite"),
223 part_size_bytes: default_part_size(),
224 max_concurrent_uploads: default_concurrent_uploads(),
225 compression_level: default_compression_level(),
226 sync_interval_secs: default_sync_interval(),
227 }
228 }
229}
230
231impl LayerStorageConfig {
232 pub fn new(bucket: impl Into<String>) -> Self {
234 Self {
235 bucket: bucket.into(),
236 ..Default::default()
237 }
238 }
239
240 #[must_use]
242 pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
243 self.prefix = prefix.into();
244 self
245 }
246
247 #[must_use]
249 pub fn with_region(mut self, region: impl Into<String>) -> Self {
250 self.region = Some(region.into());
251 self
252 }
253
254 #[must_use]
256 pub fn with_endpoint_url(mut self, url: impl Into<String>) -> Self {
257 self.endpoint_url = Some(url.into());
258 self
259 }
260
261 #[must_use]
263 pub fn with_staging_dir(mut self, path: impl Into<PathBuf>) -> Self {
264 self.staging_dir = path.into();
265 self
266 }
267
268 #[must_use]
270 pub fn with_state_db_path(mut self, path: impl Into<PathBuf>) -> Self {
271 self.state_db_path = path.into();
272 self
273 }
274
275 #[must_use]
277 pub fn object_key(&self, digest: &str) -> String {
278 format!("{}{}.tar.zst", self.prefix, digest)
279 }
280
281 #[must_use]
283 pub fn metadata_key(&self, digest: &str) -> String {
284 format!("{}{}.meta.json", self.prefix, digest)
285 }
286}