Skip to main content

turbo_cdn/config/
mod.rs

1// Licensed under the MIT License
2// Copyright (c) 2025 Hal <hal.long@outlook.com>
3
4//! # Configuration System
5//!
6//! Type-safe configuration management using TOML.
7
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11/// Main configuration for TurboCdn
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct TurboCdnConfig {
14    /// General settings
15    pub general: GeneralConfig,
16    /// Performance settings
17    pub performance: PerformanceConfig,
18    /// Security settings
19    pub security: SecurityConfig,
20    /// Geographic detection settings
21    pub geo_detection: GeoDetectionConfig,
22    /// Testing configuration
23    pub testing: TestingConfig,
24    /// URL mapping rules
25    pub url_mapping_rules: Vec<UrlMappingRuleConfig>,
26}
27
28/// URL mapping rule configuration
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct UrlMappingRuleConfig {
31    /// Rule name for identification
32    pub name: String,
33    /// Regex pattern to match URLs
34    pub pattern: String,
35    /// Replacement URL templates (in priority order)
36    pub replacements: Vec<String>,
37    /// Applicable regions for this rule
38    pub regions: Vec<Region>,
39    /// Priority (lower = higher priority)
40    pub priority: u32,
41    /// Whether this rule is enabled
42    pub enabled: bool,
43}
44
45/// General configuration
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct GeneralConfig {
48    /// Enable debug mode
49    pub debug: bool,
50    /// Default region
51    pub default_region: Region,
52    /// User agent string
53    pub user_agent: String,
54    /// Enable URL mapping cache
55    pub enable_url_cache: bool,
56    /// URL cache TTL in seconds
57    pub url_cache_ttl: u64,
58    /// Maximum cache entries
59    pub max_cache_entries: usize,
60}
61
62/// Performance configuration
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct PerformanceConfig {
65    /// Maximum concurrent downloads
66    pub max_concurrent_downloads: usize,
67    /// Chunk size for downloads
68    pub chunk_size: u64,
69    /// Connection timeout in seconds
70    pub timeout: u64,
71    /// Maximum retry attempts
72    pub retry_attempts: usize,
73    /// Enable adaptive chunking
74    pub adaptive_chunking: bool,
75    /// HTTP connection pool settings
76    pub pool_max_idle_per_host: usize,
77    /// Pool idle timeout in seconds
78    pub pool_idle_timeout: u64,
79    /// TCP keepalive timeout in seconds
80    pub tcp_keepalive: u64,
81    /// Enable HTTP/2 prior knowledge
82    pub http2_prior_knowledge: bool,
83    /// Minimum chunk size in bytes
84    pub min_chunk_size: u64,
85    /// Maximum chunk size in bytes
86    pub max_chunk_size: u64,
87    /// Speed threshold for adaptive chunking in bytes per second
88    pub speed_threshold_bytes_per_sec: u64,
89    /// Enable adaptive concurrency control
90    pub adaptive_concurrency: Option<bool>,
91    /// Minimum concurrent downloads
92    pub min_concurrent_downloads: Option<u32>,
93    /// Maximum concurrent downloads limit
94    pub max_concurrent_downloads_limit: Option<u32>,
95    /// Network congestion threshold (0.0 to 1.0)
96    pub network_congestion_threshold: Option<f64>,
97    /// Enable DNS caching
98    pub dns_cache_enabled: Option<bool>,
99    /// DNS cache TTL in seconds
100    pub dns_cache_ttl_seconds: Option<u64>,
101    /// Maximum DNS cache entries
102    pub dns_cache_max_entries: Option<usize>,
103    /// Enable smart chunking
104    pub smart_chunking_enabled: Option<bool>,
105    /// Chunk performance history size
106    pub chunk_performance_history_size: Option<usize>,
107}
108
109/// Security configuration
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct SecurityConfig {
112    /// Verify SSL certificates
113    pub verify_ssl: bool,
114    /// Allowed protocols
115    pub allowed_protocols: Vec<String>,
116}
117
118/// Geographic detection configuration
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct GeoDetectionConfig {
121    /// IP detection APIs
122    pub ip_apis: Vec<String>,
123    /// IP detection timeout in seconds
124    pub ip_detection_timeout: u64,
125    /// Enable automatic region detection
126    pub auto_detect_region: bool,
127}
128
129/// Testing configuration
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct TestingConfig {
132    /// Test URLs for connectivity testing
133    pub test_urls: Vec<String>,
134    /// Speed test file sizes
135    pub speed_test_sizes: Vec<u64>,
136}
137
138#[allow(clippy::derivable_impls)]
139impl Default for TurboCdnConfig {
140    fn default() -> Self {
141        Self {
142            general: GeneralConfig::default(),
143            performance: PerformanceConfig::default(),
144            security: SecurityConfig::default(),
145            geo_detection: GeoDetectionConfig::default(),
146            testing: TestingConfig::default(),
147            url_mapping_rules: Vec::new(), // Will be loaded from config file
148        }
149    }
150}
151
152impl Default for GeneralConfig {
153    fn default() -> Self {
154        Self {
155            debug: false,
156            default_region: Region::Global,
157            user_agent: format!("turbo-cdn/{}", env!("CARGO_PKG_VERSION")),
158            enable_url_cache: true,
159            url_cache_ttl: 3600, // 1 hour
160            max_cache_entries: 1000,
161        }
162    }
163}
164
165impl Default for PerformanceConfig {
166    fn default() -> Self {
167        Self {
168            max_concurrent_downloads: 32, // 增加并发数以实现turbo速度
169            chunk_size: 1024 * 1024,      // 1MB chunks for better concurrency
170            timeout: 30,
171            retry_attempts: 3,
172            adaptive_chunking: true,
173            pool_max_idle_per_host: 50, // 增加连接池大小
174            pool_idle_timeout: 90,
175            tcp_keepalive: 60,
176            http2_prior_knowledge: true,
177            min_chunk_size: 128 * 1024, // 128KB for more granular chunks
178            max_chunk_size: 5 * 1024 * 1024, // 5MB
179            speed_threshold_bytes_per_sec: 1024 * 1024, // 1MB/s
180            adaptive_concurrency: Some(true),
181            min_concurrent_downloads: Some(8), // 更高的最小并发数
182            max_concurrent_downloads_limit: Some(64), // 更高的最大并发数
183            network_congestion_threshold: Some(0.3), // 更激进的阈值
184            dns_cache_enabled: Some(true),
185            dns_cache_ttl_seconds: Some(300),
186            dns_cache_max_entries: Some(1000),
187            smart_chunking_enabled: Some(true),
188            chunk_performance_history_size: Some(100),
189        }
190    }
191}
192
193impl Default for SecurityConfig {
194    fn default() -> Self {
195        Self {
196            verify_ssl: true,
197            allowed_protocols: vec!["https".to_string(), "http".to_string()],
198        }
199    }
200}
201
202impl Default for GeoDetectionConfig {
203    fn default() -> Self {
204        Self {
205            ip_apis: vec![
206                "https://ipapi.co/json/".to_string(),
207                "https://ip-api.com/json/".to_string(),
208                "https://ipinfo.io/json".to_string(),
209                "https://api.ipify.org?format=json".to_string(),
210            ],
211            ip_detection_timeout: 5,
212            auto_detect_region: true,
213        }
214    }
215}
216
217impl Default for TestingConfig {
218    fn default() -> Self {
219        Self {
220            test_urls: vec![
221                "https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-pc-windows-msvc.zip".to_string(),
222                "https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js".to_string(),
223            ],
224            speed_test_sizes: vec![1048576, 10485760, 104857600], // 1MB, 10MB, 100MB
225        }
226    }
227}
228
229impl TurboCdnConfig {
230    /// Load configuration from embedded default TOML.
231    pub fn load() -> Result<Self, toml::de::Error> {
232        let config_content = include_str!("default.toml");
233        toml::from_str(config_content)
234    }
235
236    /// Load configuration from a custom TOML file, falling back to defaults.
237    pub fn load_from_file<P: Into<PathBuf>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
238        let path = path.into();
239        if path.exists() {
240            let file_content = std::fs::read_to_string(&path)?;
241            Ok(toml::from_str(&file_content)?)
242        } else {
243            let config_content = include_str!("default.toml");
244            Ok(toml::from_str(config_content)?)
245        }
246    }
247}
248
249/// Region enum for compatibility
250#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
251pub enum Region {
252    China,
253    Asia,
254    #[default]
255    Global,
256    AsiaPacific,
257    Europe,
258    NorthAmerica,
259    Custom(String),
260}
261
262impl std::fmt::Display for Region {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        match self {
265            Region::China => write!(f, "China"),
266            Region::Asia => write!(f, "Asia"),
267            Region::Global => write!(f, "Global"),
268            Region::AsiaPacific => write!(f, "AsiaPacific"),
269            Region::Europe => write!(f, "Europe"),
270            Region::NorthAmerica => write!(f, "NorthAmerica"),
271            Region::Custom(name) => write!(f, "{name}"),
272        }
273    }
274}
275
276impl std::str::FromStr for Region {
277    type Err = String;
278
279    fn from_str(s: &str) -> Result<Self, Self::Err> {
280        match s {
281            "China" => Ok(Region::China),
282            "Asia" => Ok(Region::Asia),
283            "Global" => Ok(Region::Global),
284            "AsiaPacific" => Ok(Region::AsiaPacific),
285            "Europe" => Ok(Region::Europe),
286            "NorthAmerica" => Ok(Region::NorthAmerica),
287            other => Ok(Region::Custom(other.to_string())),
288        }
289    }
290}