jax-common 0.1.11

Core data structures and cryptography for JaxBucket - end-to-end encrypted P2P storage
Documentation
//! Base-wins conflict resolver

use crate::crypto::PublicKey;

use super::types::{Conflict, Resolution};
use super::ConflictResolver;

/// Base-wins conflict resolution (conservative)
///
/// The local (base) operation always wins over incoming operations.
/// Use this when you want to preserve local changes and require
/// explicit action to accept remote changes.
#[derive(Debug, Clone, Default)]
pub struct BaseWins;

impl BaseWins {
    /// Create a new BaseWins resolver
    pub fn new() -> Self {
        Self
    }
}

impl ConflictResolver for BaseWins {
    fn resolve(&self, _conflict: &Conflict, _local_peer: &PublicKey) -> Resolution {
        Resolution::UseBase
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::crypto::SecretKey;
    use crate::mount::path_ops::{OpId, OpType, PathOperation};
    use std::path::PathBuf;

    fn make_peer_id(seed: u8) -> PublicKey {
        let mut seed_bytes = [0u8; 32];
        seed_bytes[0] = seed;
        let secret = SecretKey::from(seed_bytes);
        secret.public()
    }

    fn make_op(peer_id: PublicKey, timestamp: u64, op_type: OpType, path: &str) -> PathOperation {
        PathOperation {
            id: OpId { timestamp, peer_id },
            op_type,
            path: PathBuf::from(path),
            content_link: None,
            is_dir: false,
        }
    }

    #[test]
    fn test_base_wins() {
        let peer1 = make_peer_id(1);
        let peer2 = make_peer_id(2);

        let base = make_op(peer1, 1, OpType::Add, "file.txt");
        let incoming = make_op(peer2, 2, OpType::Remove, "file.txt");

        let conflict = Conflict::new(PathBuf::from("file.txt"), base, incoming);
        let resolver = BaseWins::new();

        // BaseWins always returns UseBase regardless of timestamps
        assert_eq!(resolver.resolve(&conflict, &peer1), Resolution::UseBase);
    }
}