llm_cost_ops/compression/
config.rs1use super::{CompressionAlgorithm, CompressionLevel};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CompressionConfig {
9 pub enabled: bool,
11
12 pub level: CompressionLevel,
14
15 pub algorithms: Vec<CompressionAlgorithm>,
17
18 pub min_size: usize,
20
21 pub max_size: Option<usize>,
23
24 pub mime_types: Vec<String>,
26
27 pub compress_requests: bool,
29
30 pub compress_responses: bool,
32
33 pub buffer_size: usize,
35}
36
37impl Default for CompressionConfig {
38 fn default() -> Self {
39 Self {
40 enabled: true,
41 level: CompressionLevel::Default,
42 algorithms: vec![
43 CompressionAlgorithm::Brotli,
44 CompressionAlgorithm::Gzip,
45 CompressionAlgorithm::Deflate,
46 ],
47 min_size: 1024, max_size: Some(10 * 1024 * 1024), mime_types: vec![
50 "text/*".to_string(),
51 "application/json".to_string(),
52 "application/xml".to_string(),
53 "application/javascript".to_string(),
54 "application/x-www-form-urlencoded".to_string(),
55 ],
56 compress_requests: false,
57 compress_responses: true,
58 buffer_size: 8192, }
60 }
61}
62
63impl CompressionConfig {
64 pub fn production() -> Self {
66 Self {
67 enabled: true,
68 level: CompressionLevel::Default,
69 algorithms: vec![
70 CompressionAlgorithm::Brotli,
71 CompressionAlgorithm::Gzip,
72 ],
73 min_size: 1024, max_size: Some(50 * 1024 * 1024), mime_types: vec![
76 "text/*".to_string(),
77 "application/json".to_string(),
78 "application/xml".to_string(),
79 "application/javascript".to_string(),
80 ],
81 compress_requests: false,
82 compress_responses: true,
83 buffer_size: 16384, }
85 }
86
87 pub fn development() -> Self {
89 Self {
90 enabled: true,
91 level: CompressionLevel::Fastest,
92 algorithms: vec![CompressionAlgorithm::Gzip],
93 min_size: 512, max_size: Some(5 * 1024 * 1024), mime_types: vec!["text/*".to_string(), "application/json".to_string()],
96 compress_requests: false,
97 compress_responses: true,
98 buffer_size: 4096, }
100 }
101
102 pub fn disabled() -> Self {
104 Self {
105 enabled: false,
106 ..Default::default()
107 }
108 }
109
110 pub fn high_compression() -> Self {
112 Self {
113 enabled: true,
114 level: CompressionLevel::Best,
115 algorithms: vec![CompressionAlgorithm::Brotli],
116 min_size: 256, max_size: None, mime_types: vec![
119 "text/*".to_string(),
120 "application/json".to_string(),
121 "application/xml".to_string(),
122 "application/javascript".to_string(),
123 "application/octet-stream".to_string(),
124 ],
125 compress_requests: true,
126 compress_responses: true,
127 buffer_size: 32768, }
129 }
130
131 pub fn validate(&self) -> Result<(), String> {
133 if self.algorithms.is_empty() {
134 return Err("At least one compression algorithm must be specified".to_string());
135 }
136
137 if self.min_size == 0 {
138 return Err("Minimum size must be greater than 0".to_string());
139 }
140
141 if let Some(max_size) = self.max_size {
142 if max_size < self.min_size {
143 return Err("Maximum size must be greater than minimum size".to_string());
144 }
145 }
146
147 if self.buffer_size == 0 {
148 return Err("Buffer size must be greater than 0".to_string());
149 }
150
151 Ok(())
152 }
153
154 pub fn should_compress_mime_type(&self, content_type: &str) -> bool {
156 if !self.enabled {
157 return false;
158 }
159
160 for pattern in &self.mime_types {
161 if pattern.ends_with("/*") {
162 let prefix = pattern.trim_end_matches("/*");
163 if content_type.starts_with(prefix) {
164 return true;
165 }
166 } else if content_type.contains(pattern) {
167 return true;
168 }
169 }
170
171 false
172 }
173
174 pub fn should_compress_size(&self, size: usize) -> bool {
176 if !self.enabled {
177 return false;
178 }
179
180 if size < self.min_size {
181 return false;
182 }
183
184 if let Some(max_size) = self.max_size {
185 if size > max_size {
186 return false;
187 }
188 }
189
190 true
191 }
192
193 pub fn select_algorithm(&self, accept_encoding: Option<&str>) -> Option<CompressionAlgorithm> {
195 if !self.enabled {
196 return None;
197 }
198
199 let accept_encoding = accept_encoding?;
200
201 super::types::ContentEncoding::select_best(accept_encoding, &self.algorithms)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_default_config() {
211 let config = CompressionConfig::default();
212 assert!(config.enabled);
213 assert_eq!(config.min_size, 1024);
214 assert!(config.validate().is_ok());
215 }
216
217 #[test]
218 fn test_production_config() {
219 let config = CompressionConfig::production();
220 assert!(config.enabled);
221 assert_eq!(config.algorithms.len(), 2);
222 assert!(config.validate().is_ok());
223 }
224
225 #[test]
226 fn test_development_config() {
227 let config = CompressionConfig::development();
228 assert!(config.enabled);
229 assert_eq!(config.level, CompressionLevel::Fastest);
230 assert!(config.validate().is_ok());
231 }
232
233 #[test]
234 fn test_disabled_config() {
235 let config = CompressionConfig::disabled();
236 assert!(!config.enabled);
237 }
238
239 #[test]
240 fn test_high_compression_config() {
241 let config = CompressionConfig::high_compression();
242 assert_eq!(config.level, CompressionLevel::Best);
243 assert!(config.compress_requests);
244 assert!(config.compress_responses);
245 }
246
247 #[test]
248 fn test_should_compress_mime_type() {
249 let config = CompressionConfig::default();
250
251 assert!(config.should_compress_mime_type("text/html"));
252 assert!(config.should_compress_mime_type("text/plain"));
253 assert!(config.should_compress_mime_type("application/json"));
254 assert!(!config.should_compress_mime_type("image/png"));
255 assert!(!config.should_compress_mime_type("video/mp4"));
256 }
257
258 #[test]
259 fn test_should_compress_size() {
260 let config = CompressionConfig::default();
261
262 assert!(!config.should_compress_size(512)); assert!(config.should_compress_size(2048)); assert!(!config.should_compress_size(20 * 1024 * 1024)); }
266
267 #[test]
268 fn test_select_algorithm() {
269 let config = CompressionConfig::default();
270
271 let algo = config.select_algorithm(Some("gzip, deflate, br"));
272 assert_eq!(algo, Some(CompressionAlgorithm::Brotli));
273
274 let algo = config.select_algorithm(Some("gzip"));
275 assert_eq!(algo, Some(CompressionAlgorithm::Gzip));
276
277 let algo = config.select_algorithm(None);
278 assert_eq!(algo, None);
279 }
280
281 #[test]
282 fn test_validate_config() {
283 let mut config = CompressionConfig::default();
284
285 assert!(config.validate().is_ok());
287
288 config.algorithms.clear();
290 assert!(config.validate().is_err());
291
292 config = CompressionConfig::default();
294
295 config.min_size = 0;
297 assert!(config.validate().is_err());
298
299 config = CompressionConfig::default();
301
302 config.max_size = Some(100);
304 config.min_size = 1000;
305 assert!(config.validate().is_err());
306 }
307}