Просмотр исходного кода

bin/darkwikid: major bug fix & derive id from title of the doc

ghassmo 4 лет назад
Родитель
Сommit
42047b9540
5 измененных файлов с 55 добавлено и 95 удалено
  1. 1 1
      Cargo.lock
  2. 1 1
      bin/darkwikid/Cargo.toml
  3. 0 2
      bin/darkwikid/src/error.rs
  4. 43 65
      bin/darkwikid/src/main.rs
  5. 10 26
      bin/darkwikid/src/patch.rs

+ 1 - 1
Cargo.lock

@@ -1348,7 +1348,6 @@ dependencies = [
  "async-executor",
  "async-std",
  "async-trait",
- "bs58",
  "chrono",
  "crypto_box",
  "ctrlc-async",
@@ -1361,6 +1360,7 @@ dependencies = [
  "rand",
  "serde",
  "serde_json",
+ "sha2",
  "simplelog",
  "smol",
  "structopt",

+ 1 - 1
bin/darkwikid/Cargo.toml

@@ -43,6 +43,6 @@ structopt-toml = "0.5.1"
 unicode-segmentation = "1.9.0"
 crypto_box = {version = "0.8.0", features = ["std"]}
 hex = "0.4.3"
-bs58 = "0.4.0"
+sha2 = "0.10.2"
 
 

+ 0 - 2
bin/darkwikid/src/error.rs

@@ -1,7 +1,5 @@
 #[derive(thiserror::Error, Debug)]
 pub enum DarkWikiError {
-    #[error("File/Doc not found")]
-    FileNotFound,
     #[error("Encryption error: `{0}`")]
     EncryptionError(String),
     #[error("Json serialization error: `{0}`")]

+ 43 - 65
bin/darkwikid/src/main.rs

@@ -1,8 +1,7 @@
 use async_std::sync::{Arc, Mutex};
 use std::{
     fs::{create_dir_all, read_dir},
-    mem::discriminant,
-    path::{Path, PathBuf},
+    path::PathBuf,
 };
 
 use async_executor::Executor;
@@ -10,6 +9,7 @@ use futures::{select, FutureExt};
 use fxhash::FxHashMap;
 use log::{error, info, warn};
 use serde::Deserialize;
+use sha2::Digest;
 use smol::future;
 use structopt::StructOpt;
 use structopt_toml::StructOptToml;
@@ -25,7 +25,6 @@ use darkfi::{
         cli::{get_log_config, get_log_level, spawn_config},
         expand_path,
         file::{load_file, load_json_file, save_file, save_json_file},
-        gen_id,
         path::get_config_path,
     },
     Error, Result,
@@ -35,7 +34,7 @@ mod error;
 mod jsonrpc;
 mod patch;
 
-use error::{DarkWikiError, DarkWikiResult};
+use error::DarkWikiResult;
 use jsonrpc::JsonRpcInterface;
 use patch::{OpMethod, Patch};
 
@@ -79,27 +78,6 @@ fn str_to_chars(s: &str) -> Vec<&str> {
     s.graphemes(true).collect::<Vec<&str>>()
 }
 
-fn get_from_index(local_path: &Path, title: &str) -> DarkWikiResult<String> {
-    let index = load_json_file::<FxHashMap<String, String>>(&local_path.join("index"))?;
-
-    for (i, t) in index {
-        if t == title {
-            return Ok(i)
-        }
-    }
-
-    Err(DarkWikiError::FileNotFound)
-}
-
-fn save_to_index(local_path: &Path, id: &str, title: &str) -> DarkWikiResult<()> {
-    let mut index = load_json_file::<FxHashMap<String, String>>(&local_path.join("index"))
-        .unwrap_or(FxHashMap::default());
-
-    index.insert(id.to_owned(), title.to_owned());
-    save_json_file(&local_path.join("index"), &index)?;
-    Ok(())
-}
-
 fn lcs(a: &str, b: &str) -> Vec<OpMethod> {
     let a: Vec<_> = str_to_chars(a);
     let b: Vec<_> = str_to_chars(b);
@@ -135,28 +113,39 @@ fn lcs(a: &str, b: &str) -> Vec<OpMethod> {
 }
 
 fn on_receive_patch(received_patch: &Patch, settings: &DarkWikiSettings) -> DarkWikiResult<()> {
-    let sync_id_path = settings.datastore_path.join("sync").join(&received_patch.id());
-    let local_id_path = settings.datastore_path.join("local").join(&received_patch.id());
+    let sync_id_path = settings.datastore_path.join("sync").join(&received_patch.id);
+    let local_id_path = settings.datastore_path.join("local").join(&received_patch.id);
 
     if let Ok(mut sync_patch) = load_json_file::<Patch>(&sync_id_path) {
-        if let Ok(local_edit) = load_file(&local_id_path) {
-            let local_edit = local_edit.trim();
+        if sync_patch.timestamp == received_patch.timestamp {
+            return Ok(())
+        }
 
-            if local_edit == sync_patch.to_string() {
+        if let Ok(local_patch) = load_json_file::<Patch>(&local_id_path) {
+            if local_patch.timestamp == sync_patch.timestamp {
+                sync_patch.base = local_patch.to_string();
                 sync_patch.set_ops(received_patch.ops());
             } else {
                 sync_patch.extend_ops(received_patch.ops());
             }
         }
 
+        sync_patch.timestamp = received_patch.timestamp;
+        sync_patch.author = received_patch.author.clone();
         save_json_file::<Patch>(&sync_id_path, &sync_patch)?;
-    } else if !received_patch.base_empty() {
+    } else if !received_patch.base.is_empty() {
         save_json_file::<Patch>(&sync_id_path, received_patch)?;
     }
 
     Ok(())
 }
 
+fn title_to_id(title: &str) -> String {
+    let mut hasher = sha2::Sha256::new();
+    hasher.update(title);
+    hex::encode(hasher.finalize())
+}
+
 fn on_receive_update(settings: &DarkWikiSettings) -> DarkWikiResult<Vec<Patch>> {
     let mut patches: Vec<Patch> = vec![];
 
@@ -171,59 +160,52 @@ fn on_receive_update(settings: &DarkWikiSettings) -> DarkWikiResult<Vec<Patch>>
         let doc_title = doc.as_ref().unwrap().file_name();
         let doc_title = doc_title.to_str().unwrap();
 
-        let doc_id = match get_from_index(&local_path, doc_title) {
-            Ok(id) => id,
-            Err(_) => {
-                let id = gen_id(30);
-                save_to_index(&local_path, &id, doc_title)?;
-                id
-            }
-        };
-
         // load doc content
         let edit = load_file(&docs_path.join(doc_title)).map_err(Error::from)?;
         let edit = edit.trim();
 
+        let doc_id = title_to_id(doc_title);
+
         // create new patch
         let mut new_patch = Patch::new(doc_title, &doc_id, &settings.author);
+        let mut b_patch;
 
         // check for any changes found with local doc and darkwiki doc
-        if let Ok(local_edit) = load_file(&local_path.join(&doc_id)) {
-            let local_edit = local_edit.trim();
-
-            // check the differences with LCS algorithm
-            let lcs_ops = lcs(local_edit, edit);
-
-            let retains_len = lcs_ops
-                .iter()
-                .filter(|&o| discriminant(&OpMethod::Retain(0)) == discriminant(o))
-                .count();
-
-            // if all the ops in lcs_ops are Reatin then no changes found
-            if retains_len == lcs_ops.len() {
+        if let Ok(local_patch) = load_json_file::<Patch>(&local_path.join(&doc_id)) {
+            // no changes found
+            if local_patch.to_string() == edit {
                 continue
             }
 
+            // check the differences with LCS algorithm
+            let lcs_ops = lcs(&local_patch.to_string(), edit);
+
             // add the change ops to the new patch
             for op in lcs_ops {
                 new_patch.add_op(&op);
             }
 
+            new_patch.base = local_patch.to_string();
+
             // check if the same doc has received patch from the network
             if let Ok(sync_patch) = load_json_file::<Patch>(&sync_path.join(&doc_id)) {
-                if sync_patch.to_string() != local_edit {
+                if sync_patch.timestamp != local_patch.timestamp {
                     let sync_patch_t = new_patch.transform(&sync_patch);
                     new_patch = new_patch.merge(&sync_patch_t);
                     save_file(&docs_path.join(doc_title), &new_patch.to_string())?;
                 }
             }
+
+            b_patch = new_patch.clone();
+            b_patch.base = "".to_string();
         } else {
-            new_patch.set_base(edit);
+            new_patch.base = edit.to_string();
+            b_patch = new_patch.clone();
         };
 
-        save_file(&local_path.join(&doc_id), &new_patch.to_string())?;
+        save_json_file(&local_path.join(&doc_id), &new_patch)?;
         save_json_file(&sync_path.join(doc_id), &new_patch)?;
-        patches.push(new_patch);
+        patches.push(b_patch);
     }
 
     // check if a new patch received
@@ -235,18 +217,14 @@ fn on_receive_update(settings: &DarkWikiSettings) -> DarkWikiResult<Vec<Patch>>
         let file_path = sync_path.join(&file_id);
         let sync_patch: Patch = load_json_file(&file_path)?;
 
-        if let Ok(local_edit) = load_file(&local_path.join(&file_id)) {
-            if local_edit.trim() == sync_patch.to_string() {
+        if let Ok(local_patch) = load_json_file::<Patch>(&local_path.join(&file_id)) {
+            if local_patch.timestamp == sync_patch.timestamp {
                 continue
             }
         }
 
-        let sync_patch_str = sync_patch.to_string();
-        let file_title = sync_patch.title();
-        save_to_index(&local_path, file_id, &file_title)?;
-
-        save_file(&docs_path.join(&file_title), &sync_patch_str)?;
-        save_file(&local_path.join(file_id), &sync_patch_str)?;
+        save_file(&docs_path.join(&sync_patch.title), &sync_patch.to_string())?;
+        save_json_file(&local_path.join(file_id), &sync_patch)?;
     }
 
     Ok(patches)

+ 10 - 26
bin/darkwikid/src/patch.rs

@@ -21,12 +21,12 @@ pub struct OpMethods(pub Vec<OpMethod>);
 
 #[derive(PartialEq, Eq, SerialEncodable, SerialDecodable, Serialize, Deserialize, Clone, Debug)]
 pub struct Patch {
-    title: String,
-    author: String,
-    id: String,
-    base: String,
+    pub title: String,
+    pub author: String,
+    pub id: String,
+    pub base: String,
+    pub timestamp: Timestamp,
     ops: OpMethods,
-    timestamp: Timestamp,
 }
 
 impl std::string::ToString for Patch {
@@ -129,10 +129,6 @@ impl Patch {
         self.add_op(&OpMethod::Delete(n));
     }
 
-    pub fn set_base(&mut self, base: &str) {
-        self.base = base.to_owned();
-    }
-
     pub fn set_ops(&mut self, ops: OpMethods) {
         self.ops = ops;
     }
@@ -141,18 +137,6 @@ impl Patch {
         self.ops.0.extend(ops.0);
     }
 
-    pub fn base_empty(&self) -> bool {
-        self.base.is_empty()
-    }
-
-    pub fn id(&self) -> String {
-        self.id.clone()
-    }
-
-    pub fn title(&self) -> String {
-        self.title.clone()
-    }
-
     pub fn ops(&self) -> OpMethods {
         self.ops.clone()
     }
@@ -165,7 +149,7 @@ impl Patch {
     // TODO need more work to get better performance with iterators
     pub fn transform(&self, other: &Self) -> Self {
         let mut new_patch = Self::new(&self.title, &self.id, &self.author);
-        new_patch.set_base(&self.base);
+        new_patch.base = self.base.clone();
 
         let mut ops1 = self.ops.0.iter().cloned();
         let mut ops2 = other.ops.0.iter().cloned();
@@ -267,7 +251,7 @@ impl Patch {
         let mut ops2 = other.ops.0.iter().cloned();
 
         let mut new_patch = Self::new(&self.title, &self.id, &self.author);
-        new_patch.set_base(&self.base);
+        new_patch.base = self.base.clone();
 
         let mut op1 = ops1.next();
         let mut op2 = ops2.next();
@@ -439,7 +423,7 @@ mod tests {
     #[test]
     fn test_to_string() {
         let mut patch = Patch::new("", &gen_id(30), "");
-        patch.set_base("text example\n hello");
+        patch.base = "text example\n hello".to_string();
         patch.retain(14);
         patch.delete(5);
         patch.insert("hey");
@@ -451,7 +435,7 @@ mod tests {
     fn test_merge() {
         let mut patch_init = Patch::new("", &gen_id(30), "");
         let base = "text example\n hello";
-        patch_init.set_base(base);
+        patch_init.base = base.to_string();
 
         let mut patch1 = patch_init.clone();
         patch1.retain(14);
@@ -489,7 +473,7 @@ mod tests {
     fn test_transform() {
         let mut patch_init = Patch::new("", &gen_id(30), "");
         let base = "text example\n hello";
-        patch_init.set_base(base);
+        patch_init.base = base.to_string();
 
         let mut patch1 = patch_init.clone();
         patch1.retain(14);