Преглед изворни кода

holding opened file handler

appflowy пре 3 година
родитељ
комит
c5d1a90009

+ 3 - 0
rust-lib/flowy-document/Cargo.toml

@@ -13,8 +13,10 @@ flowy-derive = { path = "../flowy-derive" }
 flowy-database = { path = "../flowy-database" }
 flowy-infra = { path = "../flowy-infra" }
 flowy-observable = { path = "../flowy-observable" }
+flowy-ot = { path = "../flowy-ot" }
 flowy-net = { path = "../flowy-net", features = ["flowy_request"] }
 
+
 diesel = {version = "1.4.7", features = ["sqlite"]}
 diesel_derives = {version = "1.4.1", features = ["sqlite"]}
 protobuf = {version = "2.18.0"}
@@ -26,6 +28,7 @@ tracing = { version = "0.1", features = ["log"] }
 bytes = { version = "1.0" }
 strum = "0.21"
 strum_macros = "0.21"
+dashmap = "4.0"
 
 [dev-dependencies]
 flowy-test = { path = "../flowy-test" }

+ 4 - 0
rust-lib/flowy-document/src/entities/doc/parser/doc_id.rs

@@ -10,3 +10,7 @@ impl DocId {
         Ok(Self(s))
     }
 }
+
+impl AsRef<str> for DocId {
+    fn as_ref(&self) -> &str { &self.0 }
+}

+ 0 - 5
rust-lib/flowy-document/src/errors.rs

@@ -1,4 +1,3 @@
-use crate::services::file_manager::FileError;
 use bytes::Bytes;
 use derive_more::Display;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
@@ -53,10 +52,6 @@ impl std::convert::From<flowy_database::Error> for DocError {
 //     fn from(error: r2d2::Error) -> Self {
 // ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } }
 
-impl std::convert::From<FileError> for DocError {
-    fn from(error: FileError) -> Self { ErrorBuilder::new(ErrorCode::InternalError).error(error).build() }
-}
-
 // impl std::convert::From<flowy_sqlite::Error> for DocError {
 //     fn from(error: flowy_sqlite::Error) -> Self {
 // ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } }

+ 33 - 14
rust-lib/flowy-document/src/module.rs

@@ -1,8 +1,11 @@
 use crate::{
     errors::DocError,
-    services::{doc_controller::DocController, file_manager::FileManager, server::construct_doc_server},
+    services::{doc_controller::DocController, doc_manager::DocManager, server::construct_doc_server},
 };
 
+use crate::entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams};
+use diesel::SqliteConnection;
+use flowy_database::ConnectionPool;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
@@ -16,21 +19,37 @@ pub enum DocumentType {
     Doc,
 }
 
