1use serde::{Deserialize, Serialize};
14use std::time::Duration;
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22pub struct SimpleTranslationConfig {
23 pub enabled: bool,
25 pub target_lang: String,
27 pub source_lang: String,
29 pub api_url: String,
31 pub requests_per_second: f64,
33 pub max_text_length: usize,
35 pub cache_enabled: bool,
37 pub cache_ttl_seconds: u64,
39}
40
41impl Default for SimpleTranslationConfig {
42 fn default() -> Self {
43 Self {
44 enabled: true,
45 target_lang: "zh".to_string(),
46 source_lang: "auto".to_string(),
47 api_url: "http://localhost:1188/translate".to_string(),
48 requests_per_second: 1.0,
49 max_text_length: 3000,
50 cache_enabled: true,
51 cache_ttl_seconds: 3600,
52 }
53 }
54}
55
56impl SimpleTranslationConfig {
57 pub fn builder() -> ConfigBuilder {
59 ConfigBuilder::new()
60 }
61
62 pub fn from_env() -> Self {
64 let mut config = Self::default();
65
66 if let Ok(enabled) = std::env::var("TRANSLATION_ENABLED") {
67 config.enabled = enabled.parse().unwrap_or(true);
68 }
69
70 if let Ok(target_lang) = std::env::var("TRANSLATION_TARGET_LANG") {
71 config.target_lang = target_lang;
72 }
73
74 if let Ok(source_lang) = std::env::var("TRANSLATION_SOURCE_LANG") {
75 config.source_lang = source_lang;
76 }
77
78 if let Ok(api_url) = std::env::var("TRANSLATION_API_URL") {
79 config.api_url = api_url;
80 }
81
82 if let Ok(rate) = std::env::var("TRANSLATION_REQUESTS_PER_SECOND") {
83 config.requests_per_second = rate.parse().unwrap_or(1.0);
84 }
85
86 if let Ok(max_len) = std::env::var("TRANSLATION_MAX_TEXT_LENGTH") {
87 config.max_text_length = max_len.parse().unwrap_or(3000);
88 }
89
90 if let Ok(cache_enabled) = std::env::var("TRANSLATION_CACHE_ENABLED") {
91 config.cache_enabled = cache_enabled.parse().unwrap_or(true);
92 }
93
94 if let Ok(cache_ttl) = std::env::var("TRANSLATION_CACHE_TTL_SECONDS") {
95 config.cache_ttl_seconds = cache_ttl.parse().unwrap_or(3600);
96 }
97
98 config
99 }
100
101 pub fn quick(target_lang: &str, api_url: Option<&str>) -> Self {
103 Self {
104 target_lang: target_lang.to_string(),
105 api_url: api_url.unwrap_or("http://localhost:1188/translate").to_string(),
106 ..Default::default()
107 }
108 }
109
110 pub fn validate(&self) -> Result<(), String> {
112 if self.target_lang.is_empty() {
113 return Err("Target language cannot be empty".to_string());
114 }
115
116 if self.api_url.is_empty() {
117 return Err("API URL cannot be empty".to_string());
118 }
119
120 if self.requests_per_second <= 0.0 {
121 return Err("Requests per second must be positive".to_string());
122 }
123
124 if self.max_text_length == 0 {
125 return Err("Max text length must be positive".to_string());
126 }
127
128 Ok(())
129 }
130
131 pub fn request_interval(&self) -> Duration {
133 Duration::from_secs_f64(1.0 / self.requests_per_second)
134 }
135
136 pub fn cache_ttl(&self) -> Duration {
138 Duration::from_secs(self.cache_ttl_seconds)
139 }
140}
141
142#[derive(Debug)]
148pub struct ConfigBuilder {
149 config: SimpleTranslationConfig,
150}
151
152impl ConfigBuilder {
153 pub fn new() -> Self {
154 Self {
155 config: SimpleTranslationConfig::default(),
156 }
157 }
158
159 pub fn enabled(mut self, enabled: bool) -> Self {
161 self.config.enabled = enabled;
162 self
163 }
164
165 pub fn target_lang<S: Into<String>>(mut self, lang: S) -> Self {
167 self.config.target_lang = lang.into();
168 self
169 }
170
171 pub fn source_lang<S: Into<String>>(mut self, lang: S) -> Self {
173 self.config.source_lang = lang.into();
174 self
175 }
176
177 pub fn api_url<S: Into<String>>(mut self, url: S) -> Self {
179 self.config.api_url = url.into();
180 self
181 }
182
183 pub fn requests_per_second(mut self, rate: f64) -> Self {
185 self.config.requests_per_second = rate;
186 self
187 }
188
189 pub fn max_text_length(mut self, length: usize) -> Self {
191 self.config.max_text_length = length;
192 self
193 }
194
195 pub fn cache_enabled(mut self, enabled: bool) -> Self {
197 self.config.cache_enabled = enabled;
198 self
199 }
200
201 pub fn cache_ttl_seconds(mut self, seconds: u64) -> Self {
203 self.config.cache_ttl_seconds = seconds;
204 self
205 }
206
207 pub fn build(self) -> Result<SimpleTranslationConfig, String> {
209 self.config.validate()?;
210 Ok(self.config)
211 }
212
213 pub fn build_unchecked(self) -> SimpleTranslationConfig {
215 self.config
216 }
217}
218
219impl Default for ConfigBuilder {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225pub struct SimpleConfigManager {
231 config: SimpleTranslationConfig,
232}
233
234impl SimpleConfigManager {
235 pub fn new() -> Self {
237 Self {
238 config: SimpleTranslationConfig::default(),
239 }
240 }
241
242 pub fn with_config(config: SimpleTranslationConfig) -> Self {
244 Self { config }
245 }
246
247 pub fn from_env() -> Self {
249 Self {
250 config: SimpleTranslationConfig::from_env(),
251 }
252 }
253
254 pub fn config(&self) -> &SimpleTranslationConfig {
256 &self.config
257 }
258
259 pub fn config_cloned(&self) -> SimpleTranslationConfig {
261 self.config.clone()
262 }
263
264 pub fn update_config(&mut self, config: SimpleTranslationConfig) {
266 self.config = config;
267 }
268
269 pub fn update_with_builder<F>(&mut self, f: F) -> Result<(), String>
271 where
272 F: FnOnce(ConfigBuilder) -> ConfigBuilder,
273 {
274 let builder = ConfigBuilder {
275 config: self.config.clone(),
276 };
277 let new_config = f(builder).build()?;
278 self.config = new_config;
279 Ok(())
280 }
281
282 pub fn validate(&self) -> Result<(), String> {
284 self.config.validate()
285 }
286}
287
288impl Default for SimpleConfigManager {
289 fn default() -> Self {
290 Self::new()
291 }
292}
293
294pub fn quick_config(target_lang: &str, api_url: Option<&str>) -> SimpleTranslationConfig {
300 SimpleTranslationConfig::quick(target_lang, api_url)
301}
302
303pub fn config_builder() -> ConfigBuilder {
305 ConfigBuilder::new()
306}
307
308pub fn load_config_from_env() -> SimpleTranslationConfig {
310 SimpleTranslationConfig::from_env()
311}
312
313pub fn validate_config(config: &SimpleTranslationConfig) -> Result<(), String> {
315 config.validate()
316}
317
318pub mod presets {
324 use super::*;
325
326 pub fn development() -> SimpleTranslationConfig {
328 SimpleTranslationConfig {
329 enabled: true,
330 target_lang: "zh".to_string(),
331 source_lang: "auto".to_string(),
332 api_url: "http://localhost:1188/translate".to_string(),
333 requests_per_second: 2.0,
334 max_text_length: 1000,
335 cache_enabled: true,
336 cache_ttl_seconds: 1800, }
338 }
339
340 pub fn production() -> SimpleTranslationConfig {
342 SimpleTranslationConfig {
343 enabled: true,
344 target_lang: "zh".to_string(),
345 source_lang: "auto".to_string(),
346 api_url: "http://localhost:1188/translate".to_string(),
347 requests_per_second: 1.0,
348 max_text_length: 3000,
349 cache_enabled: true,
350 cache_ttl_seconds: 3600, }
352 }
353
354 pub fn testing() -> SimpleTranslationConfig {
356 SimpleTranslationConfig {
357 enabled: false, target_lang: "zh".to_string(),
359 source_lang: "auto".to_string(),
360 api_url: "http://localhost:1188/translate".to_string(),
361 requests_per_second: 10.0, max_text_length: 500,
363 cache_enabled: false, cache_ttl_seconds: 300, }
366 }
367
368 pub fn high_performance() -> SimpleTranslationConfig {
370 SimpleTranslationConfig {
371 enabled: true,
372 target_lang: "zh".to_string(),
373 source_lang: "auto".to_string(),
374 api_url: "http://localhost:1188/translate".to_string(),
375 requests_per_second: 5.0,
376 max_text_length: 5000,
377 cache_enabled: true,
378 cache_ttl_seconds: 7200, }
380 }
381}
382
383#[cfg(test)]
388mod tests {
389 use super::*;
390
391 #[test]
392 fn test_default_config() {
393 let config = SimpleTranslationConfig::default();
394 assert!(config.enabled);
395 assert_eq!(config.target_lang, "zh");
396 assert_eq!(config.source_lang, "auto");
397 assert!(config.validate().is_ok());
398 }
399
400 #[test]
401 fn test_config_builder() {
402 let config = ConfigBuilder::new()
403 .target_lang("en")
404 .api_url("http://example.com/translate")
405 .requests_per_second(2.0)
406 .build()
407 .unwrap();
408
409 assert_eq!(config.target_lang, "en");
410 assert_eq!(config.api_url, "http://example.com/translate");
411 assert_eq!(config.requests_per_second, 2.0);
412 }
413
414 #[test]
415 fn test_quick_config() {
416 let config = SimpleTranslationConfig::quick("ja", Some("http://api.example.com"));
417 assert_eq!(config.target_lang, "ja");
418 assert_eq!(config.api_url, "http://api.example.com");
419 }
420
421 #[test]
422 fn test_config_validation() {
423 let mut config = SimpleTranslationConfig::default();
424 assert!(config.validate().is_ok());
425
426 config.target_lang = "".to_string();
427 assert!(config.validate().is_err());
428
429 config.target_lang = "zh".to_string();
430 config.requests_per_second = -1.0;
431 assert!(config.validate().is_err());
432 }
433
434 #[test]
435 fn test_config_manager() {
436 let mut manager = SimpleConfigManager::new();
437 assert!(manager.validate().is_ok());
438
439 let result = manager.update_with_builder(|builder| {
440 builder.target_lang("ko").requests_per_second(3.0)
441 });
442 assert!(result.is_ok());
443 assert_eq!(manager.config().target_lang, "ko");
444 assert_eq!(manager.config().requests_per_second, 3.0);
445 }
446
447 #[test]
448 fn test_presets() {
449 let dev_config = presets::development();
450 assert!(dev_config.enabled);
451 assert_eq!(dev_config.requests_per_second, 2.0);
452
453 let prod_config = presets::production();
454 assert_eq!(prod_config.max_text_length, 3000);
455
456 let test_config = presets::testing();
457 assert!(!test_config.enabled);
458 assert!(!test_config.cache_enabled);
459 }
460
461 #[test]
462 fn test_convenience_functions() {
463 let config = quick_config("fr", Some("http://api.example.com"));
464 assert_eq!(config.target_lang, "fr");
465
466 let builder = config_builder().target_lang("de");
467 let config = builder.build().unwrap();
468 assert_eq!(config.target_lang, "de");
469 }
470
471 #[test]
472 fn test_duration_helpers() {
473 let config = SimpleTranslationConfig::default();
474 let interval = config.request_interval();
475 assert_eq!(interval, Duration::from_secs(1));
476
477 let ttl = config.cache_ttl();
478 assert_eq!(ttl, Duration::from_secs(3600));
479 }
480}