|
@@ -1,12 +1,8 @@
|
|
|
use crate::{
|
|
|
document::Document,
|
|
|
- entities::{
|
|
|
- doc::DocumentInfo,
|
|
|
- revision::{RepeatedRevision, Revision},
|
|
|
- ws::DocumentServerWSDataBuilder,
|
|
|
- },
|
|
|
+ entities::{doc::DocumentInfo, ws::DocumentServerWSDataBuilder},
|
|
|
errors::{internal_error, CollaborateError, CollaborateResult},
|
|
|
- protobuf::DocumentClientWSData,
|
|
|
+ protobuf::{DocumentClientWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
|
|
|
sync::{RevisionSynchronizer, RevisionUser, SyncResponse},
|
|
|
};
|
|
|
use async_stream::stream;
|
|
@@ -14,29 +10,41 @@ use dashmap::DashMap;
|
|
|
use futures::stream::StreamExt;
|
|
|
use lib_infra::future::BoxResultFuture;
|
|
|
use lib_ot::rich_text::RichTextDelta;
|
|
|
-use std::{convert::TryFrom, fmt::Debug, sync::Arc};
|
|
|
+use std::{collections::HashMap, fmt::Debug, sync::Arc};
|
|
|
use tokio::{
|
|
|
- sync::{mpsc, oneshot},
|
|
|
+ sync::{mpsc, oneshot, RwLock},
|
|
|
task::spawn_blocking,
|
|
|
};
|
|
|
|
|
|
pub trait DocumentPersistence: Send + Sync + Debug {
|
|
|
fn read_doc(&self, doc_id: &str) -> BoxResultFuture<DocumentInfo, CollaborateError>;
|
|
|
- fn create_doc(&self, doc_id: &str, revisions: Vec<Revision>) -> BoxResultFuture<DocumentInfo, CollaborateError>;
|
|
|
- fn get_revisions(&self, doc_id: &str, rev_ids: Vec<i64>) -> BoxResultFuture<Vec<Revision>, CollaborateError>;
|
|
|
- fn get_doc_revisions(&self, doc_id: &str) -> BoxResultFuture<Vec<Revision>, CollaborateError>;
|
|
|
- fn reset_document(&self, doc_id: &str, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError>;
|
|
|
+
|
|
|
+ fn create_doc(
|
|
|
+ &self,
|
|
|
+ doc_id: &str,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
+ ) -> BoxResultFuture<DocumentInfo, CollaborateError>;
|
|
|
+
|
|
|
+ fn get_revisions(&self, doc_id: &str, rev_ids: Vec<i64>) -> BoxResultFuture<Vec<RevisionPB>, CollaborateError>;
|
|
|
+
|
|
|
+ fn get_doc_revisions(&self, doc_id: &str) -> BoxResultFuture<Vec<RevisionPB>, CollaborateError>;
|
|
|
+
|
|
|
+ fn reset_document(
|
|
|
+ &self,
|
|
|
+ doc_id: &str,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
+ ) -> BoxResultFuture<(), CollaborateError>;
|
|
|
}
|
|
|
|
|
|
pub struct ServerDocumentManager {
|
|
|
- open_doc_map: DashMap<String, Arc<OpenDocHandle>>,
|
|
|
+ open_doc_map: Arc<RwLock<HashMap<String, Arc<OpenDocHandle>>>>,
|
|
|
persistence: Arc<dyn DocumentPersistence>,
|
|
|
}
|
|
|
|
|
|
impl ServerDocumentManager {
|
|
|
pub fn new(persistence: Arc<dyn DocumentPersistence>) -> Self {
|
|
|
Self {
|
|
|
- open_doc_map: DashMap::new(),
|
|
|
+ open_doc_map: Arc::new(RwLock::new(HashMap::new())),
|
|
|
persistence,
|
|
|
}
|
|
|
}
|
|
@@ -46,28 +54,20 @@ impl ServerDocumentManager {
|
|
|
user: Arc<dyn RevisionUser>,
|
|
|
mut client_data: DocumentClientWSData,
|
|
|
) -> Result<(), CollaborateError> {
|
|
|
- let mut pb = client_data.take_revisions();
|
|
|
+ let repeated_revision = client_data.take_revisions();
|
|
|
let cloned_user = user.clone();
|
|
|
let ack_id = rev_id_from_str(&client_data.id)?;
|
|
|
let doc_id = client_data.doc_id;
|
|
|
|
|
|
- let revisions = spawn_blocking(move || {
|
|
|
- let repeated_revision = RepeatedRevision::try_from(&mut pb)?;
|
|
|
- let revisions = repeated_revision.into_inner();
|
|
|
- Ok::<Vec<Revision>, CollaborateError>(revisions)
|
|
|
- })
|
|
|
- .await
|
|
|
- .map_err(internal_error)??;
|
|
|
-
|
|
|
let result = match self.get_document_handler(&doc_id).await {
|
|
|
None => {
|
|
|
- let _ = self.create_document(&doc_id, revisions).await.map_err(|e| {
|
|
|
+ let _ = self.create_document(&doc_id, repeated_revision).await.map_err(|e| {
|
|
|
CollaborateError::internal().context(format!("Server crate document failed: {}", e))
|
|
|
})?;
|
|
|
Ok(())
|
|
|
},
|
|
|
Some(handler) => {
|
|
|
- let _ = handler.apply_revisions(user, revisions).await?;
|
|
|
+ let _ = handler.apply_revisions(user, repeated_revision).await?;
|
|
|
Ok(())
|
|
|
},
|
|
|
};
|
|
@@ -99,59 +99,64 @@ impl ServerDocumentManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub async fn handle_document_reset(&self, doc_id: &str, revisions: Vec<Revision>) -> Result<(), CollaborateError> {
|
|
|
+ pub async fn handle_document_reset(
|
|
|
+ &self,
|
|
|
+ doc_id: &str,
|
|
|
+ mut repeated_revision: RepeatedRevisionPB,
|
|
|
+ ) -> Result<(), CollaborateError> {
|
|
|
+ repeated_revision.mut_items().sort_by(|a, b| a.rev_id.cmp(&b.rev_id));
|
|
|
match self.get_document_handler(doc_id).await {
|
|
|
None => {
|
|
|
tracing::warn!("Document:{} doesn't exist, ignore document reset", doc_id);
|
|
|
Ok(())
|
|
|
},
|
|
|
Some(handler) => {
|
|
|
- let _ = handler.apply_document_reset(revisions).await?;
|
|
|
+ let _ = handler.apply_document_reset(repeated_revision).await?;
|
|
|
Ok(())
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async fn get_document_handler(&self, doc_id: &str) -> Option<Arc<OpenDocHandle>> {
|
|
|
- match self.open_doc_map.get(doc_id).map(|ctx| ctx.clone()) {
|
|
|
- Some(edit_doc) => Some(edit_doc),
|
|
|
- None => {
|
|
|
- let f = || async {
|
|
|
- let doc = self.persistence.read_doc(doc_id).await?;
|
|
|
- let handler = self.cache_document(doc).await.map_err(internal_error)?;
|
|
|
- Ok::<Arc<OpenDocHandle>, CollaborateError>(handler)
|
|
|
- };
|
|
|
- match f().await {
|
|
|
- Ok(handler) => Some(handler),
|
|
|
- Err(e) => {
|
|
|
- log::error!("{}", e);
|
|
|
- None
|
|
|
- },
|
|
|
- }
|
|
|
- },
|
|
|
+ if let Some(handler) = self.open_doc_map.read().await.get(doc_id).cloned() {
|
|
|
+ return Some(handler);
|
|
|
}
|
|
|
+
|
|
|
+ let mut write_guard = self.open_doc_map.write().await;
|
|
|
+ let doc = self.persistence.read_doc(doc_id).await.unwrap();
|
|
|
+ let handler = self.create_document_handler(doc).await.map_err(internal_error).unwrap();
|
|
|
+ write_guard.insert(doc_id.to_owned(), handler.clone());
|
|
|
+ drop(write_guard);
|
|
|
+ Some(handler)
|
|
|
}
|
|
|
|
|
|
- #[tracing::instrument(level = "debug", skip(self, revisions), err)]
|
|
|
+ #[tracing::instrument(level = "debug", skip(self, repeated_revision), err)]
|
|
|
async fn create_document(
|
|
|
&self,
|
|
|
doc_id: &str,
|
|
|
- revisions: Vec<Revision>,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
) -> Result<Arc<OpenDocHandle>, CollaborateError> {
|
|
|
- let doc = self.persistence.create_doc(doc_id, revisions).await?;
|
|
|
- let handler = self.cache_document(doc).await?;
|
|
|
+ let doc = self.persistence.create_doc(doc_id, repeated_revision).await?;
|
|
|
+ let handler = self.create_document_handler(doc).await?;
|
|
|
+ self.open_doc_map
|
|
|
+ .write()
|
|
|
+ .await
|
|
|
+ .insert(doc_id.to_owned(), handler.clone());
|
|
|
Ok(handler)
|
|
|
}
|
|
|
|
|
|
- async fn cache_document(&self, doc: DocumentInfo) -> Result<Arc<OpenDocHandle>, CollaborateError> {
|
|
|
- let doc_id = doc.doc_id.clone();
|
|
|
+ async fn create_document_handler(&self, doc: DocumentInfo) -> Result<Arc<OpenDocHandle>, CollaborateError> {
|
|
|
let persistence = self.persistence.clone();
|
|
|
let handle = spawn_blocking(|| OpenDocHandle::new(doc, persistence))
|
|
|
.await
|
|
|
.map_err(|e| CollaborateError::internal().context(format!("Create open doc handler failed: {}", e)))?;
|
|
|
- let handle = Arc::new(handle?);
|
|
|
- self.open_doc_map.insert(doc_id, handle.clone());
|
|
|
- Ok(handle)
|
|
|
+ Ok(Arc::new(handle?))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl std::ops::Drop for ServerDocumentManager {
|
|
|
+ fn drop(&mut self) {
|
|
|
+ log::debug!("ServerDocumentManager was drop");
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -177,24 +182,24 @@ impl OpenDocHandle {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- #[tracing::instrument(level = "debug", skip(self, user, revisions), err)]
|
|
|
+ #[tracing::instrument(level = "debug", skip(self, user, repeated_revision), err)]
|
|
|
async fn apply_revisions(
|
|
|
&self,
|
|
|
user: Arc<dyn RevisionUser>,
|
|
|
- revisions: Vec<Revision>,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
) -> Result<(), CollaborateError> {
|
|
|
let (ret, rx) = oneshot::channel();
|
|
|
let persistence = self.persistence.clone();
|
|
|
self.users.insert(user.user_id(), user.clone());
|
|
|
let msg = DocumentCommand::ApplyRevisions {
|
|
|
user,
|
|
|
- revisions,
|
|
|
+ repeated_revision,
|
|
|
persistence,
|
|
|
ret,
|
|
|
};
|
|
|
|
|
|
- let _ = self.send(msg, rx).await?;
|
|
|
- Ok(())
|
|
|
+ let result = self.send(msg, rx).await?;
|
|
|
+ result
|
|
|
}
|
|
|
|
|
|
#[tracing::instrument(level = "debug", skip(self, user), err)]
|
|
@@ -208,21 +213,21 @@ impl OpenDocHandle {
|
|
|
rev_id,
|
|
|
ret,
|
|
|
};
|
|
|
- let _ = self.send(msg, rx).await?;
|
|
|
- Ok(())
|
|
|
+ let result = self.send(msg, rx).await?;
|
|
|
+ result
|
|
|
}
|
|
|
|
|
|
- #[tracing::instrument(level = "debug", skip(self, revisions), err)]
|
|
|
- async fn apply_document_reset(&self, revisions: Vec<Revision>) -> Result<(), CollaborateError> {
|
|
|
+ #[tracing::instrument(level = "debug", skip(self, repeated_revision), err)]
|
|
|
+ async fn apply_document_reset(&self, repeated_revision: RepeatedRevisionPB) -> Result<(), CollaborateError> {
|
|
|
let (ret, rx) = oneshot::channel();
|
|
|
let persistence = self.persistence.clone();
|
|
|
let msg = DocumentCommand::Reset {
|
|
|
persistence,
|
|
|
- revisions,
|
|
|
+ repeated_revision,
|
|
|
ret,
|
|
|
};
|
|
|
- let _ = self.send(msg, rx).await?;
|
|
|
- Ok(())
|
|
|
+ let result = self.send(msg, rx).await?;
|
|
|
+ result
|
|
|
}
|
|
|
|
|
|
async fn send<T>(&self, msg: DocumentCommand, rx: oneshot::Receiver<T>) -> CollaborateResult<T> {
|
|
@@ -237,6 +242,7 @@ impl OpenDocHandle {
|
|
|
|
|
|
impl std::ops::Drop for OpenDocHandle {
|
|
|
fn drop(&mut self) {
|
|
|
+ //
|
|
|
log::debug!("{} OpenDocHandle was drop", self.doc_id);
|
|
|
}
|
|
|
}
|
|
@@ -245,7 +251,7 @@ impl std::ops::Drop for OpenDocHandle {
|
|
|
enum DocumentCommand {
|
|
|
ApplyRevisions {
|
|
|
user: Arc<dyn RevisionUser>,
|
|
|
- revisions: Vec<Revision>,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
persistence: Arc<dyn DocumentPersistence>,
|
|
|
ret: oneshot::Sender<CollaborateResult<()>>,
|
|
|
},
|
|
@@ -257,7 +263,7 @@ enum DocumentCommand {
|
|
|
},
|
|
|
Reset {
|
|
|
persistence: Arc<dyn DocumentPersistence>,
|
|
|
- revisions: Vec<Revision>,
|
|
|
+ repeated_revision: RepeatedRevisionPB,
|
|
|
ret: oneshot::Sender<CollaborateResult<()>>,
|
|
|
},
|
|
|
}
|
|
@@ -305,13 +311,13 @@ impl DocumentCommandQueue {
|
|
|
match msg {
|
|
|
DocumentCommand::ApplyRevisions {
|
|
|
user,
|
|
|
- revisions,
|
|
|
+ repeated_revision,
|
|
|
persistence,
|
|
|
ret,
|
|
|
} => {
|
|
|
let result = self
|
|
|
.synchronizer
|
|
|
- .sync_revisions(user, revisions, persistence)
|
|
|
+ .sync_revisions(user, repeated_revision, persistence)
|
|
|
.await
|
|
|
.map_err(internal_error);
|
|
|
let _ = ret.send(result);
|
|
@@ -331,12 +337,12 @@ impl DocumentCommandQueue {
|
|
|
},
|
|
|
DocumentCommand::Reset {
|
|
|
persistence,
|
|
|
- revisions,
|
|
|
+ repeated_revision,
|
|
|
ret,
|
|
|
} => {
|
|
|
let result = self
|
|
|
.synchronizer
|
|
|
- .reset(persistence, revisions)
|
|
|
+ .reset(persistence, repeated_revision)
|
|
|
.await
|
|
|
.map_err(internal_error);
|
|
|
let _ = ret.send(result);
|