-pub struct Document {
-    user: Arc<dyn DocumentUser>,
-    file_manager: RwLock<FileManager>,
-    pub doc: Arc<DocController>,
+pub struct FlowyDocument {
+    controller: Arc<DocController>,
+    manager: Arc<DocManager>,
 }
 
-impl Document {
-    pub fn new(user: Arc<dyn DocumentUser>) -> Document {
+impl FlowyDocument {
+    pub fn new(user: Arc<dyn DocumentUser>) -> FlowyDocument {
         let server = construct_doc_server();
-        let doc_controller = Arc::new(DocController::new(server.clone(), user.clone()));
-        let file_manager = RwLock::new(FileManager::new(user.clone()));
-        Self {
-            user,
-            file_manager,
-            doc: doc_controller,
-        }
+        let manager = Arc::new(DocManager::new());
+        let controller = Arc::new(DocController::new(server.clone(), user.clone()));
+        Self { controller, manager }
+    }
+
+    pub fn create(&self, params: CreateDocParams, conn: &SqliteConnection) -> Result<(), DocError> {
+        let _ = self.controller.create(params, conn)?;
+        Ok(())
+    }
+
+    pub fn delete(&self, params: QueryDocParams, conn: &SqliteConnection) -> Result<(), DocError> {
+        let _ = self.controller.delete(params.into(), conn)?;
+        Ok(())
+    }
+
+    pub async fn open(&self, params: QueryDocParams, pool: Arc<ConnectionPool>) -> Result<Doc, DocError> {
+        let doc = self.controller.open(params, pool).await?;
+
+        Ok(doc)
+    }
+
+    pub fn update(&self, params: UpdateDocParams, conn: &SqliteConnection) -> Result<(), DocError> {
+        let _ = self.controller.update(params, conn)?;
+        Ok(())
     }
 }

+ 65 - 0
rust-lib/flowy-document/src/services/doc_manager/doc_manager.rs

@@ -0,0 +1,65 @@
+use crate::errors::{DocError, ErrorBuilder, ErrorCode};
+use dashmap::{mapref::one::Ref, DashMap};
+use flowy_ot::{
+    client::{Document, FlowyDoc},
+    core::Delta,
+};
+use std::convert::TryInto;
+use tokio::sync::RwLock;
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct DocId(pub(crate) String);
+
+pub struct DocInfo {
+    document: Document,
+}
+
+impl std::convert::From<String> for DocId {
+    fn from(s: String) -> Self { DocId(s) }
+}
+
+pub(crate) struct DocManager {
+    inner: DashMap<DocId, RwLock<DocInfo>>,
+}
+
+impl DocManager {
+    pub(crate) fn new() -> Self { Self { inner: DashMap::new() } }
+    pub(crate) fn open<T, D>(&self, id: T, data: D) -> Result<(), DocError>
+    where
+        T: Into<DocId>,
+        D: TryInto<Delta, Error = DocError>,
+    {
+        let doc_id = id.into();
+        let delta = data.try_into()?;
+        let document = Document::from_delta(delta);
+        let doc_info = DocInfo { document };
+        self.inner.insert(doc_id, RwLock::new(doc_info));
+        Ok(())
+    }
+
+    pub(crate) async fn mut_doc<T, F>(&self, id: T, f: F) -> Result<(), DocError>
+    where
+        T: Into<DocId>,
+        F: FnOnce(&mut Document) -> Result<(), DocError>,
+    {
+        let doc_id = id.into();
+        match self.inner.get(&doc_id) {
+            None => Err(ErrorBuilder::new(ErrorCode::DocNotfound)
+                .msg("Doc is close or you should call open first")
+                .build()),
+            Some(doc_info) => {
+                let mut write_guard = doc_info.write().await;
+                f(&mut write_guard.document)
+            },
+        }
+    }
+
+    pub(crate) fn close<T>(&self, id: T) -> Result<(), DocError>
+    where
+        T: Into<DocId>,
+    {
+        let doc_id = id.into();
+        self.inner.remove(&doc_id);
+        Ok(())
+    }
+}

+ 3 - 0
rust-lib/flowy-document/src/services/doc_manager/mod.rs

@@ -0,0 +1,3 @@
+mod doc_manager;
+
+pub use doc_manager::*;

+ 1 - 1
rust-lib/flowy-document/src/services/mod.rs

@@ -1,3 +1,3 @@
 pub mod doc_controller;
-pub mod file_manager;
+pub(crate) mod doc_manager;
 pub mod server;

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/mod.rs

@@ -8,9 +8,9 @@ mod delete;
 mod format;
 mod insert;
 
-pub type InsertExtension = Box<dyn InsertExt>;
-pub type FormatExtension = Box<dyn FormatExt>;
-pub type DeleteExtension = Box<dyn DeleteExt>;
+pub type InsertExtension = Box<dyn InsertExt + Send + Sync>;
+pub type FormatExtension = Box<dyn FormatExt + Send + Sync>;
+pub type DeleteExtension = Box<dyn DeleteExt + Send + Sync>;
 
 pub trait InsertExt {
     fn ext_name(&self) -> &str;

+ 2 - 2
rust-lib/flowy-sdk/src/module.rs

@@ -1,7 +1,7 @@
 use flowy_dispatch::prelude::Module;
 
 use crate::deps_resolve::{EditorUserImpl, WorkspaceDatabaseImpl, WorkspaceUserImpl};
-use flowy_document::module::Document;
+use flowy_document::module::FlowyDocument;
 use flowy_user::services::user::UserSessionBuilder;
 use std::sync::Arc;
 
@@ -24,7 +24,7 @@ pub fn build_modules(config: ModuleConfig) -> Vec<Module> {
         user_session: user_session.clone(),
     });
 
-    let document = Arc::new(Document::new(editor_user));
+    let document = Arc::new(FlowyDocument::new(editor_user));
 
     vec![
         flowy_user::module::create(user_session),

+ 2 - 2
rust-lib/flowy-workspace/src/module.rs

@@ -6,7 +6,7 @@ use crate::{
 };
 use flowy_database::DBConnection;
 use flowy_dispatch::prelude::*;
-use flowy_document::module::Document;
+use flowy_document::module::FlowyDocument;
 use flowy_sqlite::ConnectionPool;
 use std::sync::Arc;
 
@@ -29,7 +29,7 @@ pub trait WorkspaceDatabase: Send + Sync {
     }
 }
 
-pub fn create(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>, document: Arc<Document>) -> Module {
+pub fn create(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyDocument>) -> Module {
     let server = construct_workspace_server();
     let view_controller = Arc::new(ViewController::new(user.clone(), database.clone(), server.clone(), document));
     let app_controller = Arc::new(AppController::new(user.clone(), database.clone(), server.clone()));

+ 12 - 7
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -15,7 +15,7 @@ use crate::{
 use flowy_database::SqliteConnection;
 use flowy_document::{
     entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams},
-    module::Document,
+    module::FlowyDocument,
 };
 use std::sync::Arc;
 
@@ -24,11 +24,16 @@ pub(crate) struct ViewController {
     sql: Arc<ViewTableSql>,
     server: Server,
     database: Arc<dyn WorkspaceDatabase>,
-    document: Arc<Document>,
+    document: Arc<FlowyDocument>,
 }
 
 impl ViewController {
-    pub(crate) fn new(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>, server: Server, document: Arc<Document>) -> Self {
+    pub(crate) fn new(
+        user: Arc<dyn WorkspaceUser>,
+        database: Arc<dyn WorkspaceDatabase>,
+        server: Server,
+        document: Arc<FlowyDocument>,
+    ) -> Self {
         let sql = Arc::new(ViewTableSql {});
         Self {
             user,
@@ -45,7 +50,7 @@ impl ViewController {
         // TODO: rollback anything created before if failed?
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.save_view(view.clone(), conn)?;
-            self.document.doc.create(CreateDocParams::new(&view.id, &params.data), conn)?;
+            self.document.create(CreateDocParams::new(&view.id, &params.data), conn)?;
 
             let repeated_view = self.read_local_views_belong_to(&view.belong_to_id, conn)?;
             notify(&view.belong_to_id, WorkspaceObservable::AppCreateView)
@@ -72,7 +77,7 @@ impl ViewController {
     }
 
     pub(crate) async fn open_view(&self, params: QueryDocParams) -> Result<Doc, WorkspaceError> {
-        let doc = self.document.doc.open(params, self.database.db_pool()?).await?;
+        let doc = self.document.open(params, self.database.db_pool()?).await?;
         Ok(doc)
     }
 
@@ -82,7 +87,7 @@ impl ViewController {
 
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let view_table = self.sql.delete_view(&params.view_id, conn)?;
-            let _ = self.document.doc.delete(params.into(), conn)?;
+            let _ = self.document.delete(params.into(), conn)?;
 
             let repeated_view = self.read_local_views_belong_to(&view_table.belong_to_id, conn)?;
             notify(&view_table.belong_to_id, WorkspaceObservable::AppDeleteView)
@@ -121,7 +126,7 @@ impl ViewController {
 
     pub(crate) async fn update_view_data(&self, params: UpdateDocParams) -> Result<(), WorkspaceError> {
         let conn = &*self.database.db_connection()?;
-        let _ = self.document.doc.update(params, &*conn)?;
+        let _ = self.document.update(params, &*conn)?;
         Ok(())
     }
 }