Skip to main content

zlayer_storage/
config.rs

1//! Configuration types for layer storage
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6/// Configuration for S3-backed layer storage
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct LayerStorageConfig {
9    /// S3 bucket name for storing layers
10    pub bucket: String,
11
12    /// S3 key prefix for layer objects (e.g., "layers/")
13    #[serde(default = "default_prefix")]
14    pub prefix: String,
15
16    /// AWS region (if not using environment/profile defaults)
17    pub region: Option<String>,
18
19    /// Custom S3 endpoint URL (for S3-compatible storage like MinIO)
20    pub endpoint_url: Option<String>,
21
22    /// Local directory for staging tarballs before upload
23    pub staging_dir: PathBuf,
24
25    /// Local database path for sync state persistence
26    pub state_db_path: PathBuf,
27
28    /// Multipart upload part size in bytes (default: 64MB)
29    #[serde(default = "default_part_size")]
30    pub part_size_bytes: u64,
31
32    /// Maximum concurrent part uploads
33    #[serde(default = "default_concurrent_uploads")]
34    pub max_concurrent_uploads: usize,
35
36    /// Compression level for zstd (1-22, default: 3)
37    #[serde(default = "default_compression_level")]
38    pub compression_level: i32,
39
40    /// Sync interval in seconds (how often to check for changes)
41    #[serde(default = "default_sync_interval")]
42    pub sync_interval_secs: u64,
43}
44
45fn default_prefix() -> String {
46    "layers/".to_string()
47}
48
49fn default_part_size() -> u64 {
50    64 * 1024 * 1024 // 64MB
51}
52
53fn default_concurrent_uploads() -> usize {
54    4
55}
56
57fn default_compression_level() -> i32 {
58    3
59}
60
61fn default_sync_interval() -> u64 {
62    30
63}
64
65impl Default for LayerStorageConfig {
66    fn default() -> Self {
67        Self {
68            bucket: String::new(),
69            prefix: default_prefix(),
70            region: None,
71            endpoint_url: None,
72            staging_dir: PathBuf::from("/tmp/zlayer-storage/staging"),
73            state_db_path: PathBuf::from("/var/lib/zlayer/layer-state.redb"),
74            part_size_bytes: default_part_size(),
75            max_concurrent_uploads: default_concurrent_uploads(),
76            compression_level: default_compression_level(),
77            sync_interval_secs: default_sync_interval(),
78        }
79    }
80}
81
82impl LayerStorageConfig {
83    /// Create a new config with the required bucket name
84    pub fn new(bucket: impl Into<String>) -> Self {
85        Self {
86            bucket: bucket.into(),
87            ..Default::default()
88        }
89    }
90
91    /// Set the S3 key prefix
92    pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
93        self.prefix = prefix.into();
94        self
95    }
96
97    /// Set the AWS region
98    pub fn with_region(mut self, region: impl Into<String>) -> Self {
99        self.region = Some(region.into());
100        self
101    }
102
103    /// Set a custom S3 endpoint URL
104    pub fn with_endpoint_url(mut self, url: impl Into<String>) -> Self {
105        self.endpoint_url = Some(url.into());
106        self
107    }
108
109    /// Set the staging directory
110    pub fn with_staging_dir(mut self, path: impl Into<PathBuf>) -> Self {
111        self.staging_dir = path.into();
112        self
113    }
114
115    /// Set the state database path
116    pub fn with_state_db_path(mut self, path: impl Into<PathBuf>) -> Self {
117        self.state_db_path = path.into();
118        self
119    }
120
121    /// Build the S3 object key for a given layer digest
122    pub fn object_key(&self, digest: &str) -> String {
123        format!("{}{}.tar.zst", self.prefix, digest)
124    }
125
126    /// Build the S3 object key for layer metadata
127    pub fn metadata_key(&self, digest: &str) -> String {
128        format!("{}{}.meta.json", self.prefix, digest)
129    }
130}