rvault/sync/
conflict.rs

1use std::collections::HashMap;
2use crate::{
3    storage::Secret,
4    sync::{ConflictInfo, SyncMetadata},
5    error::Result,
6};
7
8
9
10pub async fn detect_conflicts(
11    local_secrets: &HashMap<String, Secret>,
12    remote_metadata: &SyncMetadata,
13) -> Result<Vec<ConflictInfo>> {
14    let mut conflicts = Vec::new();
15    
16    // Simple conflict detection based on version comparison
17    for (key, secret) in local_secrets {
18        if secret.metadata.version != remote_metadata.sync_version {
19            let parts: Vec<&str> = key.split(':').collect();
20            if parts.len() >= 4 {
21                conflicts.push(ConflictInfo {
22                    secret_key: parts[3].to_string(),
23                    namespace: parts[2].to_string(),
24                    local_version: secret.metadata.version,
25                    remote_version: remote_metadata.sync_version,
26                    conflict_type: "ModifiedBoth".to_string(),
27                });
28            }
29        }
30    }
31    
32    Ok(conflicts)
33}
34
35#[derive(Debug)]
36pub enum ConflictResolution {
37    UseLocal,
38    UseRemote,
39    Merge,
40    Skip,
41}
42
43pub struct ConflictResolver;
44
45impl ConflictResolver {
46    #[allow(dead_code)]
47    pub fn resolve_conflict(
48        local_secret: &Secret,
49        remote_secret: &Secret,
50        strategy: ConflictResolution,
51    ) -> Result<Secret> {
52        match strategy {
53            ConflictResolution::UseLocal => Ok(local_secret.clone()),
54            ConflictResolution::UseRemote => Ok(remote_secret.clone()),
55            ConflictResolution::Merge => {
56                // Simple merge: use newer timestamp
57                if local_secret.metadata.updated_at > remote_secret.metadata.updated_at {
58                    Ok(local_secret.clone())
59                } else {
60                    Ok(remote_secret.clone())
61                }
62            }
63            ConflictResolution::Skip => Ok(local_secret.clone()),
64        }
65    }
66
67    pub fn auto_resolve_conflicts(
68        conflicts: &[ConflictInfo],
69        strategy: AutoResolveStrategy,
70    ) -> Result<Vec<(ConflictInfo, ConflictResolution)>> {
71        let mut resolutions = Vec::new();
72        
73        for conflict in conflicts {
74            let resolution = match strategy {
75                AutoResolveStrategy::PreferLocal => ConflictResolution::UseLocal,
76                AutoResolveStrategy::PreferRemote => ConflictResolution::UseRemote,
77                AutoResolveStrategy::PreferNewer => ConflictResolution::Merge,
78                AutoResolveStrategy::Manual => ConflictResolution::Skip,
79            };
80            resolutions.push((conflict.clone(), resolution));
81        }
82        
83        Ok(resolutions)
84    }
85}
86
87#[derive(Debug)]
88pub enum AutoResolveStrategy {
89    PreferLocal,
90    PreferRemote,
91    PreferNewer,
92    Manual,
93}