2021-12-16 22:24:05 +08:00
|
|
|
use async_stream::stream;
|
2021-12-25 21:44:45 +08:00
|
|
|
|
2021-12-16 22:24:05 +08:00
|
|
|
use flowy_collaboration::{
|
2021-12-25 21:44:45 +08:00
|
|
|
entities::revision::Revision,
|
2021-12-16 22:24:05 +08:00
|
|
|
errors::CollaborateError,
|
|
|
|
};
|
|
|
|
use flowy_error::FlowyError;
|
|
|
|
use futures::stream::StreamExt;
|
|
|
|
use lib_ot::{
|
|
|
|
core::{Interval, OperationTransformable},
|
|
|
|
rich_text::{RichTextAttribute, RichTextDelta},
|
|
|
|
};
|
2021-12-25 21:44:45 +08:00
|
|
|
use std::sync::Arc;
|
2021-12-16 22:24:05 +08:00
|
|
|
use tokio::sync::{mpsc, oneshot, RwLock};
|
2021-12-25 23:02:20 +08:00
|
|
|
use flowy_collaboration::document::{Document, history::UndoResult};
|
2021-12-16 22:24:05 +08:00
|
|
|
|
2021-12-18 18:35:45 +08:00
|
|
|
pub(crate) struct EditorCommandQueue {
|
2021-12-16 22:24:05 +08:00
|
|
|
doc_id: String,
|
|
|
|
document: Arc<RwLock<Document>>,
|
2021-12-18 18:35:45 +08:00
|
|
|
receiver: Option<mpsc::UnboundedReceiver<EditorCommand>>,
|
2021-12-16 22:24:05 +08:00
|
|
|
}
|
|
|
|
|
2021-12-18 18:35:45 +08:00
|
|
|
impl EditorCommandQueue {
|
|
|
|
pub(crate) fn new(doc_id: &str, delta: RichTextDelta, receiver: mpsc::UnboundedReceiver<EditorCommand>) -> Self {
|
2021-12-16 22:24:05 +08:00
|
|
|
let document = Arc::new(RwLock::new(Document::from_delta(delta)));
|
|
|
|
Self {
|
|
|
|
doc_id: doc_id.to_owned(),
|
|
|
|
document,
|
|
|
|
receiver: Some(receiver),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) async fn run(mut self) {
|
|
|
|
let mut receiver = self.receiver.take().expect("Should only call once");
|
|
|
|
let stream = stream! {
|
|
|
|
loop {
|
|
|
|
match receiver.recv().await {
|
|
|
|
Some(msg) => yield msg,
|
|
|
|
None => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
stream
|
|
|
|
.for_each(|msg| async {
|
|
|
|
match self.handle_message(msg).await {
|
|
|
|
Ok(_) => {},
|
|
|
|
Err(e) => tracing::debug!("[EditCommandQueue]: {}", e),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2021-12-18 18:35:45 +08:00
|
|
|
async fn handle_message(&self, msg: EditorCommand) -> Result<(), FlowyError> {
|
2021-12-16 22:24:05 +08:00
|
|
|
match msg {
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::ComposeDelta { delta, ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let result = self.composed_delta(delta).await;
|
|
|
|
let _ = ret.send(result);
|
|
|
|
},
|
2021-12-25 21:44:45 +08:00
|
|
|
EditorCommand::ProcessRemoteRevision { revisions, ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let f = || async {
|
2021-12-25 21:44:45 +08:00
|
|
|
let mut new_delta = RichTextDelta::new();
|
|
|
|
for revision in revisions {
|
|
|
|
match RichTextDelta::from_bytes(revision.delta_data) {
|
|
|
|
Ok(delta) => {
|
|
|
|
new_delta = new_delta.compose(&delta)?;
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
let err_msg = format!("Deserialize remote revision failed: {:?}", e);
|
|
|
|
log::error!("{}", err_msg);
|
|
|
|
return Err(CollaborateError::internal().context(err_msg));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-16 22:24:05 +08:00
|
|
|
let read_guard = self.document.read().await;
|
2021-12-25 21:44:45 +08:00
|
|
|
let (server_prime, client_prime) = read_guard.delta().transform(&new_delta)?;
|
2021-12-16 22:24:05 +08:00
|
|
|
drop(read_guard);
|
|
|
|
|
|
|
|
let transform_delta = TransformDeltas {
|
|
|
|
client_prime,
|
|
|
|
server_prime,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok::<TransformDeltas, CollaborateError>(transform_delta)
|
|
|
|
};
|
|
|
|
let _ = ret.send(f().await);
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Insert { index, data, ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let mut write_guard = self.document.write().await;
|
|
|
|
let delta = write_guard.insert(index, data)?;
|
|
|
|
let md5 = write_guard.md5();
|
|
|
|
let _ = ret.send(Ok((delta, md5)));
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Delete { interval, ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let mut write_guard = self.document.write().await;
|
|
|
|
let delta = write_guard.delete(interval)?;
|
|
|
|
let md5 = write_guard.md5();
|
|
|
|
let _ = ret.send(Ok((delta, md5)));
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Format {
|
2021-12-16 22:24:05 +08:00
|
|
|
interval,
|
|
|
|
attribute,
|
|
|
|
ret,
|
|
|
|
} => {
|
|
|
|
let mut write_guard = self.document.write().await;
|
|
|
|
let delta = write_guard.format(interval, attribute)?;
|
|
|
|
let md5 = write_guard.md5();
|
|
|
|
let _ = ret.send(Ok((delta, md5)));
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Replace { interval, data, ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let mut write_guard = self.document.write().await;
|
|
|
|
let delta = write_guard.replace(interval, data)?;
|
|
|
|
let md5 = write_guard.md5();
|
|
|
|
let _ = ret.send(Ok((delta, md5)));
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::CanUndo { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let _ = ret.send(self.document.read().await.can_undo());
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::CanRedo { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let _ = ret.send(self.document.read().await.can_redo());
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Undo { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let result = self.document.write().await.undo();
|
|
|
|
let _ = ret.send(result);
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::Redo { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let result = self.document.write().await.redo();
|
|
|
|
let _ = ret.send(result);
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::ReadDoc { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let data = self.document.read().await.to_json();
|
|
|
|
let _ = ret.send(Ok(data));
|
|
|
|
},
|
2021-12-18 18:35:45 +08:00
|
|
|
EditorCommand::ReadDocDelta { ret } => {
|
2021-12-16 22:24:05 +08:00
|
|
|
let delta = self.document.read().await.delta().clone();
|
|
|
|
let _ = ret.send(Ok(delta));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tracing::instrument(level = "debug", skip(self, delta), fields(compose_result), err)]
|
|
|
|
async fn composed_delta(&self, delta: RichTextDelta) -> Result<String, CollaborateError> {
|
|
|
|
// tracing::debug!("{:?} thread handle_message", thread::current(),);
|
|
|
|
let mut document = self.document.write().await;
|
|
|
|
tracing::Span::current().record(
|
|
|
|
"composed_delta",
|
|
|
|
&format!("doc_id:{} - {}", &self.doc_id, delta.to_json()).as_str(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let _ = document.compose_delta(delta)?;
|
|
|
|
let md5 = document.md5();
|
|
|
|
drop(document);
|
|
|
|
|
|
|
|
Ok(md5)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) type Ret<T> = oneshot::Sender<Result<T, CollaborateError>>;
|
|
|
|
pub(crate) type NewDelta = (RichTextDelta, String);
|
|
|
|
pub(crate) type DocumentMD5 = String;
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2021-12-18 18:35:45 +08:00
|
|
|
pub(crate) enum EditorCommand {
|
2021-12-16 22:24:05 +08:00
|
|
|
ComposeDelta {
|
|
|
|
delta: RichTextDelta,
|
|
|
|
ret: Ret<DocumentMD5>,
|
|
|
|
},
|
|
|
|
ProcessRemoteRevision {
|
2021-12-25 21:44:45 +08:00
|
|
|
revisions: Vec<Revision>,
|
2021-12-16 22:24:05 +08:00
|
|
|
ret: Ret<TransformDeltas>,
|
|
|
|
},
|
|
|
|
Insert {
|
|
|
|
index: usize,
|
|
|
|
data: String,
|
|
|
|
ret: Ret<NewDelta>,
|
|
|
|
},
|
|
|
|
Delete {
|
|
|
|
interval: Interval,
|
|
|
|
ret: Ret<NewDelta>,
|
|
|
|
},
|
|
|
|
Format {
|
|
|
|
interval: Interval,
|
|
|
|
attribute: RichTextAttribute,
|
|
|
|
ret: Ret<NewDelta>,
|
|
|
|
},
|
|
|
|
|
|
|
|
Replace {
|
|
|
|
interval: Interval,
|
|
|
|
data: String,
|
|
|
|
ret: Ret<NewDelta>,
|
|
|
|
},
|
|
|
|
CanUndo {
|
|
|
|
ret: oneshot::Sender<bool>,
|
|
|
|
},
|
|
|
|
CanRedo {
|
|
|
|
ret: oneshot::Sender<bool>,
|
|
|
|
},
|
|
|
|
Undo {
|
|
|
|
ret: Ret<UndoResult>,
|
|
|
|
},
|
|
|
|
Redo {
|
|
|
|
ret: Ret<UndoResult>,
|
|
|
|
},
|
|
|
|
ReadDoc {
|
|
|
|
ret: Ret<String>,
|
|
|
|
},
|
|
|
|
ReadDocDelta {
|
|
|
|
ret: Ret<RichTextDelta>,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct TransformDeltas {
|
|
|
|
pub client_prime: RichTextDelta,
|
|
|
|
pub server_prime: RichTextDelta,
|
|
|
|
}
|