mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
describe the delta interaction between client and server
This commit is contained in:
parent
c872226b44
commit
d0111e30dc
@ -94,14 +94,18 @@ async fn delta_sync_with_server_push_delta() {
|
||||
// ◀─────────────────┤ start ws connection
|
||||
// │ │
|
||||
// ◀─────────────────┤ notify with rev: 1
|
||||
// │ │
|
||||
// ┌───────────────────┐ │ │ ┌──────────────────────────┐
|
||||
// │ops: ["123"] rev: 3│ ├────Push Rev─────▶ │ops: ["abc", "123"] rev: 4│
|
||||
// └───────────────────┘ │ │ └──────────────────────────┘
|
||||
// ┌──────────────────────────┐ │ │ ┌────────────────────┐
|
||||
// │ops: ["abc", "123"] rev: 4│ ◀────Push Rev─────┤ │ops: ["abc"] rev: 4 │
|
||||
// └──────────────────────────┘ │ │ └────────────────────┘
|
||||
// │ │
|
||||
// ┌───────────────────┐ │ │
|
||||
// │ops: ["123"] rev: 3│ ├────Push Rev─────▶ transform
|
||||
// └───────────────────┘ │ │ ┌──────────────────────────┐
|
||||
// │ │ │ops: ["abc", "123"] rev: 4│
|
||||
// │ │ └──────────────────────────┘
|
||||
// │ │ ┌────────────────────────────────┐
|
||||
// compose ◀────Push Rev─────┤ │ops: ["abc", "retain 3"] rev: 4 │
|
||||
// │ │ └────────────────────────────────┘
|
||||
// ┌──────────────────────────┐ │
|
||||
// │ops: ["abc", "123"] rev: 4│ │
|
||||
// └──────────────────────────┘ │
|
||||
// │ │
|
||||
#[actix_rt::test]
|
||||
async fn delta_sync_while_local_rev_less_than_server_rev() {
|
||||
let test = DocumentTest::new().await;
|
||||
@ -120,6 +124,31 @@ async fn delta_sync_while_local_rev_less_than_server_rev() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
// ┌─────────┐ ┌─────────┐
|
||||
// │ Server │ │ Client │
|
||||
// └─────────┘ └─────────┘
|
||||
// ┌───────────────────┐ │ │
|
||||
// │ops: ["123"] rev: 1│ │ │
|
||||
// └───────────────────┘ │ │
|
||||
// ◀── http request ─┤ Open doc
|
||||
// │ │
|
||||
// │ │ ┌───────────────┐
|
||||
// ├──http response──┼──▶│ops: [123] rev:│
|
||||
// │ │ └───────────────┘
|
||||
// │ │ ┌──────────────────────────────────┐
|
||||
// │ │ │ops: ["123","abc", "efg"] rev: 3 │
|
||||
// │ │ └──────────────────────────────────┘
|
||||
// ◀─────────────────┤ start ws connection
|
||||
// │ │
|
||||
// ◀─────────────────┤ notify with rev: 3
|
||||
// │ │
|
||||
// ├────Pull Rev─────▶
|
||||
// │ │ ┌──────────────────────────────────┐
|
||||
// compose ◀────Push Rev─────┤ │ops: ["retain 3", "abcefg"] rev: 3│
|
||||
// ┌──────────────────────────────────┐│ │ └──────────────────────────────────┘
|
||||
// │ops: ["123","abc", "efg"] rev: 3 ││ │
|
||||
// └──────────────────────────────────┘│ │
|
||||
#[actix_rt::test]
|
||||
async fn delta_sync_while_local_rev_greater_than_server_rev() {
|
||||
let test = DocumentTest::new().await;
|
||||
|
@ -114,7 +114,7 @@ async fn run_scripts(context: Arc<RwLock<ScriptContext>>, scripts: Vec<DocScript
|
||||
let doc_id = context.read().doc_id.clone();
|
||||
match script {
|
||||
DocScript::ConnectWs => {
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
// sleep(Duration::from_millis(300)).await;
|
||||
let user_session = context.read().user_session.clone();
|
||||
let token = user_session.token().unwrap();
|
||||
let _ = user_session.start_ws_connection(&token).await.unwrap();
|
||||
@ -126,13 +126,12 @@ async fn run_scripts(context: Arc<RwLock<ScriptContext>>, scripts: Vec<DocScript
|
||||
context.read().client_edit_context().insert(index, s).await.unwrap();
|
||||
},
|
||||
DocScript::AssertClient(s) => {
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
let json = context.read().client_edit_context().doc_json().await.unwrap();
|
||||
assert_eq(s, &json);
|
||||
},
|
||||
DocScript::AssertServer(s) => {
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
let pg_pool = context.read().pool.clone();
|
||||
let doc_manager = context.read().doc_manager.clone();
|
||||
let edit_doc = doc_manager.get(&doc_id, pg_pool).await.unwrap().unwrap();
|
||||
|
@ -7,11 +7,11 @@ edition = "2018"
|
||||
[lib]
|
||||
name = "dart_ffi"
|
||||
# this value will change depending on the target os
|
||||
# for iOS it would be `cdylib`
|
||||
# for Macos it would be `cdylib`
|
||||
# for iOS it would be `rlib`
|
||||
# for Macos it would be `rlib`
|
||||
# for android it would be `c-dylib`
|
||||
# default cdylib
|
||||
crate-type = ["cdylib"]
|
||||
# default rlib
|
||||
crate-type = ["rlib"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
|
@ -127,3 +127,14 @@ pub struct RevisionRange {
|
||||
#[pb(index = 3)]
|
||||
pub to_rev_id: i64,
|
||||
}
|
||||
|
||||
impl RevisionRange {
|
||||
pub fn len(&self) -> i64 {
|
||||
debug_assert!(self.to_rev_id >= self.from_rev_id);
|
||||
if self.to_rev_id >= self.from_rev_id {
|
||||
self.to_rev_id - self.from_rev_id
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ impl ClientEditDoc {
|
||||
},
|
||||
WsDataType::PullRev => {
|
||||
let range = RevisionRange::try_from(bytes)?;
|
||||
let revision = self.rev_manager.send_revisions(range).await?;
|
||||
let revision = self.rev_manager.construct_revisions(range).await?;
|
||||
self.ws.send(revision.into());
|
||||
},
|
||||
WsDataType::NewDocUser => {},
|
||||
|
@ -65,7 +65,7 @@ impl RevisionManager {
|
||||
|
||||
pub fn update_rev_id(&self, rev_id: i64) { self.rev_id_counter.set(rev_id); }
|
||||
|
||||
pub async fn send_revisions(&self, range: RevisionRange) -> Result<Revision, DocError> {
|
||||
pub async fn construct_revisions(&self, range: RevisionRange) -> Result<Revision, DocError> {
|
||||
debug_assert!(&range.doc_id == &self.doc_id);
|
||||
let (ret, rx) = oneshot::channel();
|
||||
let sender = self.rev_store.clone();
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
sql_tables::{RevState, RevTableSql},
|
||||
};
|
||||
use async_stream::stream;
|
||||
use dashmap::DashMap;
|
||||
use dashmap::{mapref::one::Ref, DashMap};
|
||||
use flowy_database::ConnectionPool;
|
||||
use flowy_ot::core::{Attributes, Delta, OperationTransformable};
|
||||
use futures::{stream::StreamExt, TryFutureExt};
|
||||
@ -85,7 +85,7 @@ impl RevisionStoreActor {
|
||||
self.handle_revision_acked(rev_id).await;
|
||||
},
|
||||
RevisionCmd::GetRevisions { range, ret } => {
|
||||
let result = revs_in_range(&self.doc_id, self.persistence.clone(), range).await;
|
||||
let result = self.revs_in_range(range).await;
|
||||
let _ = ret.send(result);
|
||||
},
|
||||
RevisionCmd::DocumentDelta { ret } => {
|
||||
@ -150,6 +150,37 @@ impl RevisionStoreActor {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async fn revs_in_range(&self, range: RevisionRange) -> DocResult<Vec<Revision>> {
|
||||
let iter_range = (range.from_rev_id..=range.to_rev_id);
|
||||
let revs = iter_range
|
||||
.flat_map(|rev_id| {
|
||||
//
|
||||
match self.revs.get(&rev_id) {
|
||||
None => None,
|
||||
Some(rev) => Some((&*(*rev)).clone()),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Revision>>();
|
||||
|
||||
debug_assert!(revs.len() == range.len() as usize);
|
||||
|
||||
if revs.len() == range.len() as usize {
|
||||
Ok(revs)
|
||||
} else {
|
||||
let doc_id = self.doc_id.clone();
|
||||
let persistence = self.persistence.clone();
|
||||
let result = spawn_blocking(move || {
|
||||
let conn = &*persistence.pool.get().map_err(internal_error)?;
|
||||
let revisions = persistence.rev_sql.read_rev_tables_with_range(&doc_id, range, conn)?;
|
||||
Ok(revisions)
|
||||
})
|
||||
.await
|
||||
.map_err(internal_error)?;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_document(
|
||||
@ -216,19 +247,6 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
|
||||
.map_err(internal_error)?
|
||||
}
|
||||
|
||||
async fn revs_in_range(doc_id: &str, persistence: Arc<Persistence>, range: RevisionRange) -> DocResult<Vec<Revision>> {
|
||||
let doc_id = doc_id.to_owned();
|
||||
let result = spawn_blocking(move || {
|
||||
let conn = &*persistence.pool.get().map_err(internal_error)?;
|
||||
let revisions = persistence.rev_sql.read_rev_tables_with_range(&doc_id, range, conn)?;
|
||||
Ok(revisions)
|
||||
})
|
||||
.await
|
||||
.map_err(internal_error)?;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
struct Persistence {
|
||||
rev_sql: Arc<RevTableSql>,
|
||||
pool: Arc<ConnectionPool>,
|
||||
|
Loading…
Reference in New Issue
Block a user