瀏覽代碼

chore: fix trailing characters parser error

appflowy 2 年之前
父節點
當前提交
4c07ae26fc

+ 69 - 2
shared-lib/flowy-folder-data-model/src/revision/folder_rev.rs

@@ -1,9 +1,76 @@
 use crate::revision::{TrashRevision, WorkspaceRevision};
-use serde::{Deserialize, Serialize};
+use serde::de::{MapAccess, Visitor};
+use serde::{de, Deserialize, Deserializer, Serialize};
+use std::fmt;
 use std::sync::Arc;
 
-#[derive(Debug, Default, Deserialize, Serialize, Clone, Eq, PartialEq)]
+#[derive(Debug, Default, Serialize, Clone, Eq, PartialEq)]
 pub struct FolderRevision {
     pub workspaces: Vec<Arc<WorkspaceRevision>>,
     pub trash: Vec<Arc<TrashRevision>>,
 }
+
+impl<'de> Deserialize<'de> for FolderRevision {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct FolderVisitor<'a>(&'a mut Option<FolderRevision>);
+        impl<'de, 'a> Visitor<'de> for FolderVisitor<'a> {
+            type Value = ();
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("Expect struct FolderRevision")
+            }
+
+            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+            where
+                A: MapAccess<'de>,
+            {
+                let f = |map: &mut A,
+                         workspaces: &mut Option<Vec<WorkspaceRevision>>,
+                         trash: &mut Option<Vec<TrashRevision>>| match map.next_key::<String>()
+                {
+                    Ok(Some(key)) => {
+                        if key == "workspaces" && workspaces.is_none() {
+                            *workspaces = Some(map.next_value::<Vec<WorkspaceRevision>>().ok()?);
+                        }
+                        if key == "trash" && trash.is_none() {
+                            *trash = Some(map.next_value::<Vec<TrashRevision>>().ok()?);
+                        }
+                        Some(())
+                    }
+                    Ok(None) => None,
+                    Err(_e) => None,
+                };
+
+                let mut workspaces: Option<Vec<WorkspaceRevision>> = None;
+                let mut trash: Option<Vec<TrashRevision>> = None;
+                while f(&mut map, &mut workspaces, &mut trash).is_some() {
+                    if workspaces.is_some() && trash.is_some() {
+                        break;
+                    }
+                }
+
+                *self.0 = Some(FolderRevision {
+                    workspaces: workspaces.unwrap_or_default().into_iter().map(Arc::new).collect(),
+                    trash: trash.unwrap_or_default().into_iter().map(Arc::new).collect(),
+                });
+                Ok(())
+            }
+        }
+
+        let mut folder_rev: Option<FolderRevision> = None;
+        const FIELDS: &[&str] = &["workspaces", "trash"];
+        let _ = serde::Deserializer::deserialize_struct(
+            deserializer,
+            "FolderRevision",
+            FIELDS,
+            FolderVisitor(&mut folder_rev),
+        );
+
+        match folder_rev {
+            None => Err(de::Error::missing_field("workspaces or trash")),
+            Some(folder_rev) => Ok(folder_rev),
+        }
+    }
+}

+ 5 - 1
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -12,6 +12,7 @@ use flowy_folder_data_model::revision::{AppRevision, FolderRevision, TrashRevisi
 use lib_infra::util::move_vec_element;
 use lib_ot::core::*;
 
+use serde::Deserialize;
 use std::sync::Arc;
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -44,7 +45,9 @@ impl FolderPad {
     pub fn from_delta(delta: FolderDelta) -> CollaborateResult<Self> {
         // TODO: Reconvert from history if delta.to_str() failed.
         let content = delta.content()?;
-        let folder_rev: FolderRevision = serde_json::from_str(&content).map_err(|e| {
+        let mut deserializer = serde_json::Deserializer::from_reader(content.as_bytes());
+
+        let folder_rev = FolderRevision::deserialize(&mut deserializer).map_err(|e| {
             tracing::error!("Deserialize folder from {} failed", content);
             return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e));
         })?;
@@ -455,6 +458,7 @@ mod tests {
     #![allow(clippy::all)]
     use crate::{client_folder::folder_pad::FolderPad, entities::folder::FolderDelta};
     use chrono::Utc;
+    use serde::Deserialize;
 
     use flowy_folder_data_model::revision::{
         AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,