cloud_disk_sync/config/
mod.rs

1mod migrator;
2mod security;
3mod utils;
4mod validator;
5
6use crate::encryption::types::{EncryptionAlgorithm, IvMode};
7use crate::error::ConfigError;
8use security::SecurityManager;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::error::Error;
12use std::fs;
13use std::fs::create_dir_all;
14use std::path::PathBuf;
15use tracing::info;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub enum ProviderType {
19    AliYunDrive,
20    OneOneFive,
21    Quark,
22    WebDAV,
23    SMB,
24    Local,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct AccountConfig {
29    pub id: String,
30    pub provider: ProviderType,
31    pub name: String,
32    pub credentials: HashMap<String, String>,
33    pub rate_limit: Option<RateLimitConfig>,
34    pub retry_policy: RetryPolicy,
35}
36
37impl AccountConfig {
38    pub fn validate(&self) -> Result<(), Box<dyn Error>> {
39        Ok(())
40    }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct RateLimitConfig {
45    pub requests_per_minute: u32,
46    pub max_concurrent: usize,
47    pub chunk_size: usize,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct RetryPolicy {
52    pub max_retries: u32,
53    pub initial_delay_ms: u64,
54    pub max_delay_ms: u64,
55    pub backoff_factor: f64,
56}
57
58impl Default for RetryPolicy {
59    fn default() -> Self {
60        // todo 默认重试策略缺失
61        RetryPolicy {
62            max_retries: 0,
63            initial_delay_ms: 0,
64            max_delay_ms: 0,
65            backoff_factor: 0.0,
66        }
67    }
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct SyncTask {
72    pub id: String,
73    pub name: String,
74    pub source_account: String,
75    pub source_path: String,
76    pub target_account: String,
77    pub target_path: String,
78    pub schedule: Option<Schedule>,
79    pub filters: Vec<FilterRule>,
80    pub encryption: Option<EncryptionConfig>,
81    pub diff_mode: DiffMode,
82    pub preserve_metadata: bool,
83    pub verify_integrity: bool,
84    /// 同步策略(删除、覆盖、扫描限频等)
85    pub sync_policy: Option<SyncPolicy>,
86}
87
88impl SyncTask {
89    pub fn validate(&self) -> Result<(), Box<dyn Error>> {
90        // todo 需要对同步任务进行校验
91        info!("SyncTask::validate()");
92        todo!()
93    }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
97pub enum Schedule {
98    Cron(String),
99    Interval { seconds: u64 },
100    Manual,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub enum FilterRule {
105    Include(String),
106    Exclude(String),
107    SizeGreaterThan(u64),
108    SizeLessThan(u64),
109    ModifiedAfter(i64),
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct EncryptionConfig {
114    pub algorithm: EncryptionAlgorithm,
115    pub key_id: String,
116    pub iv_mode: IvMode,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub enum DiffMode {
121    Full,
122    Incremental,
123    Smart,
124}
125
126/// 同步策略
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct SyncPolicy {
129    /// 是否删除目标端的孤立文件(仅目标存在)
130    pub delete_orphans: bool,
131    /// 是否覆盖目标端已存在文件
132    pub overwrite_existing: bool,
133    /// 列目录扫描的冷却时间(秒),在冷却期内复用上次快照以降低风控风险
134    pub scan_cooldown_secs: u64,
135}
136
137pub struct ConfigManager {
138    config_path: PathBuf,
139    accounts: HashMap<String, AccountConfig>,
140    tasks: HashMap<String, SyncTask>,
141    security_manager: SecurityManager,
142}
143
144impl ConfigManager {
145    pub fn get_task(&self, task_id: &str) -> Option<SyncTask> {
146        self.tasks.get(task_id).cloned()
147    }
148}
149
150impl ConfigManager {
151    pub fn new() -> Result<Self, ConfigError> {
152        let config_dir = dirs::config_dir()
153            .ok_or(ConfigError::NoConfigDir)?
154            .join("disksync");
155
156        // todo 进行错误处理!
157        create_dir_all(&config_dir).unwrap();
158
159        let config_path = config_dir.join("config.yaml");
160
161        Self::new_with_path(config_path)
162    }
163
164    pub fn new_with_path(config_path: PathBuf) -> Result<Self, ConfigError> {
165        let parent = config_path
166            .parent()
167            .unwrap_or_else(|| std::path::Path::new("."));
168        create_dir_all(parent).unwrap();
169
170        let security_manager = SecurityManager::new(parent);
171
172        let mut manager = Self {
173            config_path,
174            accounts: HashMap::new(),
175            tasks: HashMap::new(),
176            security_manager,
177        };
178
179        if manager.config_path.exists() {
180            manager.load()?;
181        }
182        Ok(manager)
183    }
184
185    pub fn load(&mut self) -> Result<(), ConfigError> {
186        if self.config_path.exists() {
187            let content = fs::read_to_string(&self.config_path).unwrap();
188            let mut config: ConfigFile = serde_yaml::from_str(&content).unwrap();
189
190            // 执行配置迁移
191            let config_dir = self
192                .config_path
193                .parent()
194                .unwrap_or_else(|| std::path::Path::new("."));
195            let mut migration_occurred = false;
196
197            // 只要版本不是 0.1.0,就尝试迁移/重置
198            if config.version != "0.1.0" {
199                if let Err(e) = migrator::ConfigMigrator::migrate(&mut config, config_dir) {
200                    tracing::warn!("Config migration failed: {}", e);
201                } else {
202                    migration_occurred = true;
203                }
204            }
205
206            self.accounts = config
207                .accounts
208                .into_iter()
209                .map(|mut a| {
210                    // 解密凭据
211                    // 此时经过迁移,内存中的 config 应该已经是加密状态(如果是旧版本升级上来)
212                    // 或者是 ENC: 状态(如果是新版本读取)
213                    for (_, v) in a.credentials.iter_mut() {
214                        *v = self.security_manager.decrypt(v);
215                    }
216                    (a.id.clone(), a)
217                })
218                .collect();
219            self.tasks = config
220                .tasks
221                .into_iter()
222                .map(|t| (t.id.clone(), t))
223                .collect();
224
225            // 如果发生了迁移,保存更新后的配置
226            if migration_occurred {
227                tracing::info!("Config migration occurred, saving updated config...");
228                if let Err(e) = self.save() {
229                    tracing::error!("Failed to save migrated config: {}", e);
230                }
231            }
232        }
233        Ok(())
234    }
235
236    pub fn save(&self) -> Result<(), ConfigError> {
237        let accounts: Vec<AccountConfig> = self
238            .accounts
239            .values()
240            .cloned()
241            .map(|mut a| {
242                // 加密凭据
243                for (_, v) in a.credentials.iter_mut() {
244                    *v = self.security_manager.encrypt(v);
245                }
246                a
247            })
248            .collect();
249
250        let config = ConfigFile {
251            version: "0.1.0".to_string(), // Reset to 0.1.0
252            global_settings: Default::default(),
253            accounts,
254            tasks: self.tasks.values().cloned().collect(),
255            encryption_keys: vec![],
256            plugins: vec![],
257            schedules: vec![],
258            network_settings: None,
259            security_settings: None,
260        };
261
262        // 写入配置信息到文件!
263        let content = serde_yaml::to_string(&config).unwrap();
264        fs::write(&self.config_path, content).unwrap();
265        info!("Configuration saved to file: {:?}", self.config_path);
266        Ok(())
267    }
268}
269
270impl ConfigManager {
271    pub fn get_tasks(&self) -> &HashMap<String, SyncTask> {
272        &self.tasks
273    }
274
275    pub fn get_accounts(&self) -> &HashMap<String, AccountConfig> {
276        &self.accounts
277    }
278
279    pub fn add_task(&mut self, task: SyncTask) -> Result<(), ConfigError> {
280        self.tasks.insert(task.id.clone(), task);
281        Ok(())
282    }
283
284    pub fn add_account(&mut self, account: AccountConfig) -> Result<(), ConfigError> {
285        self.accounts.insert(account.id.clone(), account);
286        Ok(())
287    }
288
289    /// 更新账户
290    pub fn update_account(&mut self, account: AccountConfig) -> Result<(), ConfigError> {
291        self.accounts.insert(account.id.clone(), account);
292        Ok(())
293    }
294
295    /// 删除账户
296    pub fn remove_account(&mut self, account_id: &str) -> Result<(), ConfigError> {
297        self.accounts.remove(account_id);
298        Ok(())
299    }
300
301    /// 获取账户
302    pub fn get_account(&self, account_id: &str) -> Option<AccountConfig> {
303        self.accounts.get(account_id).cloned()
304    }
305
306    /// 更新任务
307    pub fn update_task(&mut self, task: SyncTask) -> Result<(), ConfigError> {
308        self.tasks.insert(task.id.clone(), task);
309        Ok(())
310    }
311
312    /// 删除任务
313    pub fn remove_task(&mut self, task_id: &str) -> Result<(), ConfigError> {
314        self.tasks.remove(task_id);
315        Ok(())
316    }
317}
318
319// 主要配置文件结构
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct ConfigFile {
322    pub version: String,
323    pub global_settings: GlobalSettings,
324    pub accounts: Vec<AccountConfig>,
325    pub tasks: Vec<SyncTask>,
326    pub encryption_keys: Vec<EncryptionKey>,
327    pub plugins: Vec<PluginConfig>,
328    pub schedules: Vec<ScheduleConfig>,
329    pub network_settings: Option<NetworkSettings>,
330    pub security_settings: Option<SecuritySettings>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
334pub struct GlobalSettings {
335    pub data_dir: Option<PathBuf>,
336    pub temp_dir: Option<PathBuf>,
337    pub log_level: LogLevel,
338    pub log_retention_days: u32,
339    pub max_concurrent_tasks: usize,
340    pub default_retry_policy: RetryPolicy,
341    pub enable_telemetry: bool,
342    pub auto_update_check: bool,
343    pub ui_language: String,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
347pub enum LogLevel {
348    Off,
349    Error,
350    Warn,
351    Info,
352    Debug,
353    Trace,
354}
355
356// todo 这里的字段不完善,lastUsed,createTime等字段不完整
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct EncryptionKey {
359    pub id: String,
360    pub name: String,
361    pub algorithm: EncryptionAlgorithm,
362    pub key_data: KeyData,
363    pub description: Option<String>,
364    pub tags: Vec<String>,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
368pub enum KeyData {
369    /// 本地存储的密钥(加密存储)
370    Local {
371        encrypted_data: Vec<u8>,
372        salt: Vec<u8>,
373    },
374    /// 外部密钥管理服务
375    External { service: String, key_uri: String },
376    /// 硬件安全模块
377    HSM {
378        module_id: String,
379        key_handle: String,
380    },
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct PluginConfig {
385    pub name: String,
386    pub enabled: bool,
387    pub version: String,
388    pub source: PluginSource,
389    pub config: HashMap<String, serde_json::Value>,
390    pub hooks: Vec<PluginHookConfig>,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub enum PluginSource {
395    /// 内置插件
396    Builtin,
397    /// 本地文件
398    Local { path: PathBuf },
399    /// Git仓库
400    Git { url: String, branch: Option<String> },
401    /// 注册表
402    Registry { name: String, version: String },
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct PluginHookConfig {
407    pub hook_name: String,
408    pub priority: i32,
409    pub enabled: bool,
410    pub config: Option<serde_json::Value>,
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct ScheduleConfig {
415    pub id: String,
416    pub name: String,
417    pub schedule: Schedule,
418    pub task_ids: Vec<String>,
419    pub enabled: bool,
420    pub max_runtime: Option<u64>, // 秒
421    pub overlap_policy: OverlapPolicy,
422    pub notifications: Vec<NotificationConfig>,
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
426pub enum OverlapPolicy {
427    /// 允许重叠执行
428    Allow,
429    /// 跳过新的执行
430    Skip,
431    /// 终止当前执行
432    Terminate,
433    /// 排队等待
434    Queue,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
438pub struct NotificationConfig {
439    pub type_: NotificationType,
440    pub destination: String,
441    pub events: Vec<NotificationEvent>,
442    pub enabled: bool,
443}
444
445#[derive(Debug, Clone, Serialize, Deserialize)]
446pub enum NotificationType {
447    Email,
448    Webhook,
449    Slack,
450    Discord,
451    Telegram,
452    Pushover,
453    Custom { command: String },
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
457pub enum NotificationEvent {
458    TaskStarted,
459    TaskCompleted,
460    TaskFailed,
461    TaskCancelled,
462    DiskFull,
463    RateLimited,
464    SecurityAlert,
465    Custom(String),
466}
467
468#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct NetworkSettings {
470    pub proxy: Option<ProxyConfig>,
471    pub dns_servers: Vec<String>,
472    pub timeout_seconds: u64,
473    pub connection_pool_size: usize,
474    pub enable_compression: bool,
475    pub enable_caching: bool,
476    pub user_agent: Option<String>,
477    pub custom_headers: HashMap<String, String>,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct ProxyConfig {
482    pub url: String,
483    pub username: Option<String>,
484    pub password: Option<String>,
485    pub bypass_for_local: bool,
486    pub bypass_list: Vec<String>,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize)]
490pub struct SecuritySettings {
491    pub enable_audit_log: bool,
492    pub audit_log_retention_days: u32,
493    pub enable_two_factor_auth: bool,
494    pub session_timeout_minutes: u32,
495    pub ip_whitelist: Vec<String>,
496    pub ip_blacklist: Vec<String>,
497    pub allowed_countries: Vec<String>,
498    pub block_tor_connections: bool,
499    pub rate_limiting: RateLimitingSettings,
500    pub encryption: SecurityEncryptionSettings,
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct RateLimitingSettings {
505    pub max_requests_per_minute: u32,
506    pub max_connections_per_ip: u32,
507    pub burst_size: u32,
508}
509
510#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct SecurityEncryptionSettings {
512    pub default_algorithm: EncryptionAlgorithm,
513    pub key_rotation_days: u32,
514    pub enforce_encryption: bool,
515    pub secure_key_storage: bool,
516}
517
518impl ConfigFile {
519    pub fn new() -> Self {
520        Self {
521            version: "0.1.0".to_string(),
522            global_settings: GlobalSettings::default(),
523            accounts: Vec::new(),
524            tasks: Vec::new(),
525            encryption_keys: Vec::new(),
526            plugins: Vec::new(),
527            schedules: Vec::new(),
528            network_settings: Some(NetworkSettings::default()),
529            security_settings: Some(SecuritySettings::default()),
530        }
531    }
532
533    pub fn validate(&self) -> Result<(), Vec<String>> {
534        let mut errors = Vec::new();
535
536        // 验证版本
537        if self.version != "0.1.0" {
538            errors.push(format!("Unsupported config version: {}", self.version));
539        }
540
541        // 验证账户
542        for (i, account) in self.accounts.iter().enumerate() {
543            if let Err(err) = account.validate() {
544                errors.push(format!("Account {} (index {}): {}", account.name, i, err));
545            }
546        }
547
548        // 验证任务
549        for (i, task) in self.tasks.iter().enumerate() {
550            if let Err(err) = task.validate() {
551                errors.push(format!("Task {} (index {}): {}", task.name, i, err));
552            }
553        }
554
555        // 验证密钥
556        let mut key_ids = std::collections::HashSet::new();
557        for key in &self.encryption_keys {
558            if key_ids.contains(&key.id) {
559                errors.push(format!("Duplicate encryption key ID: {}", key.id));
560            }
561            key_ids.insert(key.id.clone());
562        }
563
564        if errors.is_empty() {
565            Ok(())
566        } else {
567            Err(errors)
568        }
569    }
570
571    pub fn find_account(&self, account_id: &str) -> Option<&AccountConfig> {
572        self.accounts.iter().find(|a| a.id == account_id)
573    }
574
575    pub fn find_task(&self, task_id: &str) -> Option<&SyncTask> {
576        self.tasks.iter().find(|t| t.id == task_id)
577    }
578
579    pub fn find_encryption_key(&self, key_id: &str) -> Option<&EncryptionKey> {
580        self.encryption_keys.iter().find(|k| k.id == key_id)
581    }
582
583    pub fn find_schedule(&self, schedule_id: &str) -> Option<&ScheduleConfig> {
584        self.schedules.iter().find(|s| s.id == schedule_id)
585    }
586}
587
588impl Default for GlobalSettings {
589    fn default() -> Self {
590        Self {
591            data_dir: dirs::data_dir().map(|p| p.join("disksync")),
592            temp_dir: std::env::temp_dir().to_path_buf().into(),
593            log_level: LogLevel::Info,
594            log_retention_days: 30,
595            max_concurrent_tasks: 5,
596            default_retry_policy: RetryPolicy::default(),
597            enable_telemetry: false,
598            auto_update_check: true,
599            ui_language: "en".to_string(),
600        }
601    }
602}
603
604impl Default for NetworkSettings {
605    fn default() -> Self {
606        Self {
607            proxy: None,
608            dns_servers: vec!["8.8.8.8".to_string(), "8.8.4.4".to_string()],
609            timeout_seconds: 30,
610            connection_pool_size: 10,
611            enable_compression: true,
612            enable_caching: true,
613            user_agent: Some(format!("DiskSync/{}", env!("CARGO_PKG_VERSION"))),
614            custom_headers: HashMap::new(),
615        }
616    }
617}
618
619impl Default for SecuritySettings {
620    fn default() -> Self {
621        Self {
622            enable_audit_log: true,
623            audit_log_retention_days: 90,
624            enable_two_factor_auth: false,
625            session_timeout_minutes: 60,
626            ip_whitelist: Vec::new(),
627            ip_blacklist: Vec::new(),
628            allowed_countries: Vec::new(),
629            block_tor_connections: true,
630            rate_limiting: RateLimitingSettings::default(),
631            encryption: SecurityEncryptionSettings::default(),
632        }
633    }
634}
635
636impl Default for RateLimitingSettings {
637    fn default() -> Self {
638        Self {
639            max_requests_per_minute: 60,
640            max_connections_per_ip: 10,
641            burst_size: 5,
642        }
643    }
644}
645
646impl Default for SecurityEncryptionSettings {
647    fn default() -> Self {
648        Self {
649            default_algorithm: EncryptionAlgorithm::Aes256Gcm,
650            key_rotation_days: 90,
651            enforce_encryption: false,
652            secure_key_storage: true,
653        }
654    }
655}