1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
//! An engine for keeping remote siles synchronized. //! //! The engine is based on the Admissabilty Based Sequence Transformation algorithm (doi: [10.1109/TPDS.2010.64](http://dx.doi.org.ezproxy.library.dal.ca/10.1109/TPDS.2010.64)) //! The idea is that each site that wants to have a file synchronized will have an instance of [`Engine`](engine/struct.Engine.html) running. //! Any changes that are made to teh file should be run through the engine using either `process_diffs()` or `process_transaction()` prior to being broadcast. //! Any changes that are made at a remote site should be run through the engine using `integrate_remote()` prior to being applied to the file. //! //! This crate generally works well with [`rdiff`](https://crates.io/crates/rdiff), but can work with //! any system that generates difference operations that are limited to insert and delete. //! //!# Examples //! //! Assuming you have a method `read_transaction` for reading transactions from remote sites, //! the process for integrating remote changes onto a local file go like this: //! //! ```no_run //! use optra::{Engine, TransactionSequence, TimeStamper}; //! use std::collections::{LinkedList, BTreeMap}; //! use std::fs::OpenOptions; //!# fn read_transaction() -> (TransactionSequence, BTreeMap<u32, (u32, u32)>) { //!# (TransactionSequence::new(None, LinkedList::new(), LinkedList::new()), BTreeMap::new()) //!# } //!# //!# let mut engine = Engine::new(1); //!# let mut time_stamper = TimeStamper::new(); //! // Assume we already have an engine up and running //! let (mut remote_sequence, remote_lookup) = read_transaction(); //! engine.integrate_remote(&mut remote_sequence, &remote_lookup, &mut time_stamper); //! let mut file = OpenOptions::new() //! .read(true) //! .write(true) //! .open("local_file") //! .unwrap(); //! remote_sequence.apply(&mut file).unwrap(); //! ``` //! //! On the other hand, if you have a Diff generated by detecting differences to a local file, //! you can process the diff and then send it out (assuming you have a method called `send_transaction()`) //! //! In order to ensure that your tranaction has appropriate timestamps, you must have a [`TimeStamper`](engine/strict.TimeStamper.html) //! to keep track of the sequencing of operations. //! //! ```no_run //!# extern crate rdiff; //!# extern crate optra; //!# use optra::{Engine, TransactionSequence, TimeStamper}; //!# use rdiff::BlockHashes; //!# use std::collections::{LinkedList, BTreeMap}; //!# use std::fs::File; //!# fn main() { //!# fn send_transaction(_seq: TransactionSequence, _lookup: BTreeMap<u32, (u32, u32)>) { //!# //!# } //!# //!# let mut engine = Engine::new(1); //!# let mut file_hashes = BlockHashes::new(File::open("local_file").unwrap(), 8).unwrap(); //!# let mut time_stamper = TimeStamper::new(); //! let diffs = file_hashes.diff_and_update(File::open("local_file").unwrap()).unwrap(); //! let (transaction, lookup) = engine.process_diffs(diffs, &mut time_stamper); //! send_transaction(transaction, lookup); //!# } //! ``` #![feature(linked_list_extras)] #![deny(missing_docs)] #[macro_use] extern crate log; extern crate rdiff; extern crate byteorder; mod operations; mod utils; mod engine; pub use operations::{InsertOperation, DeleteOperation, Operation}; pub use engine::{Engine, TransactionSequence, TimeStamper}; type Offset = i64; type Position = u64; /// Represents an error in attempting to synchronize remote operations #[derive(Debug)] pub struct OTError { /// The kind of error this is pub kind: ErrorKind } /// Represents the kind of error we encountered synchronizing operations #[derive(Debug)] pub enum ErrorKind { /// The remote operations refer to a state that we have not yet recieved NoSuchState } impl OTError { /// Create a new OTError of the given kind. #[inline] pub fn new(kind: ErrorKind) -> OTError { OTError { kind: kind } } }