Browse Source

add flowy-sync crate

appflowy 3 years ago
parent
commit
3964508cd8
51 changed files with 1029 additions and 954 deletions
  1. 28 0
      backend/Cargo.lock
  2. 1 1
      backend/src/services/document/persistence.rs
  3. 7 7
      backend/src/services/document/ws_actor.rs
  4. 5 5
      backend/src/services/web_socket/entities/message.rs
  5. 1 1
      backend/tests/document_test/edit_script.rs
  6. 16 16
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pb.dart
  7. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbenum.dart
  8. 6 6
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbjson.dart
  9. 58 58
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pb.dart
  10. 16 16
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbenum.dart
  11. 25 25
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbjson.dart
  12. 1 0
      frontend/rust-lib/Cargo.toml
  13. 1 10
      frontend/rust-lib/flowy-core/src/services/persistence/mod.rs
  14. 0 0
      frontend/rust-lib/flowy-core/src/services/persistence/version_2/mod.rs
  15. 1 1
      frontend/rust-lib/flowy-core/src/services/workspace/event_handler.rs
  16. 2 1
      frontend/rust-lib/flowy-document/Cargo.toml
  17. 3 2
      frontend/rust-lib/flowy-document/src/context.rs
  18. 21 18
      frontend/rust-lib/flowy-document/src/controller.rs
  19. 0 5
      frontend/rust-lib/flowy-document/src/core/edit/mod.rs
  20. 59 19
      frontend/rust-lib/flowy-document/src/core/editor.rs
  21. 5 5
      frontend/rust-lib/flowy-document/src/core/mod.rs
  22. 14 9
      frontend/rust-lib/flowy-document/src/core/queue.rs
  23. 0 8
      frontend/rust-lib/flowy-document/src/core/revision/mod.rs
  24. 0 1
      frontend/rust-lib/flowy-document/src/core/revision/snapshot.rs
  25. 65 40
      frontend/rust-lib/flowy-document/src/core/web_socket.rs
  26. 1 4
      frontend/rust-lib/flowy-document/src/lib.rs
  27. 5 11
      frontend/rust-lib/flowy-document/src/ws_receivers.rs
  28. 1 1
      frontend/rust-lib/flowy-document/tests/document/edit_script.rs
  29. 8 8
      frontend/rust-lib/flowy-net/src/local_server/server.rs
  30. 1 0
      frontend/rust-lib/flowy-sdk/Cargo.toml
  31. 6 6
      frontend/rust-lib/flowy-sdk/src/deps_resolve/document_deps.rs
  32. 32 0
      frontend/rust-lib/flowy-sync/Cargo.toml
  33. 7 7
      frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs
  34. 35 30
      frontend/rust-lib/flowy-sync/src/cache/disk/sql_impl.rs
  35. 9 9
      frontend/rust-lib/flowy-sync/src/cache/memory.rs
  36. 18 18
      frontend/rust-lib/flowy-sync/src/cache/mod.rs
  37. 10 0
      frontend/rust-lib/flowy-sync/src/lib.rs
  38. 46 84
      frontend/rust-lib/flowy-sync/src/rev_manager.rs
  39. 85 101
      frontend/rust-lib/flowy-sync/src/ws_manager.rs
  40. 13 13
      frontend/rust-lib/flowy-user/src/protobuf/model/dart_notification.rs
  41. 1 0
      frontend/rust-lib/flowy-user/src/protobuf/proto/dart_notification.proto
  42. 1 1
      shared-lib/flowy-collaboration/src/entities/doc.rs
  43. 19 12
      shared-lib/flowy-collaboration/src/entities/revision.rs
  44. 38 38
      shared-lib/flowy-collaboration/src/entities/ws.rs
  45. 106 106
      shared-lib/flowy-collaboration/src/protobuf/model/revision.rs
  46. 214 213
      shared-lib/flowy-collaboration/src/protobuf/model/ws.rs
  47. 3 3
      shared-lib/flowy-collaboration/src/protobuf/proto/revision.proto
  48. 9 9
      shared-lib/flowy-collaboration/src/protobuf/proto/ws.proto
  49. 12 12
      shared-lib/flowy-collaboration/src/server_document/document_manager.rs
  50. 8 8
      shared-lib/flowy-collaboration/src/server_document/revision_sync.rs
  51. 4 4
      shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

+ 28 - 0
backend/Cargo.lock

@@ -1339,6 +1339,7 @@ dependencies = [
  "flowy-database",
  "flowy-derive",
  "flowy-error",
+ "flowy-sync",
  "futures",
  "futures-util",
  "lib-dispatch",
@@ -1419,6 +1420,7 @@ dependencies = [
  "flowy-database",
  "flowy-document",
  "flowy-net",
+ "flowy-sync",
  "flowy-user",
  "futures-core",
  "lib-dispatch",
@@ -1431,6 +1433,32 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "flowy-sync"
+version = "0.1.0"
+dependencies = [
+ "async-stream",
+ "bytes",
+ "dashmap",
+ "diesel",
+ "diesel_derives",
+ "flowy-collaboration",
+ "flowy-database",
+ "flowy-error",
+ "futures-util",
+ "lib-infra",
+ "lib-ot",
+ "lib-ws",
+ "parking_lot",
+ "protobuf",
+ "serde",
+ "serde_json",
+ "strum",
+ "strum_macros",
+ "tokio",
+ "tracing",
+]
+
 [[package]]
 name = "flowy-test"
 version = "0.1.0"

+ 1 - 1
backend/src/services/document/persistence.rs

@@ -152,7 +152,7 @@ impl DocumentKVPersistence {
 pub fn revisions_to_key_value_items(revisions: Vec<RevisionPB>) -> Result<Vec<KeyValue>, ServerError> {
     let mut items = vec![];
     for revision in revisions {
-        let key = make_revision_key(&revision.doc_id, revision.rev_id);
+        let key = make_revision_key(&revision.object_id, revision.rev_id);
 
         if revision.delta_data.is_empty() {
             return Err(ServerError::internal().context("The delta_data of RevisionPB should not be empty"));

+ 7 - 7
backend/src/services/document/ws_actor.rs

@@ -9,8 +9,8 @@ use backend_service::errors::{internal_error, Result, ServerError};
 
 use flowy_collaboration::{
     protobuf::{
-        DocumentClientWSData as DocumentClientWSDataPB,
-        DocumentClientWSDataType as DocumentClientWSDataTypePB,
+        ClientRevisionWSData as ClientRevisionWSDataPB,
+        ClientRevisionWSDataType as ClientRevisionWSDataTypePB,
         Revision as RevisionPB,
     },
     server_document::{RevisionUser, ServerDocumentManager, SyncResponse},
@@ -72,28 +72,28 @@ impl DocumentWebSocketActor {
 
     async fn handle_client_data(&self, client_data: WSClientData) -> Result<()> {
         let WSClientData { user, socket, data } = client_data;
-        let document_client_data = spawn_blocking(move || parse_from_bytes::<DocumentClientWSDataPB>(&data))
+        let document_client_data = spawn_blocking(move || parse_from_bytes::<ClientRevisionWSDataPB>(&data))
             .await
             .map_err(internal_error)??;
 
         tracing::debug!(
             "[DocumentWebSocketActor]: receive: {}:{}, {:?}",
-            document_client_data.doc_id,
-            document_client_data.id,
+            document_client_data.object_id,
+            document_client_data.data_id,
             document_client_data.ty
         );
 
         let user = Arc::new(HttpDocumentUser { user, socket });
 
         match &document_client_data.ty {
-            DocumentClientWSDataTypePB::ClientPushRev => {
+            ClientRevisionWSDataTypePB::ClientPushRev => {
                 let _ = self
                     .doc_manager
                     .handle_client_revisions(user, document_client_data)
                     .await
                     .map_err(internal_error)?;
             },
-            DocumentClientWSDataTypePB::ClientPing => {
+            ClientRevisionWSDataTypePB::ClientPing => {
                 let _ = self
                     .doc_manager
                     .handle_client_ping(user, document_client_data)

+ 5 - 5
backend/src/services/web_socket/entities/message.rs

@@ -1,6 +1,6 @@
 use actix::Message;
 use bytes::Bytes;
-use flowy_collaboration::entities::ws::{DocumentClientWSData, DocumentServerWSData};
+use flowy_collaboration::entities::ws::{ClientRevisionWSData, ServerRevisionWSData};
 use lib_ws::{WSModule, WebSocketRawMessage};
 use std::convert::TryInto;
 
@@ -14,8 +14,8 @@ impl std::ops::Deref for WebSocketMessage {
     fn deref(&self) -> &Self::Target { &self.0 }
 }
 
-impl std::convert::From<DocumentClientWSData> for WebSocketMessage {
-    fn from(data: DocumentClientWSData) -> Self {
+impl std::convert::From<ClientRevisionWSData> for WebSocketMessage {
+    fn from(data: ClientRevisionWSData) -> Self {
         let bytes: Bytes = data.try_into().unwrap();
         let msg = WebSocketRawMessage {
             module: WSModule::Doc,
@@ -27,8 +27,8 @@ impl std::convert::From<DocumentClientWSData> for WebSocketMessage {
     }
 }
 
-impl std::convert::From<DocumentServerWSData> for WebSocketMessage {
-    fn from(data: DocumentServerWSData) -> Self {
+impl std::convert::From<ServerRevisionWSData> for WebSocketMessage {
+    fn from(data: ServerRevisionWSData) -> Self {
         let bytes: Bytes = data.try_into().unwrap();
         let msg = WebSocketRawMessage {
             module: WSModule::Doc,

+ 1 - 1
backend/tests/document_test/edit_script.rs

@@ -2,7 +2,7 @@
 #![cfg_attr(rustfmt, rustfmt::skip)]
 use std::convert::TryInto;
 use actix_web::web::Data;
-use flowy_document::core::edit::ClientDocumentEditor;
+use flowy_document::core::ClientDocumentEditor;
 use flowy_test::{helper::ViewTest, FlowySDKTest};
 use flowy_user::services::UserSession;
 use futures_util::{stream, stream::StreamExt};

+ 16 - 16
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pb.dart

@@ -20,7 +20,7 @@ class Revision extends $pb.GeneratedMessage {
     ..aInt64(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
     ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deltaData', $pb.PbFieldType.OY)
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'md5')
-    ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
+    ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'objectId')
     ..e<RevType>(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: RevType.DeprecatedLocal, valueOf: RevType.valueOf, enumValues: RevType.values)
     ..aOS(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
     ..hasRequiredFields = false
@@ -32,7 +32,7 @@ class Revision extends $pb.GeneratedMessage {
     $fixnum.Int64? revId,
     $core.List<$core.int>? deltaData,
     $core.String? md5,
-    $core.String? docId,
+    $core.String? objectId,
     RevType? ty,
     $core.String? userId,
   }) {
@@ -49,8 +49,8 @@ class Revision extends $pb.GeneratedMessage {
     if (md5 != null) {
       _result.md5 = md5;
     }
-    if (docId != null) {
-      _result.docId = docId;
+    if (objectId != null) {
+      _result.objectId = objectId;
     }
     if (ty != null) {
       _result.ty = ty;
@@ -118,13 +118,13 @@ class Revision extends $pb.GeneratedMessage {
   void clearMd5() => clearField(4);
 
   @$pb.TagNumber(5)
-  $core.String get docId => $_getSZ(4);
+  $core.String get objectId => $_getSZ(4);
   @$pb.TagNumber(5)
-  set docId($core.String v) { $_setString(4, v); }
+  set objectId($core.String v) { $_setString(4, v); }
   @$pb.TagNumber(5)
-  $core.bool hasDocId() => $_has(4);
+  $core.bool hasObjectId() => $_has(4);
   @$pb.TagNumber(5)
-  void clearDocId() => clearField(5);
+  void clearObjectId() => clearField(5);
 
   @$pb.TagNumber(6)
   RevType get ty => $_getN(5);
@@ -235,7 +235,7 @@ class RevId extends $pb.GeneratedMessage {
 
 class RevisionRange extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RevisionRange', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'objectId')
     ..aInt64(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'start')
     ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'end')
     ..hasRequiredFields = false
@@ -243,13 +243,13 @@ class RevisionRange extends $pb.GeneratedMessage {
 
   RevisionRange._() : super();
   factory RevisionRange({
-    $core.String? docId,
+    $core.String? objectId,
     $fixnum.Int64? start,
     $fixnum.Int64? end,
   }) {
     final _result = create();
-    if (docId != null) {
-      _result.docId = docId;
+    if (objectId != null) {
+      _result.objectId = objectId;
     }
     if (start != null) {
       _result.start = start;
@@ -281,13 +281,13 @@ class RevisionRange extends $pb.GeneratedMessage {
   static RevisionRange? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get docId => $_getSZ(0);
+  $core.String get objectId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) { $_setString(0, v); }
+  set objectId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasDocId() => $_has(0);
+  $core.bool hasObjectId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearDocId() => clearField(1);
+  void clearObjectId() => clearField(1);
 
   @$pb.TagNumber(2)
   $fixnum.Int64 get start => $_getI64(1);

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbenum.dart

@@ -10,11 +10,11 @@ import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
 class RevisionState extends $pb.ProtobufEnum {
-  static const RevisionState Local = RevisionState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Local');
+  static const RevisionState Sync = RevisionState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Sync');
   static const RevisionState Ack = RevisionState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ack');
 
   static const $core.List<RevisionState> values = <RevisionState> [
-    Local,
+    Sync,
     Ack,
   ];
 

+ 6 - 6
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbjson.dart

@@ -12,13 +12,13 @@ import 'dart:typed_data' as $typed_data;
 const RevisionState$json = const {
   '1': 'RevisionState',
   '2': const [
-    const {'1': 'Local', '2': 0},
+    const {'1': 'Sync', '2': 0},
     const {'1': 'Ack', '2': 1},
   ],
 };
 
 /// Descriptor for `RevisionState`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List revisionStateDescriptor = $convert.base64Decode('Cg1SZXZpc2lvblN0YXRlEgkKBUxvY2FsEAASBwoDQWNrEAE=');
+final $typed_data.Uint8List revisionStateDescriptor = $convert.base64Decode('Cg1SZXZpc2lvblN0YXRlEggKBFN5bmMQABIHCgNBY2sQAQ==');
 @$core.Deprecated('Use revTypeDescriptor instead')
 const RevType$json = const {
   '1': 'RevType',
@@ -38,14 +38,14 @@ const Revision$json = const {
     const {'1': 'rev_id', '3': 2, '4': 1, '5': 3, '10': 'revId'},
     const {'1': 'delta_data', '3': 3, '4': 1, '5': 12, '10': 'deltaData'},
     const {'1': 'md5', '3': 4, '4': 1, '5': 9, '10': 'md5'},
-    const {'1': 'doc_id', '3': 5, '4': 1, '5': 9, '10': 'docId'},
+    const {'1': 'object_id', '3': 5, '4': 1, '5': 9, '10': 'objectId'},
     const {'1': 'ty', '3': 6, '4': 1, '5': 14, '6': '.RevType', '10': 'ty'},
     const {'1': 'user_id', '3': 7, '4': 1, '5': 9, '10': 'userId'},
   ],
 };
 
 /// Descriptor for `Revision`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSHQoKZGVsdGFfZGF0YRgDIAEoDFIJZGVsdGFEYXRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eRIXCgd1c2VyX2lkGAcgASgJUgZ1c2VySWQ=');
+final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSHQoKZGVsdGFfZGF0YRgDIAEoDFIJZGVsdGFEYXRhEhAKA21kNRgEIAEoCVIDbWQ1EhsKCW9iamVjdF9pZBgFIAEoCVIIb2JqZWN0SWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eRIXCgd1c2VyX2lkGAcgASgJUgZ1c2VySWQ=');
 @$core.Deprecated('Use repeatedRevisionDescriptor instead')
 const RepeatedRevision$json = const {
   '1': 'RepeatedRevision',
@@ -70,11 +70,11 @@ final $typed_data.Uint8List revIdDescriptor = $convert.base64Decode('CgVSZXZJZBI
 const RevisionRange$json = const {
   '1': 'RevisionRange',
   '2': const [
-    const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
+    const {'1': 'object_id', '3': 1, '4': 1, '5': 9, '10': 'objectId'},
     const {'1': 'start', '3': 2, '4': 1, '5': 3, '10': 'start'},
     const {'1': 'end', '3': 3, '4': 1, '5': 3, '10': 'end'},
   ],
 };
 
 /// Descriptor for `RevisionRange`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List revisionRangeDescriptor = $convert.base64Decode('Cg1SZXZpc2lvblJhbmdlEhUKBmRvY19pZBgBIAEoCVIFZG9jSWQSFAoFc3RhcnQYAiABKANSBXN0YXJ0EhAKA2VuZBgDIAEoA1IDZW5k');
+final $typed_data.Uint8List revisionRangeDescriptor = $convert.base64Decode('Cg1SZXZpc2lvblJhbmdlEhsKCW9iamVjdF9pZBgBIAEoCVIIb2JqZWN0SWQSFAoFc3RhcnQYAiABKANSBXN0YXJ0EhAKA2VuZBgDIAEoA1IDZW5k');

+ 58 - 58
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pb.dart

@@ -15,25 +15,25 @@ import 'ws.pbenum.dart';
 
 export 'ws.pbenum.dart';
 
-class DocumentClientWSData extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentClientWSData', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..e<DocumentClientWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: DocumentClientWSDataType.ClientPushRev, valueOf: DocumentClientWSDataType.valueOf, enumValues: DocumentClientWSDataType.values)
+class ClientRevisionWSData extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ClientRevisionWSData', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'objectId')
+    ..e<ClientRevisionWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: ClientRevisionWSDataType.ClientPushRev, valueOf: ClientRevisionWSDataType.valueOf, enumValues: ClientRevisionWSDataType.values)
     ..aOM<$0.RepeatedRevision>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
-    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
+    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataId')
     ..hasRequiredFields = false
   ;
 
-  DocumentClientWSData._() : super();
-  factory DocumentClientWSData({
-    $core.String? docId,
-    DocumentClientWSDataType? ty,
+  ClientRevisionWSData._() : super();
+  factory ClientRevisionWSData({
+    $core.String? objectId,
+    ClientRevisionWSDataType? ty,
     $0.RepeatedRevision? revisions,
-    $core.String? id,
+    $core.String? dataId,
   }) {
     final _result = create();
-    if (docId != null) {
-      _result.docId = docId;
+    if (objectId != null) {
+      _result.objectId = objectId;
     }
     if (ty != null) {
       _result.ty = ty;
@@ -41,45 +41,45 @@ class DocumentClientWSData extends $pb.GeneratedMessage {
     if (revisions != null) {
       _result.revisions = revisions;
     }
-    if (id != null) {
-      _result.id = id;
+    if (dataId != null) {
+      _result.dataId = dataId;
     }
     return _result;
   }
-  factory DocumentClientWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory DocumentClientWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory ClientRevisionWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ClientRevisionWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  DocumentClientWSData clone() => DocumentClientWSData()..mergeFromMessage(this);
+  ClientRevisionWSData clone() => ClientRevisionWSData()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  DocumentClientWSData copyWith(void Function(DocumentClientWSData) updates) => super.copyWith((message) => updates(message as DocumentClientWSData)) as DocumentClientWSData; // ignore: deprecated_member_use
+  ClientRevisionWSData copyWith(void Function(ClientRevisionWSData) updates) => super.copyWith((message) => updates(message as ClientRevisionWSData)) as ClientRevisionWSData; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static DocumentClientWSData create() => DocumentClientWSData._();
-  DocumentClientWSData createEmptyInstance() => create();
-  static $pb.PbList<DocumentClientWSData> createRepeated() => $pb.PbList<DocumentClientWSData>();
+  static ClientRevisionWSData create() => ClientRevisionWSData._();
+  ClientRevisionWSData createEmptyInstance() => create();
+  static $pb.PbList<ClientRevisionWSData> createRepeated() => $pb.PbList<ClientRevisionWSData>();
   @$core.pragma('dart2js:noInline')
-  static DocumentClientWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentClientWSData>(create);
-  static DocumentClientWSData? _defaultInstance;
+  static ClientRevisionWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ClientRevisionWSData>(create);
+  static ClientRevisionWSData? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get docId => $_getSZ(0);
+  $core.String get objectId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) { $_setString(0, v); }
+  set objectId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasDocId() => $_has(0);
+  $core.bool hasObjectId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearDocId() => clearField(1);
+  void clearObjectId() => clearField(1);
 
   @$pb.TagNumber(2)
-  DocumentClientWSDataType get ty => $_getN(1);
+  ClientRevisionWSDataType get ty => $_getN(1);
   @$pb.TagNumber(2)
-  set ty(DocumentClientWSDataType v) { setField(2, v); }
+  set ty(ClientRevisionWSDataType v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasTy() => $_has(1);
   @$pb.TagNumber(2)
@@ -97,32 +97,32 @@ class DocumentClientWSData extends $pb.GeneratedMessage {
   $0.RepeatedRevision ensureRevisions() => $_ensure(2);
 
   @$pb.TagNumber(4)
-  $core.String get id => $_getSZ(3);
+  $core.String get dataId => $_getSZ(3);
   @$pb.TagNumber(4)
-  set id($core.String v) { $_setString(3, v); }
+  set dataId($core.String v) { $_setString(3, v); }
   @$pb.TagNumber(4)
-  $core.bool hasId() => $_has(3);
+  $core.bool hasDataId() => $_has(3);
   @$pb.TagNumber(4)
-  void clearId() => clearField(4);
+  void clearDataId() => clearField(4);
 }
 
-class DocumentServerWSData extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentServerWSData', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..e<DocumentServerWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: DocumentServerWSDataType.ServerAck, valueOf: DocumentServerWSDataType.valueOf, enumValues: DocumentServerWSDataType.values)
+class ServerRevisionWSData extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ServerRevisionWSData', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'objectId')
+    ..e<ServerRevisionWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: ServerRevisionWSDataType.ServerAck, valueOf: ServerRevisionWSDataType.valueOf, enumValues: ServerRevisionWSDataType.values)
     ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
     ..hasRequiredFields = false
   ;
 
-  DocumentServerWSData._() : super();
-  factory DocumentServerWSData({
-    $core.String? docId,
-    DocumentServerWSDataType? ty,
+  ServerRevisionWSData._() : super();
+  factory ServerRevisionWSData({
+    $core.String? objectId,
+    ServerRevisionWSDataType? ty,
     $core.List<$core.int>? data,
   }) {
     final _result = create();
-    if (docId != null) {
-      _result.docId = docId;
+    if (objectId != null) {
+      _result.objectId = objectId;
     }
     if (ty != null) {
       _result.ty = ty;
@@ -132,40 +132,40 @@ class DocumentServerWSData extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory DocumentServerWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory DocumentServerWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory ServerRevisionWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ServerRevisionWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  DocumentServerWSData clone() => DocumentServerWSData()..mergeFromMessage(this);
+  ServerRevisionWSData clone() => ServerRevisionWSData()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  DocumentServerWSData copyWith(void Function(DocumentServerWSData) updates) => super.copyWith((message) => updates(message as DocumentServerWSData)) as DocumentServerWSData; // ignore: deprecated_member_use
+  ServerRevisionWSData copyWith(void Function(ServerRevisionWSData) updates) => super.copyWith((message) => updates(message as ServerRevisionWSData)) as ServerRevisionWSData; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static DocumentServerWSData create() => DocumentServerWSData._();
-  DocumentServerWSData createEmptyInstance() => create();
-  static $pb.PbList<DocumentServerWSData> createRepeated() => $pb.PbList<DocumentServerWSData>();
+  static ServerRevisionWSData create() => ServerRevisionWSData._();
+  ServerRevisionWSData createEmptyInstance() => create();
+  static $pb.PbList<ServerRevisionWSData> createRepeated() => $pb.PbList<ServerRevisionWSData>();
   @$core.pragma('dart2js:noInline')
-  static DocumentServerWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentServerWSData>(create);
-  static DocumentServerWSData? _defaultInstance;
+  static ServerRevisionWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ServerRevisionWSData>(create);
+  static ServerRevisionWSData? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get docId => $_getSZ(0);
+  $core.String get objectId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) { $_setString(0, v); }
+  set objectId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasDocId() => $_has(0);
+  $core.bool hasObjectId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearDocId() => clearField(1);
+  void clearObjectId() => clearField(1);
 
   @$pb.TagNumber(2)
-  DocumentServerWSDataType get ty => $_getN(1);
+  ServerRevisionWSDataType get ty => $_getN(1);
   @$pb.TagNumber(2)
-  set ty(DocumentServerWSDataType v) { setField(2, v); }
+  set ty(ServerRevisionWSDataType v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasTy() => $_has(1);
   @$pb.TagNumber(2)

+ 16 - 16
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbenum.dart

@@ -9,37 +9,37 @@
 import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-class DocumentClientWSDataType extends $pb.ProtobufEnum {
-  static const DocumentClientWSDataType ClientPushRev = DocumentClientWSDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ClientPushRev');
-  static const DocumentClientWSDataType ClientPing = DocumentClientWSDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ClientPing');
+class ClientRevisionWSDataType extends $pb.ProtobufEnum {
+  static const ClientRevisionWSDataType ClientPushRev = ClientRevisionWSDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ClientPushRev');
+  static const ClientRevisionWSDataType ClientPing = ClientRevisionWSDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ClientPing');
 
-  static const $core.List<DocumentClientWSDataType> values = <DocumentClientWSDataType> [
+  static const $core.List<ClientRevisionWSDataType> values = <ClientRevisionWSDataType> [
     ClientPushRev,
     ClientPing,
   ];
 
-  static final $core.Map<$core.int, DocumentClientWSDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static DocumentClientWSDataType? valueOf($core.int value) => _byValue[value];
+  static final $core.Map<$core.int, ClientRevisionWSDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ClientRevisionWSDataType? valueOf($core.int value) => _byValue[value];
 
-  const DocumentClientWSDataType._($core.int v, $core.String n) : super(v, n);
+  const ClientRevisionWSDataType._($core.int v, $core.String n) : super(v, n);
 }
 
-class DocumentServerWSDataType extends $pb.ProtobufEnum {
-  static const DocumentServerWSDataType ServerAck = DocumentServerWSDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerAck');
-  static const DocumentServerWSDataType ServerPushRev = DocumentServerWSDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerPushRev');
-  static const DocumentServerWSDataType ServerPullRev = DocumentServerWSDataType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerPullRev');
-  static const DocumentServerWSDataType UserConnect = DocumentServerWSDataType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserConnect');
+class ServerRevisionWSDataType extends $pb.ProtobufEnum {
+  static const ServerRevisionWSDataType ServerAck = ServerRevisionWSDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerAck');
+  static const ServerRevisionWSDataType ServerPushRev = ServerRevisionWSDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerPushRev');
+  static const ServerRevisionWSDataType ServerPullRev = ServerRevisionWSDataType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ServerPullRev');
+  static const ServerRevisionWSDataType UserConnect = ServerRevisionWSDataType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserConnect');
 
-  static const $core.List<DocumentServerWSDataType> values = <DocumentServerWSDataType> [
+  static const $core.List<ServerRevisionWSDataType> values = <ServerRevisionWSDataType> [
     ServerAck,
     ServerPushRev,
     ServerPullRev,
     UserConnect,
   ];
 
-  static final $core.Map<$core.int, DocumentServerWSDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static DocumentServerWSDataType? valueOf($core.int value) => _byValue[value];
+  static final $core.Map<$core.int, ServerRevisionWSDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ServerRevisionWSDataType? valueOf($core.int value) => _byValue[value];
 
-  const DocumentServerWSDataType._($core.int v, $core.String n) : super(v, n);
+  const ServerRevisionWSDataType._($core.int v, $core.String n) : super(v, n);
 }
 

+ 25 - 25
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbjson.dart

@@ -8,20 +8,20 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use documentClientWSDataTypeDescriptor instead')
-const DocumentClientWSDataType$json = const {
-  '1': 'DocumentClientWSDataType',
+@$core.Deprecated('Use clientRevisionWSDataTypeDescriptor instead')
+const ClientRevisionWSDataType$json = const {
+  '1': 'ClientRevisionWSDataType',
   '2': const [
     const {'1': 'ClientPushRev', '2': 0},
     const {'1': 'ClientPing', '2': 1},
   ],
 };
 
-/// Descriptor for `DocumentClientWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List documentClientWSDataTypeDescriptor = $convert.base64Decode('ChhEb2N1bWVudENsaWVudFdTRGF0YVR5cGUSEQoNQ2xpZW50UHVzaFJldhAAEg4KCkNsaWVudFBpbmcQAQ==');
-@$core.Deprecated('Use documentServerWSDataTypeDescriptor instead')
-const DocumentServerWSDataType$json = const {
-  '1': 'DocumentServerWSDataType',
+/// Descriptor for `ClientRevisionWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List clientRevisionWSDataTypeDescriptor = $convert.base64Decode('ChhDbGllbnRSZXZpc2lvbldTRGF0YVR5cGUSEQoNQ2xpZW50UHVzaFJldhAAEg4KCkNsaWVudFBpbmcQAQ==');
+@$core.Deprecated('Use serverRevisionWSDataTypeDescriptor instead')
+const ServerRevisionWSDataType$json = const {
+  '1': 'ServerRevisionWSDataType',
   '2': const [
     const {'1': 'ServerAck', '2': 0},
     const {'1': 'ServerPushRev', '2': 1},
@@ -30,33 +30,33 @@ const DocumentServerWSDataType$json = const {
   ],
 };
 
-/// Descriptor for `DocumentServerWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List documentServerWSDataTypeDescriptor = $convert.base64Decode('ChhEb2N1bWVudFNlcnZlcldTRGF0YVR5cGUSDQoJU2VydmVyQWNrEAASEQoNU2VydmVyUHVzaFJldhABEhEKDVNlcnZlclB1bGxSZXYQAhIPCgtVc2VyQ29ubmVjdBAD');
-@$core.Deprecated('Use documentClientWSDataDescriptor instead')
-const DocumentClientWSData$json = const {
-  '1': 'DocumentClientWSData',
+/// Descriptor for `ServerRevisionWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List serverRevisionWSDataTypeDescriptor = $convert.base64Decode('ChhTZXJ2ZXJSZXZpc2lvbldTRGF0YVR5cGUSDQoJU2VydmVyQWNrEAASEQoNU2VydmVyUHVzaFJldhABEhEKDVNlcnZlclB1bGxSZXYQAhIPCgtVc2VyQ29ubmVjdBAD');
+@$core.Deprecated('Use clientRevisionWSDataDescriptor instead')
+const ClientRevisionWSData$json = const {
+  '1': 'ClientRevisionWSData',
   '2': const [
-    const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
-    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.DocumentClientWSDataType', '10': 'ty'},
+    const {'1': 'object_id', '3': 1, '4': 1, '5': 9, '10': 'objectId'},
+    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.ClientRevisionWSDataType', '10': 'ty'},
     const {'1': 'revisions', '3': 3, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'},
-    const {'1': 'id', '3': 4, '4': 1, '5': 9, '10': 'id'},
+    const {'1': 'data_id', '3': 4, '4': 1, '5': 9, '10': 'dataId'},
   ],
 };
 
-/// Descriptor for `DocumentClientWSData`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List documentClientWSDataDescriptor = $convert.base64Decode('ChREb2N1bWVudENsaWVudFdTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEikKAnR5GAIgASgOMhkuRG9jdW1lbnRDbGllbnRXU0RhdGFUeXBlUgJ0eRIvCglyZXZpc2lvbnMYAyABKAsyES5SZXBlYXRlZFJldmlzaW9uUglyZXZpc2lvbnMSDgoCaWQYBCABKAlSAmlk');
-@$core.Deprecated('Use documentServerWSDataDescriptor instead')
-const DocumentServerWSData$json = const {
-  '1': 'DocumentServerWSData',
+/// Descriptor for `ClientRevisionWSData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List clientRevisionWSDataDescriptor = $convert.base64Decode('ChRDbGllbnRSZXZpc2lvbldTRGF0YRIbCglvYmplY3RfaWQYASABKAlSCG9iamVjdElkEikKAnR5GAIgASgOMhkuQ2xpZW50UmV2aXNpb25XU0RhdGFUeXBlUgJ0eRIvCglyZXZpc2lvbnMYAyABKAsyES5SZXBlYXRlZFJldmlzaW9uUglyZXZpc2lvbnMSFwoHZGF0YV9pZBgEIAEoCVIGZGF0YUlk');
+@$core.Deprecated('Use serverRevisionWSDataDescriptor instead')
+const ServerRevisionWSData$json = const {
+  '1': 'ServerRevisionWSData',
   '2': const [
-    const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
-    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.DocumentServerWSDataType', '10': 'ty'},
+    const {'1': 'object_id', '3': 1, '4': 1, '5': 9, '10': 'objectId'},
+    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.ServerRevisionWSDataType', '10': 'ty'},
     const {'1': 'data', '3': 3, '4': 1, '5': 12, '10': 'data'},
   ],
 };
 
-/// Descriptor for `DocumentServerWSData`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List documentServerWSDataDescriptor = $convert.base64Decode('ChREb2N1bWVudFNlcnZlcldTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEikKAnR5GAIgASgOMhkuRG9jdW1lbnRTZXJ2ZXJXU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRh');
+/// Descriptor for `ServerRevisionWSData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List serverRevisionWSDataDescriptor = $convert.base64Decode('ChRTZXJ2ZXJSZXZpc2lvbldTRGF0YRIbCglvYmplY3RfaWQYASABKAlSCG9iamVjdElkEikKAnR5GAIgASgOMhkuU2VydmVyUmV2aXNpb25XU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRh');
 @$core.Deprecated('Use newDocumentUserDescriptor instead')
 const NewDocumentUser$json = const {
   '1': 'NewDocumentUser',

+ 1 - 0
frontend/rust-lib/Cargo.toml

@@ -13,6 +13,7 @@ members = [
   "dart-notify",
   "flowy-document",
   "flowy-error",
+  "flowy-sync",
 ]
 
 [profile.dev]

+ 1 - 10
frontend/rust-lib/flowy-core/src/services/persistence/mod.rs

@@ -1,4 +1,5 @@
 mod version_1;
+mod version_2;
 
 use std::sync::Arc;
 pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*};
@@ -63,14 +64,4 @@ impl FlowyCorePersistence {
         let conn = self.database.db_connection()?;
         conn.immediate_transaction::<_, FlowyError, _>(|| f(Box::new(V1Transaction(&conn))))
     }
-
-    // pub fn scope_transaction<F, O>(&self, f: F) -> FlowyResult<O>
-    // where
-    //     F: for<'a> FnOnce(Box<dyn FlowyCorePersistenceTransaction + 'a>) ->
-    // FlowyResult<O>, {
-    //     match thread::scope(|_s| self.begin_transaction(f)) {
-    //         Ok(result) => result,
-    //         Err(e) => Err(FlowyError::internal().context(e)),
-    //     }
-    // }
 }

+ 0 - 0
frontend/rust-lib/flowy-core/src/services/persistence/version_2/mod.rs


+ 1 - 1
frontend/rust-lib/flowy-core/src/services/workspace/event_handler.rs

@@ -9,7 +9,7 @@ use flowy_core_data_model::entities::{
     view::View,
     workspace::{CurrentWorkspaceSetting, QueryWorkspaceRequest, RepeatedWorkspace, WorkspaceId, *},
 };
-use flowy_error::FlowyResult;
+
 use lib_dispatch::prelude::{data_result, Data, DataResult, Unit};
 use std::{convert::TryInto, sync::Arc};
 

+ 2 - 1
frontend/rust-lib/flowy-document/Cargo.toml

@@ -16,6 +16,7 @@ lib-infra = { path = "../../../shared-lib/lib-infra" }
 derive_more = {version = "0.99", features = ["display"]}
 lib-dispatch = { path = "../lib-dispatch" }
 flowy-database = { path = "../flowy-database" }
+flowy-sync = { path = "../flowy-sync" }
 flowy-error = { path = "../flowy-error", features = ["collaboration", "ot", "backend", "serde", "db"] }
 dart-notify = { path = "../dart-notify" }
 
@@ -53,4 +54,4 @@ rand = "0.7.3"
 
 [features]
 http_server = []
-flowy_unit_test = ["lib-ot/flowy_unit_test"]
+flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-sync/flowy_unit_test"]

+ 3 - 2
frontend/rust-lib/flowy-document/src/context.rs

@@ -1,10 +1,11 @@
 use crate::{
     controller::DocumentController,
-    core::{DocumentWSReceivers, DocumentWebSocket},
     errors::FlowyError,
+    ws_receivers::DocumentWSReceivers,
     DocumentCloudService,
 };
 use flowy_database::ConnectionPool;
+use flowy_sync::RevisionWebSocket;
 use std::sync::Arc;
 
 pub trait DocumentUser: Send + Sync {
@@ -23,7 +24,7 @@ impl DocumentContext {
     pub fn new(
         user: Arc<dyn DocumentUser>,
         ws_receivers: Arc<DocumentWSReceivers>,
-        ws_sender: Arc<dyn DocumentWebSocket>,
+        ws_sender: Arc<dyn RevisionWebSocket>,
         cloud_service: Arc<dyn DocumentCloudService>,
     ) -> DocumentContext {
         let doc_ctrl = Arc::new(DocumentController::new(

+ 21 - 18
frontend/rust-lib/flowy-document/src/controller.rs

@@ -1,30 +1,26 @@
 use crate::{
     context::DocumentUser,
-    core::{
-        edit::ClientDocumentEditor,
-        revision::{DocumentRevisionCache, DocumentRevisionManager, RevisionServer},
-        DocumentWSReceivers,
-        DocumentWebSocket,
-        WSStateReceiver,
-    },
+    core::ClientDocumentEditor,
     errors::FlowyError,
+    ws_receivers::DocumentWSReceivers,
     DocumentCloudService,
 };
 use bytes::Bytes;
 use dashmap::DashMap;
 use flowy_collaboration::entities::{
-    doc::{DocumentDelta, DocumentId, DocumentInfo},
-    revision::RepeatedRevision,
+    doc::{DocumentDelta, DocumentId},
+    revision::{md5, RepeatedRevision, Revision},
 };
 use flowy_database::ConnectionPool;
 use flowy_error::FlowyResult;
+use flowy_sync::{RevisionCache, RevisionCloudService, RevisionManager, RevisionWebSocket, WSStateReceiver};
 use lib_infra::future::FutureResult;
 use std::sync::Arc;
 
 pub struct DocumentController {
     cloud_service: Arc<dyn DocumentCloudService>,
     ws_receivers: Arc<DocumentWSReceivers>,
-    ws_sender: Arc<dyn DocumentWebSocket>,
+    ws_sender: Arc<dyn RevisionWebSocket>,
     open_cache: Arc<OpenDocCache>,
     user: Arc<dyn DocumentUser>,
 }
@@ -34,7 +30,7 @@ impl DocumentController {
         cloud_service: Arc<dyn DocumentCloudService>,
         user: Arc<dyn DocumentUser>,
         ws_receivers: Arc<DocumentWSReceivers>,
-        ws_sender: Arc<dyn DocumentWebSocket>,
+        ws_sender: Arc<dyn RevisionWebSocket>,
     ) -> Self {
         let open_cache = Arc::new(OpenDocCache::new());
         Self {
@@ -93,7 +89,7 @@ impl DocumentController {
         let doc_id = doc_id.as_ref().to_owned();
         let db_pool = self.user.db_pool()?;
         let rev_manager = self.make_rev_manager(&doc_id, db_pool)?;
-        let _ = rev_manager.reset_document(revisions).await?;
+        let _ = rev_manager.reset_object(revisions).await?;
         Ok(())
     }
 
@@ -127,10 +123,10 @@ impl DocumentController {
         Ok(doc_editor)
     }
 
-    fn make_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<DocumentRevisionManager, FlowyError> {
+    fn make_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
         let user_id = self.user.user_id()?;
-        let cache = Arc::new(DocumentRevisionCache::new(&user_id, doc_id, pool));
-        Ok(DocumentRevisionManager::new(&user_id, doc_id, cache))
+        let cache = Arc::new(RevisionCache::new(&user_id, doc_id, pool));
+        Ok(RevisionManager::new(&user_id, doc_id, cache))
     }
 }
 
@@ -139,19 +135,26 @@ struct RevisionServerImpl {
     server: Arc<dyn DocumentCloudService>,
 }
 
-impl RevisionServer for RevisionServerImpl {
+impl RevisionCloudService for RevisionServerImpl {
     #[tracing::instrument(level = "debug", skip(self))]
-    fn fetch_document(&self, doc_id: &str) -> FutureResult<DocumentInfo, FlowyError> {
+    fn fetch_object(&self, user_id: &str, doc_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
         let params = DocumentId {
             doc_id: doc_id.to_string(),
         };
         let server = self.server.clone();
         let token = self.token.clone();
+        let user_id = user_id.to_string();
 
         FutureResult::new(async move {
             match server.read_document(&token, params).await? {
                 None => Err(FlowyError::record_not_found().context("Remote doesn't have this document")),
-                Some(doc) => Ok(doc),
+                Some(doc) => {
+                    let delta_data = Bytes::from(doc.text.clone());
+                    let doc_md5 = md5(&delta_data);
+                    let revision =
+                        Revision::new(&doc.doc_id, doc.base_rev_id, doc.rev_id, delta_data, &user_id, doc_md5);
+                    Ok(vec![revision])
+                },
             }
         })
     }

+ 0 - 5
frontend/rust-lib/flowy-document/src/core/edit/mod.rs

@@ -1,5 +0,0 @@
-mod editor;
-mod queue;
-
-pub use editor::*;
-pub(crate) use queue::*;

+ 59 - 19
frontend/rust-lib/flowy-document/src/core/edit/editor.rs → frontend/rust-lib/flowy-document/src/core/editor.rs

@@ -1,21 +1,25 @@
 use crate::{
     context::DocumentUser,
-    core::{
-        web_socket::{make_document_ws_manager, DocumentWebSocketManager, EditorCommandSender},
-        DocumentRevisionManager,
-        DocumentWSReceiver,
-        DocumentWebSocket,
-        EditorCommand,
-        EditorCommandQueue,
-        RevisionServer,
-    },
+    core::{make_document_ws_manager, EditorCommand, EditorCommandQueue, EditorCommandSender},
     errors::FlowyError,
+    ws_receivers::DocumentWSReceiver,
 };
 use bytes::Bytes;
-use flowy_collaboration::errors::CollaborateResult;
+use flowy_collaboration::{
+    entities::{doc::DocumentInfo, revision::Revision},
+    errors::CollaborateResult,
+    util::make_delta_from_revisions,
+};
 use flowy_error::{internal_error, FlowyResult};
+use flowy_sync::{
+    RevisionCloudService,
+    RevisionManager,
+    RevisionObjectBuilder,
+    RevisionWebSocket,
+    RevisionWebSocketManager,
+};
 use lib_ot::{
-    core::Interval,
+    core::{Interval, Operation},
     rich_text::{RichTextAttribute, RichTextDelta},
 };
 use std::sync::Arc;
@@ -24,8 +28,8 @@ use tokio::sync::{mpsc, oneshot};
 pub struct ClientDocumentEditor {
     pub doc_id: String,
     #[allow(dead_code)]
-    rev_manager: Arc<DocumentRevisionManager>,
-    ws_manager: Arc<DocumentWebSocketManager>,
+    rev_manager: Arc<RevisionManager>,
+    ws_manager: Arc<RevisionWebSocketManager>,
     edit_cmd_tx: EditorCommandSender,
 }
 
@@ -33,11 +37,12 @@ impl ClientDocumentEditor {
     pub(crate) async fn new(
         doc_id: &str,
         user: Arc<dyn DocumentUser>,
-        mut rev_manager: DocumentRevisionManager,
-        ws: Arc<dyn DocumentWebSocket>,
-        server: Arc<dyn RevisionServer>,
+        mut rev_manager: RevisionManager,
+        ws: Arc<dyn RevisionWebSocket>,
+        server: Arc<dyn RevisionCloudService>,
     ) -> FlowyResult<Arc<Self>> {
-        let delta = rev_manager.load_document(server).await?;
+        let document_info = rev_manager.load::<DocumentInfoBuilder>(server).await?;
+        let delta = document_info.delta()?;
         let rev_manager = Arc::new(rev_manager);
         let doc_id = doc_id.to_string();
         let user_id = user.user_id()?;
@@ -167,7 +172,7 @@ impl std::ops::Drop for ClientDocumentEditor {
 // The edit queue will exit after the EditorCommandSender was dropped.
 fn spawn_edit_queue(
     user: Arc<dyn DocumentUser>,
-    rev_manager: Arc<DocumentRevisionManager>,
+    rev_manager: Arc<RevisionManager>,
     delta: RichTextDelta,
 ) -> EditorCommandSender {
     let (sender, receiver) = mpsc::channel(1000);
@@ -194,5 +199,40 @@ impl ClientDocumentEditor {
         Ok(delta)
     }
 
-    pub fn rev_manager(&self) -> Arc<DocumentRevisionManager> { self.rev_manager.clone() }
+    pub fn rev_manager(&self) -> Arc<RevisionManager> { self.rev_manager.clone() }
+}
+
+struct DocumentInfoBuilder();
+impl RevisionObjectBuilder for DocumentInfoBuilder {
+    type Output = DocumentInfo;
+
+    fn build_with_revisions(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
+        let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id();
+        let mut delta = make_delta_from_revisions(revisions)?;
+        correct_delta(&mut delta);
+
+        Result::<DocumentInfo, FlowyError>::Ok(DocumentInfo {
+            doc_id: object_id.to_owned(),
+            text: delta.to_json(),
+            rev_id,
+            base_rev_id,
+        })
+    }
+}
+
+// quill-editor requires the delta should end with '\n' and only contains the
+// insert operation. The function, correct_delta maybe be removed in the future.
+fn correct_delta(delta: &mut RichTextDelta) {
+    if let Some(op) = delta.ops.last() {
+        let op_data = op.get_data();
+        if !op_data.ends_with('\n') {
+            tracing::warn!("The document must end with newline. Correcting it by inserting newline op");
+            delta.ops.push(Operation::Insert("\n".into()));
+        }
+    }
+
+    if let Some(op) = delta.ops.iter().find(|op| !op.is_insert()) {
+        tracing::warn!("The document can only contains insert operations, but found {:?}", op);
+        delta.ops.retain(|op| op.is_insert());
+    }
 }

+ 5 - 5
frontend/rust-lib/flowy-document/src/core/mod.rs

@@ -1,9 +1,9 @@
-pub mod edit;
-pub mod revision;
+mod editor;
+mod queue;
 mod web_socket;
 
-pub use crate::ws_receivers::*;
-pub use edit::*;
-pub use revision::*;
+pub use editor::*;
+pub(crate) use queue::*;
+pub(crate) use web_socket::*;
 
 pub const SYNC_INTERVAL_IN_MILLIS: u64 = 1000;

+ 14 - 9
frontend/rust-lib/flowy-document/src/core/edit/queue.rs → frontend/rust-lib/flowy-document/src/core/queue.rs

@@ -1,7 +1,4 @@
-use crate::{
-    context::DocumentUser,
-    core::{web_socket::EditorCommandReceiver, DocumentRevisionManager},
-};
+use crate::{context::DocumentUser, core::web_socket::EditorCommandReceiver};
 use async_stream::stream;
 use flowy_collaboration::{
     client_document::{history::UndoResult, ClientDocument, NewlineDoc},
@@ -10,6 +7,7 @@ use flowy_collaboration::{
     util::make_delta_from_revisions,
 };
 use flowy_error::FlowyError;
+use flowy_sync::RevisionManager;
 use futures::stream::StreamExt;
 use lib_ot::{
     core::{Interval, OperationTransformable},
@@ -23,14 +21,14 @@ use tokio::sync::{oneshot, RwLock};
 pub(crate) struct EditorCommandQueue {
     document: Arc<RwLock<ClientDocument>>,
     user: Arc<dyn DocumentUser>,
-    rev_manager: Arc<DocumentRevisionManager>,
+    rev_manager: Arc<RevisionManager>,
     receiver: Option<EditorCommandReceiver>,
 }
 
 impl EditorCommandQueue {
     pub(crate) fn new(
         user: Arc<dyn DocumentUser>,
-        rev_manager: Arc<DocumentRevisionManager>,
+        rev_manager: Arc<RevisionManager>,
         delta: RichTextDelta,
         receiver: EditorCommandReceiver,
     ) -> Self {
@@ -88,7 +86,7 @@ impl EditorCommandQueue {
                 }
 
                 let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
-                let doc_id = self.rev_manager.doc_id.clone();
+                let doc_id = self.rev_manager.object_id.clone();
                 let user_id = self.user.user_id()?;
                 let (client_revision, server_revision) = make_client_and_server_revision(
                     &doc_id,
@@ -110,7 +108,7 @@ impl EditorCommandQueue {
 
                 let repeated_revision = RepeatedRevision::new(revisions);
                 assert_eq!(repeated_revision.last().unwrap().md5, md5);
-                let _ = self.rev_manager.reset_document(repeated_revision).await?;
+                let _ = self.rev_manager.reset_object(repeated_revision).await?;
                 let _ = ret.send(Ok(()));
             },
             EditorCommand::TransformRevision { revisions, ret } => {
@@ -204,7 +202,14 @@ impl EditorCommandQueue {
         let delta_data = delta.to_bytes();
         let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
         let user_id = self.user.user_id()?;
-        let revision = Revision::new(&self.rev_manager.doc_id, base_rev_id, rev_id, delta_data, &user_id, md5);
+        let revision = Revision::new(
+            &self.rev_manager.object_id,
+            base_rev_id,
+            rev_id,
+            delta_data,
+            &user_id,
+            md5,
+        );
         let _ = self.rev_manager.add_local_revision(&revision).await?;
         Ok(rev_id.into())
     }

+ 0 - 8
frontend/rust-lib/flowy-document/src/core/revision/mod.rs

@@ -1,8 +0,0 @@
-mod cache;
-mod disk;
-mod manager;
-mod memory;
-mod snapshot;
-
-pub use cache::*;
-pub use manager::*;

+ 0 - 1
frontend/rust-lib/flowy-document/src/core/revision/snapshot.rs

@@ -1 +0,0 @@
-

+ 65 - 40
frontend/rust-lib/flowy-document/src/core/web_socket/mod.rs → frontend/rust-lib/flowy-document/src/core/web_socket.rs

@@ -1,25 +1,27 @@
-mod ws_manager;
-pub use ws_manager::*;
-
-use crate::core::{
-    web_socket::{DocumentWSSinkDataProvider, DocumentWSSteamConsumer},
-    DocumentRevisionManager,
-    DocumentWebSocket,
-    EditorCommand,
-    TransformDeltas,
+use crate::{
+    core::{EditorCommand, TransformDeltas, SYNC_INTERVAL_IN_MILLIS},
+    ws_receivers::DocumentWSReceiver,
 };
+use async_trait::async_trait;
 use bytes::Bytes;
 use flowy_collaboration::{
     entities::{
         revision::{RepeatedRevision, Revision, RevisionRange},
-        ws::{DocumentClientWSData, DocumentServerWSDataType, NewDocumentUser},
+        ws::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSData, ServerRevisionWSDataType},
     },
     errors::CollaborateResult,
 };
 use flowy_error::{internal_error, FlowyError, FlowyResult};
+use flowy_sync::{
+    RevisionManager,
+    RevisionWSSinkDataProvider,
+    RevisionWSSteamConsumer,
+    RevisionWebSocket,
+    RevisionWebSocketManager,
+};
 use lib_infra::future::FutureResult;
 use lib_ws::WSConnectState;
-use std::{collections::VecDeque, convert::TryFrom, sync::Arc};
+use std::{collections::VecDeque, convert::TryFrom, sync::Arc, time::Duration};
 use tokio::sync::{
     broadcast,
     mpsc::{Receiver, Sender},
@@ -34,22 +36,24 @@ pub(crate) async fn make_document_ws_manager(
     doc_id: String,
     user_id: String,
     edit_cmd_tx: EditorCommandSender,
-    rev_manager: Arc<DocumentRevisionManager>,
-    ws_conn: Arc<dyn DocumentWebSocket>,
-) -> Arc<DocumentWebSocketManager> {
+    rev_manager: Arc<RevisionManager>,
+    ws_conn: Arc<dyn RevisionWebSocket>,
+) -> Arc<RevisionWebSocketManager> {
     let shared_sink = Arc::new(SharedWSSinkDataProvider::new(rev_manager.clone()));
     let ws_stream_consumer = Arc::new(DocumentWebSocketSteamConsumerAdapter {
-        doc_id: doc_id.clone(),
+        object_id: doc_id.clone(),
         edit_cmd_tx,
         rev_manager: rev_manager.clone(),
         shared_sink: shared_sink.clone(),
     });
     let data_provider = Arc::new(DocumentWSSinkDataProviderAdapter(shared_sink));
-    let ws_manager = Arc::new(DocumentWebSocketManager::new(
+    let ping_duration = Duration::from_millis(SYNC_INTERVAL_IN_MILLIS);
+    let ws_manager = Arc::new(RevisionWebSocketManager::new(
         &doc_id,
         ws_conn,
         data_provider,
         ws_stream_consumer,
+        ping_duration,
     ));
     listen_document_ws_state(&user_id, &doc_id, ws_manager.scribe_state(), rev_manager);
     ws_manager
@@ -59,7 +63,7 @@ fn listen_document_ws_state(
     _user_id: &str,
     _doc_id: &str,
     mut subscriber: broadcast::Receiver<WSConnectState>,
-    _rev_manager: Arc<DocumentRevisionManager>,
+    _rev_manager: Arc<RevisionManager>,
 ) {
     tokio::spawn(async move {
         while let Ok(state) = subscriber.recv().await {
@@ -74,28 +78,28 @@ fn listen_document_ws_state(
 }
 
 pub(crate) struct DocumentWebSocketSteamConsumerAdapter {
-    pub(crate) doc_id: String,
+    pub(crate) object_id: String,
     pub(crate) edit_cmd_tx: EditorCommandSender,
-    pub(crate) rev_manager: Arc<DocumentRevisionManager>,
+    pub(crate) rev_manager: Arc<RevisionManager>,
     pub(crate) shared_sink: Arc<SharedWSSinkDataProvider>,
 }
 
-impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
+impl RevisionWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
     fn receive_push_revision(&self, bytes: Bytes) -> FutureResult<(), FlowyError> {
         let rev_manager = self.rev_manager.clone();
         let edit_cmd_tx = self.edit_cmd_tx.clone();
         let shared_sink = self.shared_sink.clone();
-        let doc_id = self.doc_id.clone();
+        let object_id = self.object_id.clone();
         FutureResult::new(async move {
             if let Some(server_composed_revision) = handle_remote_revision(edit_cmd_tx, rev_manager, bytes).await? {
-                let data = DocumentClientWSData::from_revisions(&doc_id, vec![server_composed_revision]);
+                let data = ClientRevisionWSData::from_revisions(&object_id, vec![server_composed_revision]);
                 shared_sink.push_back(data).await;
             }
             Ok(())
         })
     }
 
-    fn receive_ack(&self, id: String, ty: DocumentServerWSDataType) -> FutureResult<(), FlowyError> {
+    fn receive_ack(&self, id: String, ty: ServerRevisionWSDataType) -> FutureResult<(), FlowyError> {
         let shared_sink = self.shared_sink.clone();
         FutureResult::new(async move { shared_sink.ack(id, ty).await })
     }
@@ -108,10 +112,10 @@ impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
     fn pull_revisions_in_range(&self, range: RevisionRange) -> FutureResult<(), FlowyError> {
         let rev_manager = self.rev_manager.clone();
         let shared_sink = self.shared_sink.clone();
-        let doc_id = self.doc_id.clone();
+        let object_id = self.object_id.clone();
         FutureResult::new(async move {
             let revisions = rev_manager.get_revisions_in_range(range).await?;
-            let data = DocumentClientWSData::from_revisions(&doc_id, revisions);
+            let data = ClientRevisionWSData::from_revisions(&object_id, revisions);
             shared_sink.push_back(data).await;
             Ok(())
         })
@@ -119,8 +123,8 @@ impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
 }
 
 pub(crate) struct DocumentWSSinkDataProviderAdapter(pub(crate) Arc<SharedWSSinkDataProvider>);
-impl DocumentWSSinkDataProvider for DocumentWSSinkDataProviderAdapter {
-    fn next(&self) -> FutureResult<Option<DocumentClientWSData>, FlowyError> {
+impl RevisionWSSinkDataProvider for DocumentWSSinkDataProviderAdapter {
+    fn next(&self) -> FutureResult<Option<ClientRevisionWSData>, FlowyError> {
         let shared_sink = self.0.clone();
         FutureResult::new(async move { shared_sink.next().await })
     }
@@ -138,7 +142,7 @@ async fn transform_pushed_revisions(
 #[tracing::instrument(level = "debug", skip(edit_cmd_tx, rev_manager, bytes))]
 pub(crate) async fn handle_remote_revision(
     edit_cmd_tx: EditorCommandSender,
-    rev_manager: Arc<DocumentRevisionManager>,
+    rev_manager: Arc<RevisionManager>,
     bytes: Bytes,
 ) -> FlowyResult<Option<Revision>> {
     let mut revisions = RepeatedRevision::try_from(bytes)?.into_inner();
@@ -198,13 +202,13 @@ enum SourceType {
 
 #[derive(Clone)]
 pub(crate) struct SharedWSSinkDataProvider {
-    shared: Arc<RwLock<VecDeque<DocumentClientWSData>>>,
-    rev_manager: Arc<DocumentRevisionManager>,
+    shared: Arc<RwLock<VecDeque<ClientRevisionWSData>>>,
+    rev_manager: Arc<RevisionManager>,
     source_ty: Arc<RwLock<SourceType>>,
 }
 
 impl SharedWSSinkDataProvider {
-    pub(crate) fn new(rev_manager: Arc<DocumentRevisionManager>) -> Self {
+    pub(crate) fn new(rev_manager: Arc<RevisionManager>) -> Self {
         SharedWSSinkDataProvider {
             shared: Arc::new(RwLock::new(VecDeque::new())),
             rev_manager,
@@ -213,11 +217,11 @@ impl SharedWSSinkDataProvider {
     }
 
     #[allow(dead_code)]
-    pub(crate) async fn push_front(&self, data: DocumentClientWSData) { self.shared.write().await.push_front(data); }
+    pub(crate) async fn push_front(&self, data: ClientRevisionWSData) { self.shared.write().await.push_front(data); }
 
-    async fn push_back(&self, data: DocumentClientWSData) { self.shared.write().await.push_back(data); }
+    async fn push_back(&self, data: ClientRevisionWSData) { self.shared.write().await.push_back(data); }
 
-    async fn next(&self) -> FlowyResult<Option<DocumentClientWSData>> {
+    async fn next(&self) -> FlowyResult<Option<ClientRevisionWSData>> {
         let source_ty = self.source_ty.read().await.clone();
         match source_ty {
             SourceType::Shared => match self.shared.read().await.front() {
@@ -226,7 +230,7 @@ impl SharedWSSinkDataProvider {
                     Ok(None)
                 },
                 Some(data) => {
-                    tracing::debug!("[SharedWSSinkDataProvider]: {}:{:?}", data.doc_id, data.ty);
+                    tracing::debug!("[SharedWSSinkDataProvider]: {}:{:?}", data.object_id, data.ty);
                     Ok(Some(data.clone()))
                 },
             },
@@ -238,21 +242,21 @@ impl SharedWSSinkDataProvider {
 
                 match self.rev_manager.next_sync_revision().await? {
                     Some(rev) => {
-                        let doc_id = rev.doc_id.clone();
-                        Ok(Some(DocumentClientWSData::from_revisions(&doc_id, vec![rev])))
+                        let doc_id = rev.object_id.clone();
+                        Ok(Some(ClientRevisionWSData::from_revisions(&doc_id, vec![rev])))
                     },
                     None => {
                         //
-                        let doc_id = self.rev_manager.doc_id.clone();
+                        let doc_id = self.rev_manager.object_id.clone();
                         let latest_rev_id = self.rev_manager.rev_id();
-                        Ok(Some(DocumentClientWSData::ping(&doc_id, latest_rev_id)))
+                        Ok(Some(ClientRevisionWSData::ping(&doc_id, latest_rev_id)))
                     },
                 }
             },
         }
     }
 
-    async fn ack(&self, id: String, _ty: DocumentServerWSDataType) -> FlowyResult<()> {
+    async fn ack(&self, id: String, _ty: ServerRevisionWSDataType) -> FlowyResult<()> {
         // let _ = self.rev_manager.ack_revision(id).await?;
         let source_ty = self.source_ty.read().await.clone();
         match source_ty {
@@ -288,3 +292,24 @@ impl SharedWSSinkDataProvider {
         Ok(())
     }
 }
+
+//  RevisionWebSocketManager registers itself as a DocumentWSReceiver for each
+//  opened document.
+#[async_trait]
+impl DocumentWSReceiver for RevisionWebSocketManager {
+    #[tracing::instrument(level = "debug", skip(self, data), err)]
+    async fn receive_ws_data(&self, data: ServerRevisionWSData) -> Result<(), FlowyError> {
+        let _ = self.ws_passthrough_tx.send(data).await.map_err(|e| {
+            let err_msg = format!("{} passthrough error: {}", self.object_id, e);
+            FlowyError::internal().context(err_msg)
+        })?;
+        Ok(())
+    }
+
+    fn connect_state_changed(&self, state: WSConnectState) {
+        match self.state_passthrough_tx.send(state) {
+            Ok(_) => {},
+            Err(e) => tracing::error!("{}", e),
+        }
+    }
+}

+ 1 - 4
frontend/rust-lib/flowy-document/src/lib.rs

@@ -3,10 +3,7 @@ pub(crate) mod controller;
 pub mod core;
 // mod notify;
 pub mod protobuf;
-mod ws_receivers;
-
-#[macro_use]
-extern crate flowy_database;
+pub mod ws_receivers;
 
 pub mod errors {
     pub use flowy_error::{internal_error, ErrorCode, FlowyError};

+ 5 - 11
frontend/rust-lib/flowy-document/src/ws_receivers.rs

@@ -2,22 +2,16 @@ use crate::errors::FlowyError;
 use async_trait::async_trait;
 use bytes::Bytes;
 use dashmap::DashMap;
-use flowy_collaboration::entities::ws::{DocumentClientWSData, DocumentServerWSData};
+use flowy_collaboration::entities::ws::{ServerRevisionWSData};
 use lib_ws::WSConnectState;
 use std::{convert::TryInto, sync::Arc};
 
 #[async_trait]
 pub(crate) trait DocumentWSReceiver: Send + Sync {
-    async fn receive_ws_data(&self, data: DocumentServerWSData) -> Result<(), FlowyError>;
+    async fn receive_ws_data(&self, data: ServerRevisionWSData) -> Result<(), FlowyError>;
     fn connect_state_changed(&self, state: WSConnectState);
 }
 
-pub type WSStateReceiver = tokio::sync::broadcast::Receiver<WSConnectState>;
-pub trait DocumentWebSocket: Send + Sync {
-    fn send(&self, data: DocumentClientWSData) -> Result<(), FlowyError>;
-    fn subscribe_state_changed(&self) -> WSStateReceiver;
-}
-
 pub struct DocumentWSReceivers {
     // key: the document id
     // value: DocumentWSReceiver
@@ -44,9 +38,9 @@ impl DocumentWSReceivers {
     pub(crate) fn remove(&self, id: &str) { self.receivers.remove(id); }
 
     pub async fn did_receive_data(&self, data: Bytes) {
-        let data: DocumentServerWSData = data.try_into().unwrap();
-        match self.receivers.get(&data.doc_id) {
-            None => tracing::error!("Can't find any source handler for {:?}", data.doc_id),
+        let data: ServerRevisionWSData = data.try_into().unwrap();
+        match self.receivers.get(&data.object_id) {
+            None => tracing::error!("Can't find any source handler for {:?}", data.object_id),
             Some(handler) => match handler.receive_ws_data(data).await {
                 Ok(_) => {},
                 Err(e) => tracing::error!("{}", e),

+ 1 - 1
frontend/rust-lib/flowy-document/tests/document/edit_script.rs

@@ -1,5 +1,5 @@
 use flowy_collaboration::entities::revision::RevisionState;
-use flowy_document::core::{edit::ClientDocumentEditor, SYNC_INTERVAL_IN_MILLIS};
+use flowy_document::core::{ClientDocumentEditor, SYNC_INTERVAL_IN_MILLIS};
 use flowy_test::{helper::ViewTest, FlowySDKTest};
 use lib_ot::{core::Interval, rich_text::RichTextDelta};
 use std::sync::Arc;

+ 8 - 8
frontend/rust-lib/flowy-net/src/local_server/server.rs

@@ -5,10 +5,10 @@ use flowy_collaboration::{
     client_document::default::initial_delta_string,
     entities::{
         doc::{CreateDocParams, DocumentId, DocumentInfo, ResetDocumentParams},
-        ws::{DocumentClientWSData, DocumentClientWSDataType},
+        ws::{ClientRevisionWSData, ClientRevisionWSDataType},
     },
     errors::CollaborateError,
-    protobuf::DocumentClientWSData as DocumentClientWSDataPB,
+    protobuf::ClientRevisionWSData as ClientRevisionWSDataPB,
     server_document::*,
 };
 use flowy_core::module::WorkspaceCloudService;
@@ -105,19 +105,19 @@ impl LocalWebSocketRunner {
 
     async fn handle_message(&self, message: WebSocketRawMessage) -> Result<(), FlowyError> {
         let bytes = Bytes::from(message.data);
-        let client_data = DocumentClientWSData::try_from(bytes).map_err(internal_error)?;
+        let client_data = ClientRevisionWSData::try_from(bytes).map_err(internal_error)?;
         let _ = self.handle_client_data(client_data, "".to_owned()).await?;
         Ok(())
     }
 
     pub async fn handle_client_data(
         &self,
-        client_data: DocumentClientWSData,
+        client_data: ClientRevisionWSData,
         user_id: String,
     ) -> Result<(), CollaborateError> {
         tracing::trace!(
             "[LocalDocumentServer] receive: {}:{}-{:?} ",
-            client_data.doc_id,
+            client_data.object_id,
             client_data.id(),
             client_data.ty,
         );
@@ -127,15 +127,15 @@ impl LocalWebSocketRunner {
             client_ws_sender,
         });
         let ty = client_data.ty.clone();
-        let document_client_data: DocumentClientWSDataPB = client_data.try_into().unwrap();
+        let document_client_data: ClientRevisionWSDataPB = client_data.try_into().unwrap();
         match ty {
-            DocumentClientWSDataType::ClientPushRev => {
+            ClientRevisionWSDataType::ClientPushRev => {
                 let _ = self
                     .doc_manager
                     .handle_client_revisions(user, document_client_data)
                     .await?;
             },
-            DocumentClientWSDataType::ClientPing => {
+            ClientRevisionWSDataType::ClientPing => {
                 let _ = self.doc_manager.handle_client_ping(user, document_client_data).await?;
             },
         }

+ 1 - 0
frontend/rust-lib/flowy-sdk/Cargo.toml

@@ -13,6 +13,7 @@ flowy-net = { path = "../flowy-net" }
 flowy-core = { path = "../flowy-core", default-features = false }
 flowy-database = { path = "../flowy-database" }
 flowy-document = { path = "../flowy-document" }
+flowy-sync = { path = "../flowy-sync" }
 
 tracing = { version = "0.1" }
 log = "0.4.14"

+ 6 - 6
frontend/rust-lib/flowy-sdk/src/deps_resolve/document_deps.rs

@@ -1,11 +1,11 @@
 use backend_service::configuration::ClientServerConfiguration;
 use bytes::Bytes;
-use flowy_collaboration::entities::ws::DocumentClientWSData;
+use flowy_collaboration::entities::ws::ClientRevisionWSData;
 use flowy_database::ConnectionPool;
 use flowy_document::{
     context::DocumentUser,
-    core::{DocumentWSReceivers, DocumentWebSocket, WSStateReceiver},
     errors::{internal_error, FlowyError},
+    ws_receivers::DocumentWSReceivers,
     DocumentCloudService,
 };
 use flowy_net::{
@@ -13,15 +13,15 @@ use flowy_net::{
     local_server::LocalServer,
     ws::connection::FlowyWebSocketConnect,
 };
+use flowy_sync::{RevisionWebSocket, WSStateReceiver};
 use flowy_user::services::UserSession;
-
 use lib_ws::{WSMessageReceiver, WSModule, WebSocketRawMessage};
 use std::{convert::TryInto, path::Path, sync::Arc};
 
 pub struct DocumentDependencies {
     pub user: Arc<dyn DocumentUser>,
     pub ws_receivers: Arc<DocumentWSReceivers>,
-    pub ws_sender: Arc<dyn DocumentWebSocket>,
+    pub ws_sender: Arc<dyn RevisionWebSocket>,
     pub cloud_service: Arc<dyn DocumentCloudService>,
 }
 
@@ -73,8 +73,8 @@ impl DocumentUser for DocumentUserImpl {
 }
 
 struct DocumentWebSocketImpl(Arc<FlowyWebSocketConnect>);
-impl DocumentWebSocket for DocumentWebSocketImpl {
-    fn send(&self, data: DocumentClientWSData) -> Result<(), FlowyError> {
+impl RevisionWebSocket for DocumentWebSocketImpl {
+    fn send(&self, data: ClientRevisionWSData) -> Result<(), FlowyError> {
         let bytes: Bytes = data.try_into().unwrap();
         let msg = WebSocketRawMessage {
             module: WSModule::Doc,

+ 32 - 0
frontend/rust-lib/flowy-sync/Cargo.toml

@@ -0,0 +1,32 @@
+[package]
+name = "flowy-sync"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
+lib-ot = { path = "../../../shared-lib/lib-ot" }
+lib-ws = { path = "../../../shared-lib/lib-ws" }
+lib-infra = { path = "../../../shared-lib/lib-infra" }
+flowy-database = { path = "../flowy-database" }
+flowy-error = { path = "../flowy-error", features = ["collaboration", "ot", "backend", "serde", "db"] }
+diesel = {version = "1.4.8", features = ["sqlite"]}
+diesel_derives = {version = "1.4.1", features = ["sqlite"]}
+protobuf = {version = "2.18.0"}
+tracing = { version = "0.1", features = ["log"] }
+tokio = {version = "1", features = ["sync"]}
+bytes = { version = "1.1" }
+strum = "0.21"
+strum_macros = "0.21"
+dashmap = "4.0"
+parking_lot = "0.11"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = {version = "1.0"}
+futures-util = "0.3.15"
+async-stream = "0.3.2"
+
+
+[features]
+flowy_unit_test = ["lib-ot/flowy_unit_test"]

+ 7 - 7
frontend/rust-lib/flowy-document/src/core/revision/disk/mod.rs → frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs

@@ -1,5 +1,5 @@
 mod sql_impl;
-use crate::core::revision::RevisionRecord;
+use crate::RevisionRecord;
 use diesel::SqliteConnection;
 use flowy_collaboration::entities::revision::RevisionRange;
 pub use sql_impl::*;
@@ -7,24 +7,24 @@ pub use sql_impl::*;
 use flowy_error::FlowyResult;
 use std::fmt::Debug;
 
-pub trait DocumentRevisionDiskCache: Sync + Send {
+pub trait RevisionDiskCache: Sync + Send {
     type Error: Debug;
     fn write_revision_records(
         &self,
-        revisions: Vec<RevisionRecord>,
+        revision_records: Vec<RevisionRecord>,
         conn: &SqliteConnection,
     ) -> Result<(), Self::Error>;
 
     // Read all the records if the rev_ids is None
     fn read_revision_records(
         &self,
-        doc_id: &str,
+        object_id: &str,
         rev_ids: Option<Vec<i64>>,
     ) -> Result<Vec<RevisionRecord>, Self::Error>;
 
     fn read_revision_records_with_range(
         &self,
-        doc_id: &str,
+        object_id: &str,
         range: &RevisionRange,
     ) -> Result<Vec<RevisionRecord>, Self::Error>;
 
@@ -33,10 +33,10 @@ pub trait DocumentRevisionDiskCache: Sync + Send {
     // Delete all the records if the rev_ids is None
     fn delete_revision_records(
         &self,
-        doc_id: &str,
+        object_id: &str,
         rev_ids: Option<Vec<i64>>,
         conn: &SqliteConnection,
     ) -> Result<(), Self::Error>;
 
-    fn reset_document(&self, doc_id: &str, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error>;
+    fn reset_object(&self, object_id: &str, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error>;
 }

+ 35 - 30
frontend/rust-lib/flowy-document/src/core/revision/disk/sql_impl.rs → frontend/rust-lib/flowy-sync/src/cache/disk/sql_impl.rs

@@ -1,4 +1,4 @@
-use crate::core::revision::{disk::DocumentRevisionDiskCache, RevisionRecord};
+use crate::{cache::disk::RevisionDiskCache, RevisionRecord};
 use bytes::Bytes;
 use diesel::{sql_types::Integer, update, SqliteConnection};
 use flowy_collaboration::{
@@ -6,6 +6,7 @@ use flowy_collaboration::{
     util::md5,
 };
 use flowy_database::{
+    impl_sql_integer_expression,
     insert_or_ignore_into,
     prelude::*,
     schema::{rev_table, rev_table::dsl},
@@ -19,35 +20,35 @@ pub struct SQLitePersistence {
     pub(crate) pool: Arc<ConnectionPool>,
 }
 
-impl DocumentRevisionDiskCache for SQLitePersistence {
+impl RevisionDiskCache for SQLitePersistence {
     type Error = FlowyError;
 
     fn write_revision_records(
         &self,
-        revisions: Vec<RevisionRecord>,
+        revision_records: Vec<RevisionRecord>,
         conn: &SqliteConnection,
     ) -> Result<(), Self::Error> {
-        let _ = RevisionTableSql::create(revisions, conn)?;
+        let _ = RevisionTableSql::create(revision_records, conn)?;
         Ok(())
     }
 
     fn read_revision_records(
         &self,
-        doc_id: &str,
+        object_id: &str,
         rev_ids: Option<Vec<i64>>,
     ) -> Result<Vec<RevisionRecord>, Self::Error> {
         let conn = self.pool.get().map_err(internal_error)?;
-        let records = RevisionTableSql::read(&self.user_id, doc_id, rev_ids, &*conn)?;
+        let records = RevisionTableSql::read(&self.user_id, object_id, rev_ids, &*conn)?;
         Ok(records)
     }
 
     fn read_revision_records_with_range(
         &self,
-        doc_id: &str,
+        object_id: &str,
         range: &RevisionRange,
     ) -> Result<Vec<RevisionRecord>, Self::Error> {
         let conn = &*self.pool.get().map_err(internal_error)?;
-        let revisions = RevisionTableSql::read_with_range(&self.user_id, doc_id, range.clone(), conn)?;
+        let revisions = RevisionTableSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?;
         Ok(revisions)
     }
 
@@ -64,18 +65,18 @@ impl DocumentRevisionDiskCache for SQLitePersistence {
 
     fn delete_revision_records(
         &self,
-        doc_id: &str,
+        object_id: &str,
         rev_ids: Option<Vec<i64>>,
         conn: &SqliteConnection,
     ) -> Result<(), Self::Error> {
-        let _ = RevisionTableSql::delete(doc_id, rev_ids, conn)?;
+        let _ = RevisionTableSql::delete(object_id, rev_ids, conn)?;
         Ok(())
     }
 
-    fn reset_document(&self, doc_id: &str, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
+    fn reset_object(&self, object_id: &str, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
         let conn = self.pool.get().map_err(internal_error)?;
         conn.immediate_transaction::<_, FlowyError, _>(|| {
-            let _ = self.delete_revision_records(doc_id, None, &*conn)?;
+            let _ = self.delete_revision_records(object_id, None, &*conn)?;
             let _ = self.write_revision_records(revision_records, &*conn)?;
             Ok(())
         })
@@ -101,7 +102,7 @@ impl RevisionTableSql {
             .map(|record| {
                 let rev_state: RevisionTableState = record.state.into();
                 (
-                    dsl::doc_id.eq(record.revision.doc_id),
+                    dsl::doc_id.eq(record.revision.object_id),
                     dsl::base_rev_id.eq(record.revision.base_rev_id),
                     dsl::rev_id.eq(record.revision.rev_id),
                     dsl::data.eq(record.revision.delta_data),
@@ -118,7 +119,7 @@ impl RevisionTableSql {
     pub(crate) fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
         let filter = dsl::rev_table
             .filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
-            .filter(dsl::doc_id.eq(changeset.doc_id));
+            .filter(dsl::doc_id.eq(changeset.object_id));
         let _ = update(filter).set(dsl::state.eq(changeset.state)).execute(conn)?;
         tracing::debug!(
             "[RevisionTable] update revision:{} state:to {:?}",
@@ -130,11 +131,11 @@ impl RevisionTableSql {
 
     pub(crate) fn read(
         user_id: &str,
-        doc_id: &str,
+        object_id: &str,
         rev_ids: Option<Vec<i64>>,
         conn: &SqliteConnection,
     ) -> Result<Vec<RevisionRecord>, FlowyError> {
-        let mut sql = dsl::rev_table.filter(dsl::doc_id.eq(doc_id)).into_boxed();
+        let mut sql = dsl::rev_table.filter(dsl::doc_id.eq(object_id)).into_boxed();
         if let Some(rev_ids) = rev_ids {
             sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
         }
@@ -149,14 +150,14 @@ impl RevisionTableSql {
 
     pub(crate) fn read_with_range(
         user_id: &str,
-        doc_id: &str,
+        object_id: &str,
         range: RevisionRange,
         conn: &SqliteConnection,
     ) -> Result<Vec<RevisionRecord>, FlowyError> {
         let rev_tables = dsl::rev_table
             .filter(dsl::rev_id.ge(range.start))
             .filter(dsl::rev_id.le(range.end))
-            .filter(dsl::doc_id.eq(doc_id))
+            .filter(dsl::doc_id.eq(object_id))
             .order(dsl::rev_id.asc())
             .load::<RevisionTable>(conn)?;
 
@@ -167,8 +168,12 @@ impl RevisionTableSql {
         Ok(revisions)
     }
 
-    pub(crate) fn delete(doc_id: &str, rev_ids: Option<Vec<i64>>, conn: &SqliteConnection) -> Result<(), FlowyError> {
-        let mut sql = dsl::rev_table.filter(dsl::doc_id.eq(doc_id)).into_boxed();
+    pub(crate) fn delete(
+        object_id: &str,
+        rev_ids: Option<Vec<i64>>,
+        conn: &SqliteConnection,
+    ) -> Result<(), FlowyError> {
+        let mut sql = dsl::rev_table.filter(dsl::doc_id.eq(object_id)).into_boxed();
         if let Some(rev_ids) = rev_ids {
             sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
         }
@@ -195,22 +200,22 @@ pub(crate) struct RevisionTable {
 #[repr(i32)]
 #[sql_type = "Integer"]
 pub enum RevisionTableState {
-    Local = 0,
-    Ack   = 1,
+    Sync = 0,
+    Ack  = 1,
 }
 
 impl std::default::Default for RevisionTableState {
-    fn default() -> Self { RevisionTableState::Local }
+    fn default() -> Self { RevisionTableState::Sync }
 }
 
 impl std::convert::From<i32> for RevisionTableState {
     fn from(value: i32) -> Self {
         match value {
-            0 => RevisionTableState::Local,
+            0 => RevisionTableState::Sync,
             1 => RevisionTableState::Ack,
             o => {
-                log::error!("Unsupported rev state {}, fallback to RevState::Local", o);
-                RevisionTableState::Local
+                tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o);
+                RevisionTableState::Sync
             },
         }
     }
@@ -224,7 +229,7 @@ impl_sql_integer_expression!(RevisionTableState);
 impl std::convert::From<RevisionTableState> for RevisionState {
     fn from(s: RevisionTableState) -> Self {
         match s {
-            RevisionTableState::Local => RevisionState::Local,
+            RevisionTableState::Sync => RevisionState::Sync,
             RevisionTableState::Ack => RevisionState::Ack,
         }
     }
@@ -233,7 +238,7 @@ impl std::convert::From<RevisionTableState> for RevisionState {
 impl std::convert::From<RevisionState> for RevisionTableState {
     fn from(s: RevisionState) -> Self {
         match s {
-            RevisionState::Local => RevisionTableState::Local,
+            RevisionState::Sync => RevisionTableState::Sync,
             RevisionState::Ack => RevisionTableState::Ack,
         }
     }
@@ -274,7 +279,7 @@ impl std::convert::From<i32> for RevTableType {
             0 => RevTableType::Local,
             1 => RevTableType::Remote,
             o => {
-                log::error!("Unsupported rev type {}, fallback to RevTableType::Local", o);
+                tracing::error!("Unsupported rev type {}, fallback to RevTableType::Local", o);
                 RevTableType::Local
             },
         }
@@ -304,7 +309,7 @@ impl std::convert::From<RevTableType> for RevType {
 }
 
 pub struct RevisionChangeset {
-    pub(crate) doc_id: String,
+    pub(crate) object_id: String,
     pub(crate) rev_id: RevId,
     pub(crate) state: RevisionTableState,
 }

+ 9 - 9
frontend/rust-lib/flowy-document/src/core/revision/memory.rs → frontend/rust-lib/flowy-sync/src/cache/memory.rs

@@ -1,4 +1,4 @@
-use crate::core::RevisionRecord;
+use crate::RevisionRecord;
 use dashmap::DashMap;
 use flowy_collaboration::entities::revision::RevisionRange;
 use flowy_error::{FlowyError, FlowyResult};
@@ -7,21 +7,21 @@ use tokio::{sync::RwLock, task::JoinHandle};
 
 pub(crate) trait RevisionMemoryCacheDelegate: Send + Sync {
     fn checkpoint_tick(&self, records: Vec<RevisionRecord>) -> FlowyResult<()>;
-    fn receive_ack(&self, doc_id: &str, rev_id: i64);
+    fn receive_ack(&self, object_id: &str, rev_id: i64);
 }
 
-pub(crate) struct DocumentRevisionMemoryCache {
-    doc_id: String,
+pub(crate) struct RevisionMemoryCache {
+    object_id: String,
     revs_map: Arc<DashMap<i64, RevisionRecord>>,
     delegate: Arc<dyn RevisionMemoryCacheDelegate>,
     pending_write_revs: Arc<RwLock<Vec<i64>>>,
     defer_save: RwLock<Option<JoinHandle<()>>>,
 }
 
-impl DocumentRevisionMemoryCache {
-    pub(crate) fn new(doc_id: &str, delegate: Arc<dyn RevisionMemoryCacheDelegate>) -> Self {
-        DocumentRevisionMemoryCache {
-            doc_id: doc_id.to_owned(),
+impl RevisionMemoryCache {
+    pub(crate) fn new(object_id: &str, delegate: Arc<dyn RevisionMemoryCacheDelegate>) -> Self {
+        RevisionMemoryCache {
+            object_id: object_id.to_owned(),
             revs_map: Arc::new(DashMap::new()),
             delegate,
             pending_write_revs: Arc::new(RwLock::new(vec![])),
@@ -62,7 +62,7 @@ impl DocumentRevisionMemoryCache {
         if !self.pending_write_revs.read().await.contains(rev_id) {
             // The revision must be saved on disk if the pending_write_revs
             // doesn't contains the rev_id.
-            self.delegate.receive_ack(&self.doc_id, *rev_id);
+            self.delegate.receive_ack(&self.object_id, *rev_id);
         } else {
             self.make_checkpoint().await;
         }

+ 18 - 18
frontend/rust-lib/flowy-document/src/core/revision/cache.rs → frontend/rust-lib/flowy-sync/src/cache/mod.rs

@@ -1,13 +1,13 @@
-use crate::{
-    core::revision::{
-        disk::{DocumentRevisionDiskCache, RevisionChangeset, RevisionTableState, SQLitePersistence},
-        memory::{DocumentRevisionMemoryCache, RevisionMemoryCacheDelegate},
-    },
-    errors::FlowyError,
+mod disk;
+mod memory;
+
+use crate::cache::{
+    disk::{RevisionChangeset, RevisionDiskCache, RevisionTableState, SQLitePersistence},
+    memory::{RevisionMemoryCache, RevisionMemoryCacheDelegate},
 };
 use flowy_collaboration::entities::revision::{Revision, RevisionRange, RevisionState};
 use flowy_database::ConnectionPool;
-use flowy_error::{internal_error, FlowyResult};
+use flowy_error::{internal_error, FlowyError, FlowyResult};
 use std::{
     borrow::Cow,
     sync::{
@@ -17,17 +17,17 @@ use std::{
 };
 use tokio::task::spawn_blocking;
 
-pub struct DocumentRevisionCache {
+pub struct RevisionCache {
     doc_id: String,
-    disk_cache: Arc<dyn DocumentRevisionDiskCache<Error = FlowyError>>,
-    memory_cache: Arc<DocumentRevisionMemoryCache>,
+    disk_cache: Arc<dyn RevisionDiskCache<Error = FlowyError>>,
+    memory_cache: Arc<RevisionMemoryCache>,
     latest_rev_id: AtomicI64,
 }
 
-impl DocumentRevisionCache {
-    pub fn new(user_id: &str, doc_id: &str, pool: Arc<ConnectionPool>) -> DocumentRevisionCache {
+impl RevisionCache {
+    pub fn new(user_id: &str, doc_id: &str, pool: Arc<ConnectionPool>) -> RevisionCache {
         let disk_cache = Arc::new(SQLitePersistence::new(user_id, pool));
-        let memory_cache = Arc::new(DocumentRevisionMemoryCache::new(doc_id, Arc::new(disk_cache.clone())));
+        let memory_cache = Arc::new(RevisionMemoryCache::new(doc_id, Arc::new(disk_cache.clone())));
         let doc_id = doc_id.to_owned();
         Self {
             doc_id,
@@ -99,7 +99,7 @@ impl DocumentRevisionCache {
                 .map_err(internal_error)??;
 
             if records.len() != range_len {
-                log::error!("Revisions len is not equal to range required");
+                tracing::error!("Revisions len is not equal to range required");
             }
         }
         Ok(records
@@ -115,13 +115,13 @@ impl DocumentRevisionCache {
             .into_iter()
             .map(|revision| RevisionRecord {
                 revision,
-                state: RevisionState::Local,
+                state: RevisionState::Sync,
                 write_to_disk: false,
             })
             .collect::<Vec<_>>();
 
         let _ = self.memory_cache.reset_with_revisions(&revision_records).await?;
-        let _ = self.disk_cache.reset_document(doc_id, revision_records)?;
+        let _ = self.disk_cache.reset_object(doc_id, revision_records)?;
         Ok(())
     }
 
@@ -146,9 +146,9 @@ impl RevisionMemoryCacheDelegate for Arc<SQLitePersistence> {
         Ok(())
     }
 
-    fn receive_ack(&self, doc_id: &str, rev_id: i64) {
+    fn receive_ack(&self, object_id: &str, rev_id: i64) {
         let changeset = RevisionChangeset {
-            doc_id: doc_id.to_string(),
+            object_id: object_id.to_string(),
             rev_id: rev_id.into(),
             state: RevisionTableState::Ack,
         };

+ 10 - 0
frontend/rust-lib/flowy-sync/src/lib.rs

@@ -0,0 +1,10 @@
+mod cache;
+mod rev_manager;
+mod ws_manager;
+
+pub use cache::*;
+pub use rev_manager::*;
+pub use ws_manager::*;
+
+#[macro_use]
+extern crate flowy_database;

+ 46 - 84
frontend/rust-lib/flowy-document/src/core/revision/manager.rs → frontend/rust-lib/flowy-sync/src/rev_manager.rs

@@ -1,41 +1,40 @@
-use crate::{
-    core::{revision::DocumentRevisionCache, RevisionRecord},
-    errors::FlowyError,
-};
-use bytes::Bytes;
+use crate::{RevisionCache, RevisionRecord};
+
 use dashmap::DashMap;
 use flowy_collaboration::{
-    entities::{
-        doc::DocumentInfo,
-        revision::{RepeatedRevision, Revision, RevisionRange, RevisionState},
-    },
-    util::{make_delta_from_revisions, md5, pair_rev_id_from_revisions, RevIdCounter},
+    entities::revision::{RepeatedRevision, Revision, RevisionRange, RevisionState},
+    util::{pair_rev_id_from_revisions, RevIdCounter},
 };
-use flowy_error::FlowyResult;
+use flowy_error::{FlowyError, FlowyResult};
 use futures_util::{future, stream, stream::StreamExt};
 use lib_infra::future::FutureResult;
-use lib_ot::{core::Operation, rich_text::RichTextDelta};
+
 use std::{collections::VecDeque, sync::Arc};
 use tokio::sync::RwLock;
 
-pub trait RevisionServer: Send + Sync {
-    fn fetch_document(&self, doc_id: &str) -> FutureResult<DocumentInfo, FlowyError>;
+pub trait RevisionCloudService: Send + Sync {
+    fn fetch_object(&self, user_id: &str, object_id: &str) -> FutureResult<Vec<Revision>, FlowyError>;
 }
 
-pub struct DocumentRevisionManager {
-    pub(crate) doc_id: String,
+pub trait RevisionObjectBuilder: Send + Sync {
+    type Output;
+    fn build_with_revisions(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output>;
+}
+
+pub struct RevisionManager {
+    pub object_id: String,
     user_id: String,
     rev_id_counter: RevIdCounter,
-    revision_cache: Arc<DocumentRevisionCache>,
+    revision_cache: Arc<RevisionCache>,
     revision_sync_seq: Arc<RevisionSyncSequence>,
 }
 
-impl DocumentRevisionManager {
-    pub fn new(user_id: &str, doc_id: &str, revision_cache: Arc<DocumentRevisionCache>) -> Self {
+impl RevisionManager {
+    pub fn new(user_id: &str, object_id: &str, revision_cache: Arc<RevisionCache>) -> Self {
         let rev_id_counter = RevIdCounter::new(0);
         let revision_sync_seq = Arc::new(RevisionSyncSequence::new());
         Self {
-            doc_id: doc_id.to_string(),
+            object_id: object_id.to_string(),
             user_id: user_id.to_owned(),
             rev_id_counter,
             revision_cache,
@@ -43,27 +42,28 @@ impl DocumentRevisionManager {
         }
     }
 
-    pub async fn load_document(&mut self, server: Arc<dyn RevisionServer>) -> FlowyResult<RichTextDelta> {
+    pub async fn load<Builder>(&mut self, cloud: Arc<dyn RevisionCloudService>) -> FlowyResult<Builder::Output>
+    where
+        Builder: RevisionObjectBuilder,
+    {
         let revisions = RevisionLoader {
-            doc_id: self.doc_id.clone(),
+            object_id: self.object_id.clone(),
             user_id: self.user_id.clone(),
-            server,
+            cloud,
             revision_cache: self.revision_cache.clone(),
             revision_sync_seq: self.revision_sync_seq.clone(),
         }
         .load()
         .await?;
-        let doc = mk_doc_from_revisions(&self.doc_id, revisions)?;
-        self.rev_id_counter.set(doc.rev_id);
-        Ok(doc.delta()?)
+        Builder::build_with_revisions(&self.object_id, revisions)
     }
 
     #[tracing::instrument(level = "debug", skip(self, revisions), err)]
-    pub async fn reset_document(&self, revisions: RepeatedRevision) -> FlowyResult<()> {
+    pub async fn reset_object(&self, revisions: RepeatedRevision) -> FlowyResult<()> {
         let rev_id = pair_rev_id_from_revisions(&revisions).1;
         let _ = self
             .revision_cache
-            .reset_with_revisions(&self.doc_id, revisions.into_inner())
+            .reset_with_revisions(&self.object_id, revisions.into_inner())
             .await?;
         self.rev_id_counter.set(rev_id);
         Ok(())
@@ -90,7 +90,7 @@ impl DocumentRevisionManager {
 
         let record = self
             .revision_cache
-            .add(revision.clone(), RevisionState::Local, true)
+            .add(revision.clone(), RevisionState::Sync, true)
             .await?;
         self.revision_sync_seq.add_revision_record(record).await?;
         Ok(())
@@ -115,7 +115,7 @@ impl DocumentRevisionManager {
     }
 
     pub async fn get_revisions_in_range(&self, range: RevisionRange) -> Result<Vec<Revision>, FlowyError> {
-        debug_assert!(range.doc_id == self.doc_id);
+        debug_assert!(range.object_id == self.object_id);
         let revisions = self.revision_cache.revisions_in_range(range.clone()).await?;
         Ok(revisions)
     }
@@ -160,7 +160,7 @@ impl RevisionSyncSequence {
     fn new() -> Self { RevisionSyncSequence::default() }
 
     async fn add_revision_record(&self, record: RevisionRecord) -> FlowyResult<()> {
-        if !record.state.is_local() {
+        if !record.state.is_need_sync() {
             return Ok(());
         }
 
@@ -204,37 +204,29 @@ impl RevisionSyncSequence {
 }
 
 struct RevisionLoader {
-    doc_id: String,
+    object_id: String,
     user_id: String,
-    server: Arc<dyn RevisionServer>,
-    revision_cache: Arc<DocumentRevisionCache>,
+    cloud: Arc<dyn RevisionCloudService>,
+    revision_cache: Arc<RevisionCache>,
     revision_sync_seq: Arc<RevisionSyncSequence>,
 }
 
 impl RevisionLoader {
     async fn load(&self) -> Result<Vec<Revision>, FlowyError> {
-        let records = self.revision_cache.batch_get(&self.doc_id)?;
+        let records = self.revision_cache.batch_get(&self.object_id)?;
         let revisions: Vec<Revision>;
         if records.is_empty() {
-            let doc = self.server.fetch_document(&self.doc_id).await?;
-            let delta_data = Bytes::from(doc.text.clone());
-            let doc_md5 = md5(&delta_data);
-            let revision = Revision::new(
-                &doc.doc_id,
-                doc.base_rev_id,
-                doc.rev_id,
-                delta_data,
-                &self.user_id,
-                doc_md5,
-            );
-            let _ = self
-                .revision_cache
-                .add(revision.clone(), RevisionState::Ack, true)
-                .await?;
-            revisions = vec![revision];
+            let remote_revisions = self.cloud.fetch_object(&self.user_id, &self.object_id).await?;
+            for revision in &remote_revisions {
+                let _ = self
+                    .revision_cache
+                    .add(revision.clone(), RevisionState::Ack, true)
+                    .await?;
+            }
+            revisions = remote_revisions;
         } else {
             stream::iter(records.clone())
-                .filter(|record| future::ready(record.state == RevisionState::Local))
+                .filter(|record| future::ready(record.state == RevisionState::Sync))
                 .for_each(|record| async move {
                     let f = || async {
                         // Sync the records if their state is RevisionState::Local.
@@ -255,36 +247,6 @@ impl RevisionLoader {
     }
 }
 
-fn mk_doc_from_revisions(doc_id: &str, revisions: Vec<Revision>) -> FlowyResult<DocumentInfo> {
-    let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id();
-    let mut delta = make_delta_from_revisions(revisions)?;
-    correct_delta(&mut delta);
-
-    Result::<DocumentInfo, FlowyError>::Ok(DocumentInfo {
-        doc_id: doc_id.to_owned(),
-        text: delta.to_json(),
-        rev_id,
-        base_rev_id,
-    })
-}
-
-// quill-editor requires the delta should end with '\n' and only contains the
-// insert operation. The function, correct_delta maybe be removed in the future.
-fn correct_delta(delta: &mut RichTextDelta) {
-    if let Some(op) = delta.ops.last() {
-        let op_data = op.get_data();
-        if !op_data.ends_with('\n') {
-            log::warn!("The document must end with newline. Correcting it by inserting newline op");
-            delta.ops.push(Operation::Insert("\n".into()));
-        }
-    }
-
-    if let Some(op) = delta.ops.iter().find(|op| !op.is_insert()) {
-        log::warn!("The document can only contains insert operations, but found {:?}", op);
-        delta.ops.retain(|op| op.is_insert());
-    }
-}
-
 #[cfg(feature = "flowy_unit_test")]
 impl RevisionSyncSequence {
     #[allow(dead_code)]
@@ -294,6 +256,6 @@ impl RevisionSyncSequence {
 }
 
 #[cfg(feature = "flowy_unit_test")]
-impl DocumentRevisionManager {
-    pub fn revision_cache(&self) -> Arc<DocumentRevisionCache> { self.revision_cache.clone() }
+impl RevisionManager {
+    pub fn revision_cache(&self) -> Arc<RevisionCache> { self.revision_cache.clone() }
 }

+ 85 - 101
frontend/rust-lib/flowy-document/src/core/web_socket/ws_manager.rs → frontend/rust-lib/flowy-sync/src/ws_manager.rs

@@ -1,16 +1,11 @@
-use crate::{
-    core::SYNC_INTERVAL_IN_MILLIS,
-    ws_receivers::{DocumentWSReceiver, DocumentWebSocket},
-};
 use async_stream::stream;
-use async_trait::async_trait;
 use bytes::Bytes;
 use flowy_collaboration::entities::{
     revision::{RevId, RevisionRange},
-    ws::{DocumentClientWSData, DocumentServerWSData, DocumentServerWSDataType, NewDocumentUser},
+    ws::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSData, ServerRevisionWSDataType},
 };
 use flowy_error::{internal_error, FlowyError, FlowyResult};
-use futures::stream::StreamExt;
+use futures_util::stream::StreamExt;
 use lib_infra::future::FutureResult;
 use lib_ws::WSConnectState;
 use std::{convert::TryFrom, sync::Arc};
@@ -25,43 +20,50 @@ use tokio::{
 };
 
 // The consumer consumes the messages pushed by the web socket.
-pub trait DocumentWSSteamConsumer: Send + Sync {
+pub trait RevisionWSSteamConsumer: Send + Sync {
     fn receive_push_revision(&self, bytes: Bytes) -> FutureResult<(), FlowyError>;
-    fn receive_ack(&self, id: String, ty: DocumentServerWSDataType) -> FutureResult<(), FlowyError>;
+    fn receive_ack(&self, id: String, ty: ServerRevisionWSDataType) -> FutureResult<(), FlowyError>;
     fn receive_new_user_connect(&self, new_user: NewDocumentUser) -> FutureResult<(), FlowyError>;
     fn pull_revisions_in_range(&self, range: RevisionRange) -> FutureResult<(), FlowyError>;
 }
 
 // The sink provides the data that will be sent through the web socket to the
 // backend.
-pub trait DocumentWSSinkDataProvider: Send + Sync {
-    fn next(&self) -> FutureResult<Option<DocumentClientWSData>, FlowyError>;
+pub trait RevisionWSSinkDataProvider: Send + Sync {
+    fn next(&self) -> FutureResult<Option<ClientRevisionWSData>, FlowyError>;
+}
+
+pub type WSStateReceiver = tokio::sync::broadcast::Receiver<WSConnectState>;
+pub trait RevisionWebSocket: Send + Sync {
+    fn send(&self, data: ClientRevisionWSData) -> Result<(), FlowyError>;
+    fn subscribe_state_changed(&self) -> WSStateReceiver;
 }
 
-pub struct DocumentWebSocketManager {
-    doc_id: String,
-    data_provider: Arc<dyn DocumentWSSinkDataProvider>,
-    stream_consumer: Arc<dyn DocumentWSSteamConsumer>,
-    ws_conn: Arc<dyn DocumentWebSocket>,
-    ws_passthrough_tx: Sender<DocumentServerWSData>,
-    ws_passthrough_rx: Option<Receiver<DocumentServerWSData>>,
-    state_passthrough_tx: broadcast::Sender<WSConnectState>,
+pub struct RevisionWebSocketManager {
+    pub object_id: String,
+    data_provider: Arc<dyn RevisionWSSinkDataProvider>,
+    stream_consumer: Arc<dyn RevisionWSSteamConsumer>,
+    ws_conn: Arc<dyn RevisionWebSocket>,
+    pub ws_passthrough_tx: Sender<ServerRevisionWSData>,
+    ws_passthrough_rx: Option<Receiver<ServerRevisionWSData>>,
+    pub state_passthrough_tx: broadcast::Sender<WSConnectState>,
     stop_sync_tx: SinkStopTx,
 }
 
-impl DocumentWebSocketManager {
-    pub(crate) fn new(
-        doc_id: &str,
-        ws_conn: Arc<dyn DocumentWebSocket>,
-        data_provider: Arc<dyn DocumentWSSinkDataProvider>,
-        stream_consumer: Arc<dyn DocumentWSSteamConsumer>,
+impl RevisionWebSocketManager {
+    pub fn new(
+        object_id: &str,
+        ws_conn: Arc<dyn RevisionWebSocket>,
+        data_provider: Arc<dyn RevisionWSSinkDataProvider>,
+        stream_consumer: Arc<dyn RevisionWSSteamConsumer>,
+        ping_duration: Duration,
     ) -> Self {
         let (ws_passthrough_tx, ws_passthrough_rx) = mpsc::channel(1000);
         let (stop_sync_tx, _) = tokio::sync::broadcast::channel(2);
-        let doc_id = doc_id.to_string();
+        let object_id = object_id.to_string();
         let (state_passthrough_tx, _) = broadcast::channel(2);
-        let mut manager = DocumentWebSocketManager {
-            doc_id,
+        let mut manager = RevisionWebSocketManager {
+            object_id,
             data_provider,
             stream_consumer,
             ws_conn,
@@ -70,20 +72,21 @@ impl DocumentWebSocketManager {
             state_passthrough_tx,
             stop_sync_tx,
         };
-        manager.run();
+        manager.run(ping_duration);
         manager
     }
 
-    fn run(&mut self) {
+    fn run(&mut self, ping_duration: Duration) {
         let ws_msg_rx = self.ws_passthrough_rx.take().expect("Only take once");
-        let sink = DocumentWSSink::new(
-            &self.doc_id,
+        let sink = RevisionWSSink::new(
+            &self.object_id,
             self.data_provider.clone(),
             self.ws_conn.clone(),
             self.stop_sync_tx.subscribe(),
+            ping_duration,
         );
-        let stream = DocumentWSStream::new(
-            &self.doc_id,
+        let stream = RevisionWSStream::new(
+            &self.object_id,
             self.stream_consumer.clone(),
             ws_msg_rx,
             self.stop_sync_tx.subscribe(),
@@ -94,59 +97,37 @@ impl DocumentWebSocketManager {
 
     pub fn scribe_state(&self) -> broadcast::Receiver<WSConnectState> { self.state_passthrough_tx.subscribe() }
 
-    pub(crate) fn stop(&self) {
+    pub fn stop(&self) {
         if self.stop_sync_tx.send(()).is_ok() {
-            tracing::trace!("{} stop sync", self.doc_id)
-        }
-    }
-}
-
-//  DocumentWebSocketManager registers itself as a DocumentWSReceiver for each
-//  opened document. It will receive the web socket message and parser it into
-//  DocumentServerWSData.
-#[async_trait]
-impl DocumentWSReceiver for DocumentWebSocketManager {
-    #[tracing::instrument(level = "debug", skip(self, doc_data), err)]
-    async fn receive_ws_data(&self, doc_data: DocumentServerWSData) -> Result<(), FlowyError> {
-        let _ = self.ws_passthrough_tx.send(doc_data).await.map_err(|e| {
-            let err_msg = format!("{} passthrough error: {}", self.doc_id, e);
-            FlowyError::internal().context(err_msg)
-        })?;
-        Ok(())
-    }
-
-    fn connect_state_changed(&self, state: WSConnectState) {
-        match self.state_passthrough_tx.send(state) {
-            Ok(_) => {},
-            Err(e) => tracing::error!("{}", e),
+            tracing::trace!("{} stop sync", self.object_id)
         }
     }
 }
 
-impl std::ops::Drop for DocumentWebSocketManager {
-    fn drop(&mut self) { tracing::trace!("{} DocumentWebSocketManager was dropped", self.doc_id) }
+impl std::ops::Drop for RevisionWebSocketManager {
+    fn drop(&mut self) { tracing::trace!("{} RevisionWebSocketManager was dropped", self.object_id) }
 }
 
-pub struct DocumentWSStream {
-    doc_id: String,
-    consumer: Arc<dyn DocumentWSSteamConsumer>,
-    ws_msg_rx: Option<mpsc::Receiver<DocumentServerWSData>>,
+pub struct RevisionWSStream {
+    object_id: String,
+    consumer: Arc<dyn RevisionWSSteamConsumer>,
+    ws_msg_rx: Option<mpsc::Receiver<ServerRevisionWSData>>,
     stop_rx: Option<SinkStopRx>,
 }
 
-impl std::ops::Drop for DocumentWSStream {
-    fn drop(&mut self) { tracing::trace!("{} DocumentWSStream was dropped", self.doc_id) }
+impl std::ops::Drop for RevisionWSStream {
+    fn drop(&mut self) { tracing::trace!("{} RevisionWSStream was dropped", self.object_id) }
 }
 
-impl DocumentWSStream {
+impl RevisionWSStream {
     pub fn new(
-        doc_id: &str,
-        consumer: Arc<dyn DocumentWSSteamConsumer>,
-        ws_msg_rx: mpsc::Receiver<DocumentServerWSData>,
+        object_id: &str,
+        consumer: Arc<dyn RevisionWSSteamConsumer>,
+        ws_msg_rx: mpsc::Receiver<ServerRevisionWSData>,
         stop_rx: SinkStopRx,
     ) -> Self {
-        DocumentWSStream {
-            doc_id: doc_id.to_owned(),
+        RevisionWSStream {
+            object_id: object_id.to_owned(),
             consumer,
             ws_msg_rx: Some(ws_msg_rx),
             stop_rx: Some(stop_rx),
@@ -156,7 +137,7 @@ impl DocumentWSStream {
     pub async fn run(mut self) {
         let mut receiver = self.ws_msg_rx.take().expect("Only take once");
         let mut stop_rx = self.stop_rx.take().expect("Only take once");
-        let doc_id = self.doc_id.clone();
+        let object_id = self.object_id.clone();
         let stream = stream! {
             loop {
                 tokio::select! {
@@ -166,13 +147,13 @@ impl DocumentWSStream {
                                 yield msg
                             },
                             None => {
-                                tracing::debug!("[DocumentStream:{}] loop exit", doc_id);
+                                tracing::debug!("[RevisionWSStream:{}] loop exit", object_id);
                                 break;
                             },
                         }
                     },
                     _ = stop_rx.recv() => {
-                        tracing::debug!("[DocumentStream:{}] loop exit", doc_id);
+                        tracing::debug!("[RevisionWSStream:{}] loop exit", object_id);
                         break
                     },
                 };
@@ -183,32 +164,32 @@ impl DocumentWSStream {
             .for_each(|msg| async {
                 match self.handle_message(msg).await {
                     Ok(_) => {},
-                    Err(e) => log::error!("[DocumentStream:{}] error: {}", self.doc_id, e),
+                    Err(e) => tracing::error!("[RevisionWSStream:{}] error: {}", self.object_id, e),
                 }
             })
             .await;
     }
 
-    async fn handle_message(&self, msg: DocumentServerWSData) -> FlowyResult<()> {
-        let DocumentServerWSData { doc_id: _, ty, data } = msg;
+    async fn handle_message(&self, msg: ServerRevisionWSData) -> FlowyResult<()> {
+        let ServerRevisionWSData { object_id: _, ty, data } = msg;
         let bytes = spawn_blocking(move || Bytes::from(data))
             .await
             .map_err(internal_error)?;
 
-        tracing::trace!("[DocumentStream]: new message: {:?}", ty);
+        tracing::trace!("[RevisionWSStream]: new message: {:?}", ty);
         match ty {
-            DocumentServerWSDataType::ServerPushRev => {
+            ServerRevisionWSDataType::ServerPushRev => {
                 let _ = self.consumer.receive_push_revision(bytes).await?;
             },
-            DocumentServerWSDataType::ServerPullRev => {
+            ServerRevisionWSDataType::ServerPullRev => {
                 let range = RevisionRange::try_from(bytes)?;
                 let _ = self.consumer.pull_revisions_in_range(range).await?;
             },
-            DocumentServerWSDataType::ServerAck => {
+            ServerRevisionWSDataType::ServerAck => {
                 let rev_id = RevId::try_from(bytes).unwrap().value;
                 let _ = self.consumer.receive_ack(rev_id.to_string(), ty).await;
             },
-            DocumentServerWSDataType::UserConnect => {
+            ServerRevisionWSDataType::UserConnect => {
                 let new_user = NewDocumentUser::try_from(bytes)?;
                 let _ = self.consumer.receive_new_user_connect(new_user).await;
             },
@@ -219,33 +200,36 @@ impl DocumentWSStream {
 
 type SinkStopRx = broadcast::Receiver<()>;
 type SinkStopTx = broadcast::Sender<()>;
-pub struct DocumentWSSink {
-    provider: Arc<dyn DocumentWSSinkDataProvider>,
-    ws_sender: Arc<dyn DocumentWebSocket>,
+pub struct RevisionWSSink {
+    provider: Arc<dyn RevisionWSSinkDataProvider>,
+    ws_sender: Arc<dyn RevisionWebSocket>,
     stop_rx: Option<SinkStopRx>,
-    doc_id: String,
+    object_id: String,
+    ping_duration: Duration,
 }
 
-impl DocumentWSSink {
+impl RevisionWSSink {
     pub fn new(
-        doc_id: &str,
-        provider: Arc<dyn DocumentWSSinkDataProvider>,
-        ws_sender: Arc<dyn DocumentWebSocket>,
+        object_id: &str,
+        provider: Arc<dyn RevisionWSSinkDataProvider>,
+        ws_sender: Arc<dyn RevisionWebSocket>,
         stop_rx: SinkStopRx,
+        ping_duration: Duration,
     ) -> Self {
         Self {
             provider,
             ws_sender,
             stop_rx: Some(stop_rx),
-            doc_id: doc_id.to_owned(),
+            object_id: object_id.to_owned(),
+            ping_duration,
         }
     }
 
     pub async fn run(mut self) {
         let (tx, mut rx) = mpsc::channel(1);
         let mut stop_rx = self.stop_rx.take().expect("Only take once");
-        let doc_id = self.doc_id.clone();
-        tokio::spawn(tick(tx));
+        let object_id = self.object_id.clone();
+        tokio::spawn(tick(tx, self.ping_duration));
         let stream = stream! {
             loop {
                 tokio::select! {
@@ -256,7 +240,7 @@ impl DocumentWSSink {
                         }
                     },
                     _ = stop_rx.recv() => {
-                        tracing::trace!("[DocumentSink:{}] loop exit", doc_id);
+                        tracing::trace!("[RevisionWSSink:{}] loop exit", object_id);
                         break
                     },
                 };
@@ -266,7 +250,7 @@ impl DocumentWSSink {
             .for_each(|_| async {
                 match self.send_next_revision().await {
                     Ok(_) => {},
-                    Err(e) => log::error!("[DocumentSink] send failed, {:?}", e),
+                    Err(e) => tracing::error!("[RevisionWSSink] send failed, {:?}", e),
                 }
             })
             .await;
@@ -279,19 +263,19 @@ impl DocumentWSSink {
                 Ok(())
             },
             Some(data) => {
-                tracing::trace!("[DocumentSink] send: {}:{}-{:?}", data.doc_id, data.id(), data.ty);
+                tracing::trace!("[RevisionWSSink] send: {}:{}-{:?}", data.object_id, data.id(), data.ty);
                 self.ws_sender.send(data)
             },
         }
     }
 }
 
-impl std::ops::Drop for DocumentWSSink {
-    fn drop(&mut self) { tracing::trace!("{} DocumentWSSink was dropped", self.doc_id) }
+impl std::ops::Drop for RevisionWSSink {
+    fn drop(&mut self) { tracing::trace!("{} RevisionWSSink was dropped", self.object_id) }
 }
 
-async fn tick(sender: mpsc::Sender<()>) {
-    let mut interval = interval(Duration::from_millis(SYNC_INTERVAL_IN_MILLIS));
+async fn tick(sender: mpsc::Sender<()>, duration: Duration) {
+    let mut interval = interval(duration);
     while sender.send(()).await.is_ok() {
         interval.tick().await;
     }

+ 13 - 13
frontend/rust-lib/flowy-user/src/protobuf/model/dart_notification.rs

@@ -86,19 +86,19 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x17dart_notification.proto*\x81\x01\n\x10UserNotification\x12\x0b\n\
     \x07Unknown\x10\0\x12\x13\n\x0fUserAuthChanged\x10\x01\x12\x16\n\x12User\
     ProfileUpdated\x10\x02\x12\x14\n\x10UserUnauthorized\x10\x03\x12\x1d\n\
-    \x19UserWsConnectStateChanged\x10\x04J\xf7\x01\n\x06\x12\x04\0\0\x07\x01\
-    \n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x01\0\x07\x01\n\
-    \n\n\x03\x05\0\x01\x12\x03\x01\x05\x15\n\x0b\n\x04\x05\0\x02\0\x12\x03\
-    \x02\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x02\x04\x0b\n\x0c\n\x05\
-    \x05\0\x02\0\x02\x12\x03\x02\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\
-    \x03\x04\x18\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x03\x04\x13\n\x0c\n\
-    \x05\x05\0\x02\x01\x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\0\x02\x02\x12\
-    \x03\x04\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x04\x04\x16\n\x0c\
-    \n\x05\x05\0\x02\x02\x02\x12\x03\x04\x19\x1a\n\x0b\n\x04\x05\0\x02\x03\
-    \x12\x03\x05\x04\x19\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x05\x04\x14\n\
-    \x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x05\x17\x18\n\x0b\n\x04\x05\0\x02\
-    \x04\x12\x03\x06\x04\"\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x06\x04\x1d\
-    \n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x06\x20!b\x06proto3\
+    \x19UserWsConnectStateChanged\x10\x04J\xf7\x01\n\x06\x12\x04\0\0\x08\x01\
+    \n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x08\x01\n\
+    \n\n\x03\x05\0\x01\x12\x03\x02\x05\x15\n\x0b\n\x04\x05\0\x02\0\x12\x03\
+    \x03\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x0b\n\x0c\n\x05\
+    \x05\0\x02\0\x02\x12\x03\x03\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\
+    \x04\x04\x18\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x13\n\x0c\n\
+    \x05\x05\0\x02\x01\x02\x12\x03\x04\x16\x17\n\x0b\n\x04\x05\0\x02\x02\x12\
+    \x03\x05\x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x16\n\x0c\
+    \n\x05\x05\0\x02\x02\x02\x12\x03\x05\x19\x1a\n\x0b\n\x04\x05\0\x02\x03\
+    \x12\x03\x06\x04\x19\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x14\n\
+    \x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x17\x18\n\x0b\n\x04\x05\0\x02\
+    \x04\x12\x03\x07\x04\"\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x1d\
+    \n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x20!b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 0
frontend/rust-lib/flowy-user/src/protobuf/proto/dart_notification.proto

@@ -1,4 +1,5 @@
 syntax = "proto3";
+
 enum UserNotification {
     Unknown = 0;
     UserAuthChanged = 1;

+ 1 - 1
shared-lib/flowy-collaboration/src/entities/doc.rs

@@ -73,7 +73,7 @@ impl std::convert::TryFrom<Revision> for DocumentInfo {
         let doc_json = delta.to_json();
 
         Ok(DocumentInfo {
-            doc_id: revision.doc_id,
+            doc_id: revision.object_id,
             text: doc_json,
             rev_id: revision.rev_id,
             base_rev_id: revision.base_rev_id,

+ 19 - 12
shared-lib/flowy-collaboration/src/entities/revision.rs

@@ -18,7 +18,7 @@ pub struct Revision {
     pub md5: String,
 
     #[pb(index = 5)]
-    pub doc_id: String,
+    pub object_id: String,
 
     #[pb(index = 6)]
     ty: RevType, // Deprecated
@@ -41,14 +41,21 @@ impl Revision {
 
     pub fn is_initial(&self) -> bool { self.rev_id == 0 }
 
-    pub fn initial_revision(user_id: &str, doc_id: &str, delta_data: Bytes) -> Self {
+    pub fn initial_revision(user_id: &str, object_id: &str, delta_data: Bytes) -> Self {
         let md5 = md5(&delta_data);
-        Self::new(doc_id, 0, 0, delta_data, user_id, md5)
+        Self::new(object_id, 0, 0, delta_data, user_id, md5)
     }
 
-    pub fn new(doc_id: &str, base_rev_id: i64, rev_id: i64, delta_data: Bytes, user_id: &str, md5: String) -> Revision {
+    pub fn new(
+        object_id: &str,
+        base_rev_id: i64,
+        rev_id: i64,
+        delta_data: Bytes,
+        user_id: &str,
+        md5: String,
+    ) -> Revision {
         let user_id = user_id.to_owned();
-        let doc_id = doc_id.to_owned();
+        let object_id = object_id.to_owned();
         let delta_data = delta_data.to_vec();
         let base_rev_id = base_rev_id;
         let rev_id = rev_id;
@@ -62,7 +69,7 @@ impl Revision {
             rev_id,
             delta_data,
             md5,
-            doc_id,
+            object_id,
             ty: RevType::DeprecatedLocal,
             user_id,
         }
@@ -75,7 +82,7 @@ impl std::convert::From<Revision> for RepeatedRevision {
 
 impl std::fmt::Debug for Revision {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
+        let _ = f.write_fmt(format_args!("object_id {}, ", self.object_id))?;
         let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
         let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
         match RichTextDelta::from_bytes(&self.delta_data) {
@@ -142,7 +149,7 @@ impl std::fmt::Display for RevId {
 #[derive(Debug, Clone, Default, ProtoBuf)]
 pub struct RevisionRange {
     #[pb(index = 1)]
-    pub doc_id: String,
+    pub object_id: String,
 
     #[pb(index = 2)]
     pub start: i64,
@@ -177,14 +184,14 @@ pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum RevisionState {
-    Local = 0,
-    Ack   = 1,
+    Sync = 0,
+    Ack  = 1,
 }
 
 impl RevisionState {
-    pub fn is_local(&self) -> bool {
+    pub fn is_need_sync(&self) -> bool {
         match self {
-            RevisionState::Local => true,
+            RevisionState::Sync => true,
             RevisionState::Ack => false,
         }
     }

+ 38 - 38
shared-lib/flowy-collaboration/src/entities/ws.rs

@@ -7,12 +7,12 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use std::convert::{TryFrom, TryInto};
 
 #[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
-pub enum DocumentClientWSDataType {
+pub enum ClientRevisionWSDataType {
     ClientPushRev = 0,
     ClientPing    = 1,
 }
 
-impl DocumentClientWSDataType {
+impl ClientRevisionWSDataType {
     pub fn data<T>(&self, bytes: Bytes) -> Result<T, CollaborateError>
     where
         T: TryFrom<Bytes, Error = CollaborateError>,
@@ -21,102 +21,102 @@ impl DocumentClientWSDataType {
     }
 }
 
-impl std::default::Default for DocumentClientWSDataType {
-    fn default() -> Self { DocumentClientWSDataType::ClientPushRev }
+impl std::default::Default for ClientRevisionWSDataType {
+    fn default() -> Self { ClientRevisionWSDataType::ClientPushRev }
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
-pub struct DocumentClientWSData {
+pub struct ClientRevisionWSData {
     #[pb(index = 1)]
-    pub doc_id: String,
+    pub object_id: String,
 
     #[pb(index = 2)]
-    pub ty: DocumentClientWSDataType,
+    pub ty: ClientRevisionWSDataType,
 
     #[pb(index = 3)]
     pub revisions: RepeatedRevision,
 
     #[pb(index = 4)]
-    id: String,
+    data_id: String,
 }
 
-impl DocumentClientWSData {
-    pub fn from_revisions(doc_id: &str, revisions: Vec<Revision>) -> Self {
+impl ClientRevisionWSData {
+    pub fn from_revisions(object_id: &str, revisions: Vec<Revision>) -> Self {
         let rev_id = match revisions.first() {
             None => 0,
             Some(revision) => revision.rev_id,
         };
 
         Self {
-            doc_id: doc_id.to_owned(),
-            ty: DocumentClientWSDataType::ClientPushRev,
+            object_id: object_id.to_owned(),
+            ty: ClientRevisionWSDataType::ClientPushRev,
             revisions: RepeatedRevision::new(revisions),
-            id: rev_id.to_string(),
+            data_id: rev_id.to_string(),
         }
     }
 
-    pub fn ping(doc_id: &str, rev_id: i64) -> Self {
+    pub fn ping(object_id: &str, rev_id: i64) -> Self {
         Self {
-            doc_id: doc_id.to_owned(),
-            ty: DocumentClientWSDataType::ClientPing,
+            object_id: object_id.to_owned(),
+            ty: ClientRevisionWSDataType::ClientPing,
             revisions: RepeatedRevision::empty(),
-            id: rev_id.to_string(),
+            data_id: rev_id.to_string(),
         }
     }
 
-    pub fn id(&self) -> String { self.id.clone() }
+    pub fn id(&self) -> String { self.data_id.clone() }
 }
 
 #[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
-pub enum DocumentServerWSDataType {
+pub enum ServerRevisionWSDataType {
     ServerAck     = 0,
     ServerPushRev = 1,
     ServerPullRev = 2,
     UserConnect   = 3,
 }
 
-impl std::default::Default for DocumentServerWSDataType {
-    fn default() -> Self { DocumentServerWSDataType::ServerPushRev }
+impl std::default::Default for ServerRevisionWSDataType {
+    fn default() -> Self { ServerRevisionWSDataType::ServerPushRev }
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
-pub struct DocumentServerWSData {
+pub struct ServerRevisionWSData {
     #[pb(index = 1)]
-    pub doc_id: String,
+    pub object_id: String,
 
     #[pb(index = 2)]
-    pub ty: DocumentServerWSDataType,
+    pub ty: ServerRevisionWSDataType,
 
     #[pb(index = 3)]
     pub data: Vec<u8>,
 }
 
-pub struct DocumentServerWSDataBuilder();
-impl DocumentServerWSDataBuilder {
-    pub fn build_push_message(doc_id: &str, repeated_revision: RepeatedRevision) -> DocumentServerWSData {
+pub struct ServerRevisionWSDataBuilder();
+impl ServerRevisionWSDataBuilder {
+    pub fn build_push_message(doc_id: &str, repeated_revision: RepeatedRevision) -> ServerRevisionWSData {
         let bytes: Bytes = repeated_revision.try_into().unwrap();
-        DocumentServerWSData {
-            doc_id: doc_id.to_string(),
-            ty: DocumentServerWSDataType::ServerPushRev,
+        ServerRevisionWSData {
+            object_id: doc_id.to_string(),
+            ty: ServerRevisionWSDataType::ServerPushRev,
             data: bytes.to_vec(),
         }
     }
 
-    pub fn build_pull_message(doc_id: &str, range: RevisionRange) -> DocumentServerWSData {
+    pub fn build_pull_message(doc_id: &str, range: RevisionRange) -> ServerRevisionWSData {
         let bytes: Bytes = range.try_into().unwrap();
-        DocumentServerWSData {
-            doc_id: doc_id.to_string(),
-            ty: DocumentServerWSDataType::ServerPullRev,
+        ServerRevisionWSData {
+            object_id: doc_id.to_string(),
+            ty: ServerRevisionWSDataType::ServerPullRev,
             data: bytes.to_vec(),
         }
     }
 
-    pub fn build_ack_message(doc_id: &str, rev_id: i64) -> DocumentServerWSData {
+    pub fn build_ack_message(doc_id: &str, rev_id: i64) -> ServerRevisionWSData {
         let rev_id: RevId = rev_id.into();
         let bytes: Bytes = rev_id.try_into().unwrap();
-        DocumentServerWSData {
-            doc_id: doc_id.to_string(),
-            ty: DocumentServerWSDataType::ServerAck,
+        ServerRevisionWSData {
+            object_id: doc_id.to_string(),
+            ty: ServerRevisionWSDataType::ServerAck,
             data: bytes.to_vec(),
         }
     }

+ 106 - 106
shared-lib/flowy-collaboration/src/protobuf/model/revision.rs

@@ -30,7 +30,7 @@ pub struct Revision {
     pub rev_id: i64,
     pub delta_data: ::std::vec::Vec<u8>,
     pub md5: ::std::string::String,
-    pub doc_id: ::std::string::String,
+    pub object_id: ::std::string::String,
     pub ty: RevType,
     pub user_id: ::std::string::String,
     // special fields
@@ -131,30 +131,30 @@ impl Revision {
         ::std::mem::replace(&mut self.md5, ::std::string::String::new())
     }
 
-    // string doc_id = 5;
+    // string object_id = 5;
 
 
-    pub fn get_doc_id(&self) -> &str {
-        &self.doc_id
+    pub fn get_object_id(&self) -> &str {
+        &self.object_id
     }
-    pub fn clear_doc_id(&mut self) {
-        self.doc_id.clear();
+    pub fn clear_object_id(&mut self) {
+        self.object_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_doc_id(&mut self, v: ::std::string::String) {
-        self.doc_id = v;
+    pub fn set_object_id(&mut self, v: ::std::string::String) {
+        self.object_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_doc_id(&mut self) -> &mut ::std::string::String {
-        &mut self.doc_id
+    pub fn mut_object_id(&mut self) -> &mut ::std::string::String {
+        &mut self.object_id
     }
 
     // Take field
-    pub fn take_doc_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    pub fn take_object_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.object_id, ::std::string::String::new())
     }
 
     // .RevType ty = 6;
@@ -229,7 +229,7 @@ impl ::protobuf::Message for Revision {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.md5)?;
                 },
                 5 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.object_id)?;
                 },
                 6 => {
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 6, &mut self.unknown_fields)?
@@ -261,8 +261,8 @@ impl ::protobuf::Message for Revision {
         if !self.md5.is_empty() {
             my_size += ::protobuf::rt::string_size(4, &self.md5);
         }
-        if !self.doc_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(5, &self.doc_id);
+        if !self.object_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(5, &self.object_id);
         }
         if self.ty != RevType::DeprecatedLocal {
             my_size += ::protobuf::rt::enum_size(6, self.ty);
@@ -288,8 +288,8 @@ impl ::protobuf::Message for Revision {
         if !self.md5.is_empty() {
             os.write_string(4, &self.md5)?;
         }
-        if !self.doc_id.is_empty() {
-            os.write_string(5, &self.doc_id)?;
+        if !self.object_id.is_empty() {
+            os.write_string(5, &self.object_id)?;
         }
         if self.ty != RevType::DeprecatedLocal {
             os.write_enum(6, ::protobuf::ProtobufEnum::value(&self.ty))?;
@@ -356,9 +356,9 @@ impl ::protobuf::Message for Revision {
                 |m: &mut Revision| { &mut m.md5 },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "doc_id",
-                |m: &Revision| { &m.doc_id },
-                |m: &mut Revision| { &mut m.doc_id },
+                "object_id",
+                |m: &Revision| { &m.object_id },
+                |m: &mut Revision| { &mut m.object_id },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<RevType>>(
                 "ty",
@@ -390,7 +390,7 @@ impl ::protobuf::Clear for Revision {
         self.rev_id = 0;
         self.delta_data.clear();
         self.md5.clear();
-        self.doc_id.clear();
+        self.object_id.clear();
         self.ty = RevType::DeprecatedLocal;
         self.user_id.clear();
         self.unknown_fields.clear();
@@ -730,7 +730,7 @@ impl ::protobuf::reflect::ProtobufValue for RevId {
 #[derive(PartialEq,Clone,Default)]
 pub struct RevisionRange {
     // message fields
-    pub doc_id: ::std::string::String,
+    pub object_id: ::std::string::String,
     pub start: i64,
     pub end: i64,
     // special fields
@@ -749,30 +749,30 @@ impl RevisionRange {
         ::std::default::Default::default()
     }
 
-    // string doc_id = 1;
+    // string object_id = 1;
 
 
-    pub fn get_doc_id(&self) -> &str {
-        &self.doc_id
+    pub fn get_object_id(&self) -> &str {
+        &self.object_id
     }
-    pub fn clear_doc_id(&mut self) {
-        self.doc_id.clear();
+    pub fn clear_object_id(&mut self) {
+        self.object_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_doc_id(&mut self, v: ::std::string::String) {
-        self.doc_id = v;
+    pub fn set_object_id(&mut self, v: ::std::string::String) {
+        self.object_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_doc_id(&mut self) -> &mut ::std::string::String {
-        &mut self.doc_id
+    pub fn mut_object_id(&mut self) -> &mut ::std::string::String {
+        &mut self.object_id
     }
 
     // Take field
-    pub fn take_doc_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    pub fn take_object_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.object_id, ::std::string::String::new())
     }
 
     // int64 start = 2;
@@ -816,7 +816,7 @@ impl ::protobuf::Message for RevisionRange {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.object_id)?;
                 },
                 2 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
@@ -844,8 +844,8 @@ impl ::protobuf::Message for RevisionRange {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.doc_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.doc_id);
+        if !self.object_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.object_id);
         }
         if self.start != 0 {
             my_size += ::protobuf::rt::value_size(2, self.start, ::protobuf::wire_format::WireTypeVarint);
@@ -859,8 +859,8 @@ impl ::protobuf::Message for RevisionRange {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.doc_id.is_empty() {
-            os.write_string(1, &self.doc_id)?;
+        if !self.object_id.is_empty() {
+            os.write_string(1, &self.object_id)?;
         }
         if self.start != 0 {
             os.write_int64(2, self.start)?;
@@ -907,9 +907,9 @@ impl ::protobuf::Message for RevisionRange {
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "doc_id",
-                |m: &RevisionRange| { &m.doc_id },
-                |m: &mut RevisionRange| { &mut m.doc_id },
+                "object_id",
+                |m: &RevisionRange| { &m.object_id },
+                |m: &mut RevisionRange| { &mut m.object_id },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
                 "start",
@@ -937,7 +937,7 @@ impl ::protobuf::Message for RevisionRange {
 
 impl ::protobuf::Clear for RevisionRange {
     fn clear(&mut self) {
-        self.doc_id.clear();
+        self.object_id.clear();
         self.start = 0;
         self.end = 0;
         self.unknown_fields.clear();
@@ -958,7 +958,7 @@ impl ::protobuf::reflect::ProtobufValue for RevisionRange {
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 pub enum RevisionState {
-    Local = 0,
+    Sync = 0,
     Ack = 1,
 }
 
@@ -969,7 +969,7 @@ impl ::protobuf::ProtobufEnum for RevisionState {
 
     fn from_i32(value: i32) -> ::std::option::Option<RevisionState> {
         match value {
-            0 => ::std::option::Option::Some(RevisionState::Local),
+            0 => ::std::option::Option::Some(RevisionState::Sync),
             1 => ::std::option::Option::Some(RevisionState::Ack),
             _ => ::std::option::Option::None
         }
@@ -977,7 +977,7 @@ impl ::protobuf::ProtobufEnum for RevisionState {
 
     fn values() -> &'static [Self] {
         static values: &'static [RevisionState] = &[
-            RevisionState::Local,
+            RevisionState::Sync,
             RevisionState::Ack,
         ];
         values
@@ -996,7 +996,7 @@ impl ::std::marker::Copy for RevisionState {
 
 impl ::std::default::Default for RevisionState {
     fn default() -> Self {
-        RevisionState::Local
+        RevisionState::Sync
     }
 }
 
@@ -1057,68 +1057,68 @@ impl ::protobuf::reflect::ProtobufValue for RevType {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0erevision.proto\"\xbc\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\
+    \n\x0erevision.proto\"\xc2\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\
     \x18\x01\x20\x01(\x03R\tbaseRevId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\
     \x03R\x05revId\x12\x1d\n\ndelta_data\x18\x03\x20\x01(\x0cR\tdeltaData\
-    \x12\x10\n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x15\n\x06doc_id\x18\x05\
-    \x20\x01(\tR\x05docId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.RevTypeR\
-    \x02ty\x12\x17\n\x07user_id\x18\x07\x20\x01(\tR\x06userId\"3\n\x10Repeat\
-    edRevision\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.RevisionR\x05items\
-    \"\x1d\n\x05RevId\x12\x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\
-    \rRevisionRange\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\
-    \n\x05start\x18\x02\x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\
-    \x01(\x03R\x03end*#\n\rRevisionState\x12\t\n\x05Local\x10\0\x12\x07\n\
-    \x03Ack\x10\x01*4\n\x07RevType\x12\x13\n\x0fDeprecatedLocal\x10\0\x12\
-    \x14\n\x10DeprecatedRemote\x10\x01J\xe8\x07\n\x06\x12\x04\0\0\x1d\x01\n\
-    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\n\x01\n\n\n\
-    \x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
-    \x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\
-    \x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x18\
-    \x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\
-    \x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\
-    \x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\x04\0\
-    \x02\x02\x12\x03\x05\x04\x19\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\
-    \x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\n\x14\n\x0c\n\x05\x04\0\
-    \x02\x02\x03\x12\x03\x05\x17\x18\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\
-    \x04\x13\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\
-    \0\x02\x03\x01\x12\x03\x06\x0b\x0e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\
-    \x06\x11\x12\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\
-    \x04\0\x02\x04\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\0\x02\x04\x01\x12\
-    \x03\x07\x0b\x11\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x14\x15\n\x0b\
-    \n\x04\x04\0\x02\x05\x12\x03\x08\x04\x13\n\x0c\n\x05\x04\0\x02\x05\x06\
-    \x12\x03\x08\x04\x0b\n\x0c\n\x05\x04\0\x02\x05\x01\x12\x03\x08\x0c\x0e\n\
-    \x0c\n\x05\x04\0\x02\x05\x03\x12\x03\x08\x11\x12\n\x0b\n\x04\x04\0\x02\
-    \x06\x12\x03\t\x04\x17\n\x0c\n\x05\x04\0\x02\x06\x05\x12\x03\t\x04\n\n\
-    \x0c\n\x05\x04\0\x02\x06\x01\x12\x03\t\x0b\x12\n\x0c\n\x05\x04\0\x02\x06\
-    \x03\x12\x03\t\x15\x16\n\n\n\x02\x04\x01\x12\x04\x0b\0\r\x01\n\n\n\x03\
-    \x04\x01\x01\x12\x03\x0b\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x0c\
-    \x04\x20\n\x0c\n\x05\x04\x01\x02\0\x04\x12\x03\x0c\x04\x0c\n\x0c\n\x05\
-    \x04\x01\x02\0\x06\x12\x03\x0c\r\x15\n\x0c\n\x05\x04\x01\x02\0\x01\x12\
-    \x03\x0c\x16\x1b\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x0c\x1e\x1f\n\n\n\
-    \x02\x04\x02\x12\x04\x0e\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\
-    \r\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0f\x04\x14\n\x0c\n\x05\x04\x02\x02\
-    \0\x05\x12\x03\x0f\x04\t\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\n\x0f\
-    \n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0f\x12\x13\n\n\n\x02\x04\x03\x12\
-    \x04\x11\0\x15\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\x15\n\x0b\n\x04\
-    \x04\x03\x02\0\x12\x03\x12\x04\x16\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\
-    \x12\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x0b\x11\n\x0c\n\x05\
-    \x04\x03\x02\0\x03\x12\x03\x12\x14\x15\n\x0b\n\x04\x04\x03\x02\x01\x12\
-    \x03\x13\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x13\x04\t\n\x0c\
-    \n\x05\x04\x03\x02\x01\x01\x12\x03\x13\n\x0f\n\x0c\n\x05\x04\x03\x02\x01\
-    \x03\x12\x03\x13\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x14\x04\x12\
-    \n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x14\x04\t\n\x0c\n\x05\x04\x03\
-    \x02\x02\x01\x12\x03\x14\n\r\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x14\
-    \x10\x11\n\n\n\x02\x05\0\x12\x04\x16\0\x19\x01\n\n\n\x03\x05\0\x01\x12\
-    \x03\x16\x05\x12\n\x0b\n\x04\x05\0\x02\0\x12\x03\x17\x04\x0e\n\x0c\n\x05\
-    \x05\0\x02\0\x01\x12\x03\x17\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\
-    \x17\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x18\x04\x0c\n\x0c\n\x05\x05\
-    \0\x02\x01\x01\x12\x03\x18\x04\x07\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\
-    \x18\n\x0b\n\n\n\x02\x05\x01\x12\x04\x1a\0\x1d\x01\n\n\n\x03\x05\x01\x01\
-    \x12\x03\x1a\x05\x0c\n\x0b\n\x04\x05\x01\x02\0\x12\x03\x1b\x04\x18\n\x0c\
-    \n\x05\x05\x01\x02\0\x01\x12\x03\x1b\x04\x13\n\x0c\n\x05\x05\x01\x02\0\
-    \x02\x12\x03\x1b\x16\x17\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x1c\x04\x19\
-    \n\x0c\n\x05\x05\x01\x02\x01\x01\x12\x03\x1c\x04\x14\n\x0c\n\x05\x05\x01\
-    \x02\x01\x02\x12\x03\x1c\x17\x18b\x06proto3\
+    \x12\x10\n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x1b\n\tobject_id\x18\
+    \x05\x20\x01(\tR\x08objectId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.R\
+    evTypeR\x02ty\x12\x17\n\x07user_id\x18\x07\x20\x01(\tR\x06userId\"3\n\
+    \x10RepeatedRevision\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.Revision\
+    R\x05items\"\x1d\n\x05RevId\x12\x14\n\x05value\x18\x01\x20\x01(\x03R\x05\
+    value\"T\n\rRevisionRange\x12\x1b\n\tobject_id\x18\x01\x20\x01(\tR\x08ob\
+    jectId\x12\x14\n\x05start\x18\x02\x20\x01(\x03R\x05start\x12\x10\n\x03en\
+    d\x18\x03\x20\x01(\x03R\x03end*\"\n\rRevisionState\x12\x08\n\x04Sync\x10\
+    \0\x12\x07\n\x03Ack\x10\x01*4\n\x07RevType\x12\x13\n\x0fDeprecatedLocal\
+    \x10\0\x12\x14\n\x10DeprecatedRemote\x10\x01J\xe8\x07\n\x06\x12\x04\0\0\
+    \x1d\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\n\
+    \x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\n\x04\x04\0\x02\0\x12\
+    \x03\x03\x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\
+    \x05\x04\0\x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\
+    \x03\x03\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\
+    \x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\
+    \x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\
+    \x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x19\n\x0c\n\x05\x04\0\x02\x02\
+    \x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\n\x14\n\
+    \x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x17\x18\n\x0b\n\x04\x04\0\x02\
+    \x03\x12\x03\x06\x04\x13\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x04\n\
+    \n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06\x0b\x0e\n\x0c\n\x05\x04\0\x02\
+    \x03\x03\x12\x03\x06\x11\x12\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x04\
+    \x19\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\0\
+    \x02\x04\x01\x12\x03\x07\x0b\x14\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\
+    \x07\x17\x18\n\x0b\n\x04\x04\0\x02\x05\x12\x03\x08\x04\x13\n\x0c\n\x05\
+    \x04\0\x02\x05\x06\x12\x03\x08\x04\x0b\n\x0c\n\x05\x04\0\x02\x05\x01\x12\
+    \x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\x08\x11\x12\n\x0b\
+    \n\x04\x04\0\x02\x06\x12\x03\t\x04\x17\n\x0c\n\x05\x04\0\x02\x06\x05\x12\
+    \x03\t\x04\n\n\x0c\n\x05\x04\0\x02\x06\x01\x12\x03\t\x0b\x12\n\x0c\n\x05\
+    \x04\0\x02\x06\x03\x12\x03\t\x15\x16\n\n\n\x02\x04\x01\x12\x04\x0b\0\r\
+    \x01\n\n\n\x03\x04\x01\x01\x12\x03\x0b\x08\x18\n\x0b\n\x04\x04\x01\x02\0\
+    \x12\x03\x0c\x04\x20\n\x0c\n\x05\x04\x01\x02\0\x04\x12\x03\x0c\x04\x0c\n\
+    \x0c\n\x05\x04\x01\x02\0\x06\x12\x03\x0c\r\x15\n\x0c\n\x05\x04\x01\x02\0\
+    \x01\x12\x03\x0c\x16\x1b\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x0c\x1e\
+    \x1f\n\n\n\x02\x04\x02\x12\x04\x0e\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\
+    \x03\x0e\x08\r\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0f\x04\x14\n\x0c\n\x05\
+    \x04\x02\x02\0\x05\x12\x03\x0f\x04\t\n\x0c\n\x05\x04\x02\x02\0\x01\x12\
+    \x03\x0f\n\x0f\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0f\x12\x13\n\n\n\
+    \x02\x04\x03\x12\x04\x11\0\x15\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\
+    \x15\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x19\n\x0c\n\x05\x04\x03\
+    \x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\
+    \x0b\x14\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x12\x17\x18\n\x0b\n\x04\
+    \x04\x03\x02\x01\x12\x03\x13\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\
+    \x03\x13\x04\t\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x13\n\x0f\n\x0c\n\
+    \x05\x04\x03\x02\x01\x03\x12\x03\x13\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\
+    \x12\x03\x14\x04\x12\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x14\x04\t\n\
+    \x0c\n\x05\x04\x03\x02\x02\x01\x12\x03\x14\n\r\n\x0c\n\x05\x04\x03\x02\
+    \x02\x03\x12\x03\x14\x10\x11\n\n\n\x02\x05\0\x12\x04\x16\0\x19\x01\n\n\n\
+    \x03\x05\0\x01\x12\x03\x16\x05\x12\n\x0b\n\x04\x05\0\x02\0\x12\x03\x17\
+    \x04\r\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x17\x04\x08\n\x0c\n\x05\x05\0\
+    \x02\0\x02\x12\x03\x17\x0b\x0c\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x18\x04\
+    \x0c\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x18\x04\x07\n\x0c\n\x05\x05\0\
+    \x02\x01\x02\x12\x03\x18\n\x0b\n\n\n\x02\x05\x01\x12\x04\x1a\0\x1d\x01\n\
+    \n\n\x03\x05\x01\x01\x12\x03\x1a\x05\x0c\n\x0b\n\x04\x05\x01\x02\0\x12\
+    \x03\x1b\x04\x18\n\x0c\n\x05\x05\x01\x02\0\x01\x12\x03\x1b\x04\x13\n\x0c\
+    \n\x05\x05\x01\x02\0\x02\x12\x03\x1b\x16\x17\n\x0b\n\x04\x05\x01\x02\x01\
+    \x12\x03\x1c\x04\x19\n\x0c\n\x05\x05\x01\x02\x01\x01\x12\x03\x1c\x04\x14\
+    \n\x0c\n\x05\x05\x01\x02\x01\x02\x12\x03\x1c\x17\x18b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 214 - 213
shared-lib/flowy-collaboration/src/protobuf/model/ws.rs

@@ -24,66 +24,66 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(PartialEq,Clone,Default)]
-pub struct DocumentClientWSData {
+pub struct ClientRevisionWSData {
     // message fields
-    pub doc_id: ::std::string::String,
-    pub ty: DocumentClientWSDataType,
+    pub object_id: ::std::string::String,
+    pub ty: ClientRevisionWSDataType,
     pub revisions: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
-    pub id: ::std::string::String,
+    pub data_id: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a DocumentClientWSData {
-    fn default() -> &'a DocumentClientWSData {
-        <DocumentClientWSData as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a ClientRevisionWSData {
+    fn default() -> &'a ClientRevisionWSData {
+        <ClientRevisionWSData as ::protobuf::Message>::default_instance()
     }
 }
 
-impl DocumentClientWSData {
-    pub fn new() -> DocumentClientWSData {
+impl ClientRevisionWSData {
+    pub fn new() -> ClientRevisionWSData {
         ::std::default::Default::default()
     }
 
-    // string doc_id = 1;
+    // string object_id = 1;
 
 
-    pub fn get_doc_id(&self) -> &str {
-        &self.doc_id
+    pub fn get_object_id(&self) -> &str {
+        &self.object_id
     }
-    pub fn clear_doc_id(&mut self) {
-        self.doc_id.clear();
+    pub fn clear_object_id(&mut self) {
+        self.object_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_doc_id(&mut self, v: ::std::string::String) {
-        self.doc_id = v;
+    pub fn set_object_id(&mut self, v: ::std::string::String) {
+        self.object_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_doc_id(&mut self) -> &mut ::std::string::String {
-        &mut self.doc_id
+    pub fn mut_object_id(&mut self) -> &mut ::std::string::String {
+        &mut self.object_id
     }
 
     // Take field
-    pub fn take_doc_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    pub fn take_object_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.object_id, ::std::string::String::new())
     }
 
-    // .DocumentClientWSDataType ty = 2;
+    // .ClientRevisionWSDataType ty = 2;
 
 
-    pub fn get_ty(&self) -> DocumentClientWSDataType {
+    pub fn get_ty(&self) -> ClientRevisionWSDataType {
         self.ty
     }
     pub fn clear_ty(&mut self) {
-        self.ty = DocumentClientWSDataType::ClientPushRev;
+        self.ty = ClientRevisionWSDataType::ClientPushRev;
     }
 
     // Param is passed by value, moved
-    pub fn set_ty(&mut self, v: DocumentClientWSDataType) {
+    pub fn set_ty(&mut self, v: ClientRevisionWSDataType) {
         self.ty = v;
     }
 
@@ -120,34 +120,34 @@ impl DocumentClientWSData {
         self.revisions.take().unwrap_or_else(|| super::revision::RepeatedRevision::new())
     }
 
-    // string id = 4;
+    // string data_id = 4;
 
 
-    pub fn get_id(&self) -> &str {
-        &self.id
+    pub fn get_data_id(&self) -> &str {
+        &self.data_id
     }
-    pub fn clear_id(&mut self) {
-        self.id.clear();
+    pub fn clear_data_id(&mut self) {
+        self.data_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_id(&mut self, v: ::std::string::String) {
-        self.id = v;
+    pub fn set_data_id(&mut self, v: ::std::string::String) {
+        self.data_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_id(&mut self) -> &mut ::std::string::String {
-        &mut self.id
+    pub fn mut_data_id(&mut self) -> &mut ::std::string::String {
+        &mut self.data_id
     }
 
     // Take field
-    pub fn take_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.id, ::std::string::String::new())
+    pub fn take_data_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.data_id, ::std::string::String::new())
     }
 }
 
-impl ::protobuf::Message for DocumentClientWSData {
+impl ::protobuf::Message for ClientRevisionWSData {
     fn is_initialized(&self) -> bool {
         for v in &self.revisions {
             if !v.is_initialized() {
@@ -162,7 +162,7 @@ impl ::protobuf::Message for DocumentClientWSData {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.object_id)?;
                 },
                 2 => {
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 2, &mut self.unknown_fields)?
@@ -171,7 +171,7 @@ impl ::protobuf::Message for DocumentClientWSData {
                     ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.revisions)?;
                 },
                 4 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data_id)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -185,18 +185,18 @@ impl ::protobuf::Message for DocumentClientWSData {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.doc_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.doc_id);
+        if !self.object_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.object_id);
         }
-        if self.ty != DocumentClientWSDataType::ClientPushRev {
+        if self.ty != ClientRevisionWSDataType::ClientPushRev {
             my_size += ::protobuf::rt::enum_size(2, self.ty);
         }
         if let Some(ref v) = self.revisions.as_ref() {
             let len = v.compute_size();
             my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         }
-        if !self.id.is_empty() {
-            my_size += ::protobuf::rt::string_size(4, &self.id);
+        if !self.data_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(4, &self.data_id);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -204,10 +204,10 @@ impl ::protobuf::Message for DocumentClientWSData {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.doc_id.is_empty() {
-            os.write_string(1, &self.doc_id)?;
+        if !self.object_id.is_empty() {
+            os.write_string(1, &self.object_id)?;
         }
-        if self.ty != DocumentClientWSDataType::ClientPushRev {
+        if self.ty != ClientRevisionWSDataType::ClientPushRev {
             os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
         }
         if let Some(ref v) = self.revisions.as_ref() {
@@ -215,8 +215,8 @@ impl ::protobuf::Message for DocumentClientWSData {
             os.write_raw_varint32(v.get_cached_size())?;
             v.write_to_with_cached_sizes(os)?;
         }
-        if !self.id.is_empty() {
-            os.write_string(4, &self.id)?;
+        if !self.data_id.is_empty() {
+            os.write_string(4, &self.data_id)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -248,8 +248,8 @@ impl ::protobuf::Message for DocumentClientWSData {
         Self::descriptor_static()
     }
 
-    fn new() -> DocumentClientWSData {
-        DocumentClientWSData::new()
+    fn new() -> ClientRevisionWSData {
+        ClientRevisionWSData::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -257,121 +257,121 @@ impl ::protobuf::Message for DocumentClientWSData {
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "doc_id",
-                |m: &DocumentClientWSData| { &m.doc_id },
-                |m: &mut DocumentClientWSData| { &mut m.doc_id },
+                "object_id",
+                |m: &ClientRevisionWSData| { &m.object_id },
+                |m: &mut ClientRevisionWSData| { &mut m.object_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentClientWSDataType>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ClientRevisionWSDataType>>(
                 "ty",
-                |m: &DocumentClientWSData| { &m.ty },
-                |m: &mut DocumentClientWSData| { &mut m.ty },
+                |m: &ClientRevisionWSData| { &m.ty },
+                |m: &mut ClientRevisionWSData| { &mut m.ty },
             ));
             fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::revision::RepeatedRevision>>(
                 "revisions",
-                |m: &DocumentClientWSData| { &m.revisions },
-                |m: &mut DocumentClientWSData| { &mut m.revisions },
+                |m: &ClientRevisionWSData| { &m.revisions },
+                |m: &mut ClientRevisionWSData| { &mut m.revisions },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "id",
-                |m: &DocumentClientWSData| { &m.id },
-                |m: &mut DocumentClientWSData| { &mut m.id },
+                "data_id",
+                |m: &ClientRevisionWSData| { &m.data_id },
+                |m: &mut ClientRevisionWSData| { &mut m.data_id },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentClientWSData>(
-                "DocumentClientWSData",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<ClientRevisionWSData>(
+                "ClientRevisionWSData",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static DocumentClientWSData {
-        static instance: ::protobuf::rt::LazyV2<DocumentClientWSData> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(DocumentClientWSData::new)
+    fn default_instance() -> &'static ClientRevisionWSData {
+        static instance: ::protobuf::rt::LazyV2<ClientRevisionWSData> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(ClientRevisionWSData::new)
     }
 }
 
-impl ::protobuf::Clear for DocumentClientWSData {
+impl ::protobuf::Clear for ClientRevisionWSData {
     fn clear(&mut self) {
-        self.doc_id.clear();
-        self.ty = DocumentClientWSDataType::ClientPushRev;
+        self.object_id.clear();
+        self.ty = ClientRevisionWSDataType::ClientPushRev;
         self.revisions.clear();
-        self.id.clear();
+        self.data_id.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for DocumentClientWSData {
+impl ::std::fmt::Debug for ClientRevisionWSData {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentClientWSData {
+impl ::protobuf::reflect::ProtobufValue for ClientRevisionWSData {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
 }
 
 #[derive(PartialEq,Clone,Default)]
-pub struct DocumentServerWSData {
+pub struct ServerRevisionWSData {
     // message fields
-    pub doc_id: ::std::string::String,
-    pub ty: DocumentServerWSDataType,
+    pub object_id: ::std::string::String,
+    pub ty: ServerRevisionWSDataType,
     pub data: ::std::vec::Vec<u8>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a DocumentServerWSData {
-    fn default() -> &'a DocumentServerWSData {
-        <DocumentServerWSData as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a ServerRevisionWSData {
+    fn default() -> &'a ServerRevisionWSData {
+        <ServerRevisionWSData as ::protobuf::Message>::default_instance()
     }
 }
 
-impl DocumentServerWSData {
-    pub fn new() -> DocumentServerWSData {
+impl ServerRevisionWSData {
+    pub fn new() -> ServerRevisionWSData {
         ::std::default::Default::default()
     }
 
-    // string doc_id = 1;
+    // string object_id = 1;
 
 
-    pub fn get_doc_id(&self) -> &str {
-        &self.doc_id
+    pub fn get_object_id(&self) -> &str {
+        &self.object_id
     }
-    pub fn clear_doc_id(&mut self) {
-        self.doc_id.clear();
+    pub fn clear_object_id(&mut self) {
+        self.object_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_doc_id(&mut self, v: ::std::string::String) {
-        self.doc_id = v;
+    pub fn set_object_id(&mut self, v: ::std::string::String) {
+        self.object_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_doc_id(&mut self) -> &mut ::std::string::String {
-        &mut self.doc_id
+    pub fn mut_object_id(&mut self) -> &mut ::std::string::String {
+        &mut self.object_id
     }
 
     // Take field
-    pub fn take_doc_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    pub fn take_object_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.object_id, ::std::string::String::new())
     }
 
-    // .DocumentServerWSDataType ty = 2;
+    // .ServerRevisionWSDataType ty = 2;
 
 
-    pub fn get_ty(&self) -> DocumentServerWSDataType {
+    pub fn get_ty(&self) -> ServerRevisionWSDataType {
         self.ty
     }
     pub fn clear_ty(&mut self) {
-        self.ty = DocumentServerWSDataType::ServerAck;
+        self.ty = ServerRevisionWSDataType::ServerAck;
     }
 
     // Param is passed by value, moved
-    pub fn set_ty(&mut self, v: DocumentServerWSDataType) {
+    pub fn set_ty(&mut self, v: ServerRevisionWSDataType) {
         self.ty = v;
     }
 
@@ -402,7 +402,7 @@ impl DocumentServerWSData {
     }
 }
 
-impl ::protobuf::Message for DocumentServerWSData {
+impl ::protobuf::Message for ServerRevisionWSData {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -412,7 +412,7 @@ impl ::protobuf::Message for DocumentServerWSData {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.object_id)?;
                 },
                 2 => {
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 2, &mut self.unknown_fields)?
@@ -432,10 +432,10 @@ impl ::protobuf::Message for DocumentServerWSData {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.doc_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.doc_id);
+        if !self.object_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.object_id);
         }
-        if self.ty != DocumentServerWSDataType::ServerAck {
+        if self.ty != ServerRevisionWSDataType::ServerAck {
             my_size += ::protobuf::rt::enum_size(2, self.ty);
         }
         if !self.data.is_empty() {
@@ -447,10 +447,10 @@ impl ::protobuf::Message for DocumentServerWSData {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.doc_id.is_empty() {
-            os.write_string(1, &self.doc_id)?;
+        if !self.object_id.is_empty() {
+            os.write_string(1, &self.object_id)?;
         }
-        if self.ty != DocumentServerWSDataType::ServerAck {
+        if self.ty != ServerRevisionWSDataType::ServerAck {
             os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
         }
         if !self.data.is_empty() {
@@ -486,8 +486,8 @@ impl ::protobuf::Message for DocumentServerWSData {
         Self::descriptor_static()
     }
 
-    fn new() -> DocumentServerWSData {
-        DocumentServerWSData::new()
+    fn new() -> ServerRevisionWSData {
+        ServerRevisionWSData::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -495,50 +495,50 @@ impl ::protobuf::Message for DocumentServerWSData {
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "doc_id",
-                |m: &DocumentServerWSData| { &m.doc_id },
-                |m: &mut DocumentServerWSData| { &mut m.doc_id },
+                "object_id",
+                |m: &ServerRevisionWSData| { &m.object_id },
+                |m: &mut ServerRevisionWSData| { &mut m.object_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentServerWSDataType>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ServerRevisionWSDataType>>(
                 "ty",
-                |m: &DocumentServerWSData| { &m.ty },
-                |m: &mut DocumentServerWSData| { &mut m.ty },
+                |m: &ServerRevisionWSData| { &m.ty },
+                |m: &mut ServerRevisionWSData| { &mut m.ty },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
                 "data",
-                |m: &DocumentServerWSData| { &m.data },
-                |m: &mut DocumentServerWSData| { &mut m.data },
+                |m: &ServerRevisionWSData| { &m.data },
+                |m: &mut ServerRevisionWSData| { &mut m.data },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentServerWSData>(
-                "DocumentServerWSData",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<ServerRevisionWSData>(
+                "ServerRevisionWSData",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static DocumentServerWSData {
-        static instance: ::protobuf::rt::LazyV2<DocumentServerWSData> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(DocumentServerWSData::new)
+    fn default_instance() -> &'static ServerRevisionWSData {
+        static instance: ::protobuf::rt::LazyV2<ServerRevisionWSData> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(ServerRevisionWSData::new)
     }
 }
 
-impl ::protobuf::Clear for DocumentServerWSData {
+impl ::protobuf::Clear for ServerRevisionWSData {
     fn clear(&mut self) {
-        self.doc_id.clear();
-        self.ty = DocumentServerWSDataType::ServerAck;
+        self.object_id.clear();
+        self.ty = ServerRevisionWSDataType::ServerAck;
         self.data.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for DocumentServerWSData {
+impl ::std::fmt::Debug for ServerRevisionWSData {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentServerWSData {
+impl ::protobuf::reflect::ProtobufValue for ServerRevisionWSData {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -788,28 +788,28 @@ impl ::protobuf::reflect::ProtobufValue for NewDocumentUser {
 }
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum DocumentClientWSDataType {
+pub enum ClientRevisionWSDataType {
     ClientPushRev = 0,
     ClientPing = 1,
 }
 
-impl ::protobuf::ProtobufEnum for DocumentClientWSDataType {
+impl ::protobuf::ProtobufEnum for ClientRevisionWSDataType {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<DocumentClientWSDataType> {
+    fn from_i32(value: i32) -> ::std::option::Option<ClientRevisionWSDataType> {
         match value {
-            0 => ::std::option::Option::Some(DocumentClientWSDataType::ClientPushRev),
-            1 => ::std::option::Option::Some(DocumentClientWSDataType::ClientPing),
+            0 => ::std::option::Option::Some(ClientRevisionWSDataType::ClientPushRev),
+            1 => ::std::option::Option::Some(ClientRevisionWSDataType::ClientPing),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [DocumentClientWSDataType] = &[
-            DocumentClientWSDataType::ClientPushRev,
-            DocumentClientWSDataType::ClientPing,
+        static values: &'static [ClientRevisionWSDataType] = &[
+            ClientRevisionWSDataType::ClientPushRev,
+            ClientRevisionWSDataType::ClientPing,
         ];
         values
     }
@@ -817,55 +817,55 @@ impl ::protobuf::ProtobufEnum for DocumentClientWSDataType {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<DocumentClientWSDataType>("DocumentClientWSDataType", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ClientRevisionWSDataType>("ClientRevisionWSDataType", file_descriptor_proto())
         })
     }
 }
 
-impl ::std::marker::Copy for DocumentClientWSDataType {
+impl ::std::marker::Copy for ClientRevisionWSDataType {
 }
 
-impl ::std::default::Default for DocumentClientWSDataType {
+impl ::std::default::Default for ClientRevisionWSDataType {
     fn default() -> Self {
-        DocumentClientWSDataType::ClientPushRev
+        ClientRevisionWSDataType::ClientPushRev
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentClientWSDataType {
+impl ::protobuf::reflect::ProtobufValue for ClientRevisionWSDataType {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
 }
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum DocumentServerWSDataType {
+pub enum ServerRevisionWSDataType {
     ServerAck = 0,
     ServerPushRev = 1,
     ServerPullRev = 2,
     UserConnect = 3,
 }
 
-impl ::protobuf::ProtobufEnum for DocumentServerWSDataType {
+impl ::protobuf::ProtobufEnum for ServerRevisionWSDataType {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<DocumentServerWSDataType> {
+    fn from_i32(value: i32) -> ::std::option::Option<ServerRevisionWSDataType> {
         match value {
-            0 => ::std::option::Option::Some(DocumentServerWSDataType::ServerAck),
-            1 => ::std::option::Option::Some(DocumentServerWSDataType::ServerPushRev),
-            2 => ::std::option::Option::Some(DocumentServerWSDataType::ServerPullRev),
-            3 => ::std::option::Option::Some(DocumentServerWSDataType::UserConnect),
+            0 => ::std::option::Option::Some(ServerRevisionWSDataType::ServerAck),
+            1 => ::std::option::Option::Some(ServerRevisionWSDataType::ServerPushRev),
+            2 => ::std::option::Option::Some(ServerRevisionWSDataType::ServerPullRev),
+            3 => ::std::option::Option::Some(ServerRevisionWSDataType::UserConnect),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [DocumentServerWSDataType] = &[
-            DocumentServerWSDataType::ServerAck,
-            DocumentServerWSDataType::ServerPushRev,
-            DocumentServerWSDataType::ServerPullRev,
-            DocumentServerWSDataType::UserConnect,
+        static values: &'static [ServerRevisionWSDataType] = &[
+            ServerRevisionWSDataType::ServerAck,
+            ServerRevisionWSDataType::ServerPushRev,
+            ServerRevisionWSDataType::ServerPullRev,
+            ServerRevisionWSDataType::UserConnect,
         ];
         values
     }
@@ -873,87 +873,88 @@ impl ::protobuf::ProtobufEnum for DocumentServerWSDataType {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<DocumentServerWSDataType>("DocumentServerWSDataType", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ServerRevisionWSDataType>("ServerRevisionWSDataType", file_descriptor_proto())
         })
     }
 }
 
-impl ::std::marker::Copy for DocumentServerWSDataType {
+impl ::std::marker::Copy for ServerRevisionWSDataType {
 }
 
-impl ::std::default::Default for DocumentServerWSDataType {
+impl ::std::default::Default for ServerRevisionWSDataType {
     fn default() -> Self {
-        DocumentServerWSDataType::ServerAck
+        ServerRevisionWSDataType::ServerAck
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentServerWSDataType {
+impl ::protobuf::reflect::ProtobufValue for ServerRevisionWSDataType {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x08ws.proto\x1a\x0erevision.proto\"\x99\x01\n\x14DocumentClientWSData\
-    \x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12)\n\x02ty\x18\x02\
-    \x20\x01(\x0e2\x19.DocumentClientWSDataTypeR\x02ty\x12/\n\trevisions\x18\
-    \x03\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\x12\x0e\n\x02id\x18\
-    \x04\x20\x01(\tR\x02id\"l\n\x14DocumentServerWSData\x12\x15\n\x06doc_id\
-    \x18\x01\x20\x01(\tR\x05docId\x12)\n\x02ty\x18\x02\x20\x01(\x0e2\x19.Doc\
-    umentServerWSDataTypeR\x02ty\x12\x12\n\x04data\x18\x03\x20\x01(\x0cR\x04\
-    data\"f\n\x0fNewDocumentUser\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\
-    \x06userId\x12\x15\n\x06doc_id\x18\x02\x20\x01(\tR\x05docId\x12#\n\rrevi\
-    sion_data\x18\x03\x20\x01(\x0cR\x0crevisionData*=\n\x18DocumentClientWSD\
-    ataType\x12\x11\n\rClientPushRev\x10\0\x12\x0e\n\nClientPing\x10\x01*`\n\
-    \x18DocumentServerWSDataType\x12\r\n\tServerAck\x10\0\x12\x11\n\rServerP\
-    ushRev\x10\x01\x12\x11\n\rServerPullRev\x10\x02\x12\x0f\n\x0bUserConnect\
-    \x10\x03J\xb1\x07\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\x01\x0c\x12\x03\0\0\
-    \x12\n\t\n\x02\x03\0\x12\x03\x01\0\x18\n\n\n\x02\x04\0\x12\x04\x03\0\x08\
-    \x01\n\n\n\x03\x04\0\x01\x12\x03\x03\x08\x1c\n\x0b\n\x04\x04\0\x02\0\x12\
-    \x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x04\x04\n\n\x0c\n\
-    \x05\x04\0\x02\0\x01\x12\x03\x04\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\
-    \x03\x04\x14\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x05\x04$\n\x0c\n\x05\
-    \x04\0\x02\x01\x06\x12\x03\x05\x04\x1c\n\x0c\n\x05\x04\0\x02\x01\x01\x12\
-    \x03\x05\x1d\x1f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x05\"#\n\x0b\n\
-    \x04\x04\0\x02\x02\x12\x03\x06\x04#\n\x0c\n\x05\x04\0\x02\x02\x06\x12\
-    \x03\x06\x04\x14\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x06\x15\x1e\n\x0c\
-    \n\x05\x04\0\x02\x02\x03\x12\x03\x06!\"\n\x0b\n\x04\x04\0\x02\x03\x12\
-    \x03\x07\x04\x12\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x07\x04\n\n\x0c\n\
-    \x05\x04\0\x02\x03\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\0\x02\x03\x03\
-    \x12\x03\x07\x10\x11\n\n\n\x02\x04\x01\x12\x04\t\0\r\x01\n\n\n\x03\x04\
-    \x01\x01\x12\x03\t\x08\x1c\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\x16\n\
-    \x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\0\
-    \x01\x12\x03\n\x0b\x11\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x14\x15\n\
-    \x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04$\n\x0c\n\x05\x04\x01\x02\x01\
-    \x06\x12\x03\x0b\x04\x1c\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x1d\
-    \x1f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\"#\n\x0b\n\x04\x04\x01\
-    \x02\x02\x12\x03\x0c\x04\x13\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0c\
-    \x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0c\n\x0e\n\x0c\n\x05\x04\
-    \x01\x02\x02\x03\x12\x03\x0c\x11\x12\n\n\n\x02\x04\x02\x12\x04\x0e\0\x12\
-    \x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x17\n\x0b\n\x04\x04\x02\x02\0\
-    \x12\x03\x0f\x04\x17\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\x04\n\n\
-    \x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x0b\x12\n\x0c\n\x05\x04\x02\x02\
-    \0\x03\x12\x03\x0f\x15\x16\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\x04\
-    \x16\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x10\x04\n\n\x0c\n\x05\x04\
-    \x02\x02\x01\x01\x12\x03\x10\x0b\x11\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\
-    \x03\x10\x14\x15\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x11\x04\x1c\n\x0c\n\
-    \x05\x04\x02\x02\x02\x05\x12\x03\x11\x04\t\n\x0c\n\x05\x04\x02\x02\x02\
-    \x01\x12\x03\x11\n\x17\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x11\x1a\
-    \x1b\n\n\n\x02\x05\0\x12\x04\x13\0\x16\x01\n\n\n\x03\x05\0\x01\x12\x03\
-    \x13\x05\x1d\n\x0b\n\x04\x05\0\x02\0\x12\x03\x14\x04\x16\n\x0c\n\x05\x05\
-    \0\x02\0\x01\x12\x03\x14\x04\x11\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\
-    \x14\x15\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x15\x04\x13\n\x0c\n\x05\x05\0\
-    \x02\x01\x01\x12\x03\x15\x04\x0e\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\
-    \x15\x11\x12\n\n\n\x02\x05\x01\x12\x04\x17\0\x1c\x01\n\n\n\x03\x05\x01\
-    \x01\x12\x03\x17\x05\x1d\n\x0b\n\x04\x05\x01\x02\0\x12\x03\x18\x04\x12\n\
-    \x0c\n\x05\x05\x01\x02\0\x01\x12\x03\x18\x04\r\n\x0c\n\x05\x05\x01\x02\0\
-    \x02\x12\x03\x18\x10\x11\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x19\x04\x16\
-    \n\x0c\n\x05\x05\x01\x02\x01\x01\x12\x03\x19\x04\x11\n\x0c\n\x05\x05\x01\
-    \x02\x01\x02\x12\x03\x19\x14\x15\n\x0b\n\x04\x05\x01\x02\x02\x12\x03\x1a\
-    \x04\x16\n\x0c\n\x05\x05\x01\x02\x02\x01\x12\x03\x1a\x04\x11\n\x0c\n\x05\
-    \x05\x01\x02\x02\x02\x12\x03\x1a\x14\x15\n\x0b\n\x04\x05\x01\x02\x03\x12\
-    \x03\x1b\x04\x14\n\x0c\n\x05\x05\x01\x02\x03\x01\x12\x03\x1b\x04\x0f\n\
-    \x0c\n\x05\x05\x01\x02\x03\x02\x12\x03\x1b\x12\x13b\x06proto3\
+    \n\x08ws.proto\x1a\x0erevision.proto\"\xa8\x01\n\x14ClientRevisionWSData\
+    \x12\x1b\n\tobject_id\x18\x01\x20\x01(\tR\x08objectId\x12)\n\x02ty\x18\
+    \x02\x20\x01(\x0e2\x19.ClientRevisionWSDataTypeR\x02ty\x12/\n\trevisions\
+    \x18\x03\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\x12\x17\n\x07dat\
+    a_id\x18\x04\x20\x01(\tR\x06dataId\"r\n\x14ServerRevisionWSData\x12\x1b\
+    \n\tobject_id\x18\x01\x20\x01(\tR\x08objectId\x12)\n\x02ty\x18\x02\x20\
+    \x01(\x0e2\x19.ServerRevisionWSDataTypeR\x02ty\x12\x12\n\x04data\x18\x03\
+    \x20\x01(\x0cR\x04data\"f\n\x0fNewDocumentUser\x12\x17\n\x07user_id\x18\
+    \x01\x20\x01(\tR\x06userId\x12\x15\n\x06doc_id\x18\x02\x20\x01(\tR\x05do\
+    cId\x12#\n\rrevision_data\x18\x03\x20\x01(\x0cR\x0crevisionData*=\n\x18C\
+    lientRevisionWSDataType\x12\x11\n\rClientPushRev\x10\0\x12\x0e\n\nClient\
+    Ping\x10\x01*`\n\x18ServerRevisionWSDataType\x12\r\n\tServerAck\x10\0\
+    \x12\x11\n\rServerPushRev\x10\x01\x12\x11\n\rServerPullRev\x10\x02\x12\
+    \x0f\n\x0bUserConnect\x10\x03J\xb1\x07\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\
+    \x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\x12\x03\x01\0\x18\n\n\n\x02\x04\
+    \0\x12\x04\x03\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x03\x08\x1c\n\x0b\n\
+    \x04\x04\0\x02\0\x12\x03\x04\x04\x19\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
+    \x04\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x04\x0b\x14\n\x0c\n\x05\
+    \x04\0\x02\0\x03\x12\x03\x04\x17\x18\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
+    \x05\x04$\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x05\x04\x1c\n\x0c\n\x05\
+    \x04\0\x02\x01\x01\x12\x03\x05\x1d\x1f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\
+    \x03\x05\"#\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x06\x04#\n\x0c\n\x05\x04\0\
+    \x02\x02\x06\x12\x03\x06\x04\x14\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\
+    \x06\x15\x1e\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x06!\"\n\x0b\n\x04\
+    \x04\0\x02\x03\x12\x03\x07\x04\x17\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\
+    \x07\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x07\x0b\x12\n\x0c\n\x05\
+    \x04\0\x02\x03\x03\x12\x03\x07\x15\x16\n\n\n\x02\x04\x01\x12\x04\t\0\r\
+    \x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x1c\n\x0b\n\x04\x04\x01\x02\0\
+    \x12\x03\n\x04\x19\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\
+    \x05\x04\x01\x02\0\x01\x12\x03\n\x0b\x14\n\x0c\n\x05\x04\x01\x02\0\x03\
+    \x12\x03\n\x17\x18\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04$\n\x0c\n\
+    \x05\x04\x01\x02\x01\x06\x12\x03\x0b\x04\x1c\n\x0c\n\x05\x04\x01\x02\x01\
+    \x01\x12\x03\x0b\x1d\x1f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\"#\
+    \n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0c\x04\x13\n\x0c\n\x05\x04\x01\x02\
+    \x02\x05\x12\x03\x0c\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0c\n\
+    \x0e\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0c\x11\x12\n\n\n\x02\x04\
+    \x02\x12\x04\x0e\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x17\n\
+    \x0b\n\x04\x04\x02\x02\0\x12\x03\x0f\x04\x17\n\x0c\n\x05\x04\x02\x02\0\
+    \x05\x12\x03\x0f\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x0b\x12\
+    \n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0f\x15\x16\n\x0b\n\x04\x04\x02\
+    \x02\x01\x12\x03\x10\x04\x16\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x10\
+    \x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x10\x0b\x11\n\x0c\n\x05\
+    \x04\x02\x02\x01\x03\x12\x03\x10\x14\x15\n\x0b\n\x04\x04\x02\x02\x02\x12\
+    \x03\x11\x04\x1c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\x04\t\n\x0c\
+    \n\x05\x04\x02\x02\x02\x01\x12\x03\x11\n\x17\n\x0c\n\x05\x04\x02\x02\x02\
+    \x03\x12\x03\x11\x1a\x1b\n\n\n\x02\x05\0\x12\x04\x13\0\x16\x01\n\n\n\x03\
+    \x05\0\x01\x12\x03\x13\x05\x1d\n\x0b\n\x04\x05\0\x02\0\x12\x03\x14\x04\
+    \x16\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x14\x04\x11\n\x0c\n\x05\x05\0\
+    \x02\0\x02\x12\x03\x14\x14\x15\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x15\x04\
+    \x13\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x15\x04\x0e\n\x0c\n\x05\x05\0\
+    \x02\x01\x02\x12\x03\x15\x11\x12\n\n\n\x02\x05\x01\x12\x04\x17\0\x1c\x01\
+    \n\n\n\x03\x05\x01\x01\x12\x03\x17\x05\x1d\n\x0b\n\x04\x05\x01\x02\0\x12\
+    \x03\x18\x04\x12\n\x0c\n\x05\x05\x01\x02\0\x01\x12\x03\x18\x04\r\n\x0c\n\
+    \x05\x05\x01\x02\0\x02\x12\x03\x18\x10\x11\n\x0b\n\x04\x05\x01\x02\x01\
+    \x12\x03\x19\x04\x16\n\x0c\n\x05\x05\x01\x02\x01\x01\x12\x03\x19\x04\x11\
+    \n\x0c\n\x05\x05\x01\x02\x01\x02\x12\x03\x19\x14\x15\n\x0b\n\x04\x05\x01\
+    \x02\x02\x12\x03\x1a\x04\x16\n\x0c\n\x05\x05\x01\x02\x02\x01\x12\x03\x1a\
+    \x04\x11\n\x0c\n\x05\x05\x01\x02\x02\x02\x12\x03\x1a\x14\x15\n\x0b\n\x04\
+    \x05\x01\x02\x03\x12\x03\x1b\x04\x14\n\x0c\n\x05\x05\x01\x02\x03\x01\x12\
+    \x03\x1b\x04\x0f\n\x0c\n\x05\x05\x01\x02\x03\x02\x12\x03\x1b\x12\x13b\
+    \x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 3 - 3
shared-lib/flowy-collaboration/src/protobuf/proto/revision.proto

@@ -5,7 +5,7 @@ message Revision {
     int64 rev_id = 2;
     bytes delta_data = 3;
     string md5 = 4;
-    string doc_id = 5;
+    string object_id = 5;
     RevType ty = 6;
     string user_id = 7;
 }
@@ -16,12 +16,12 @@ message RevId {
     int64 value = 1;
 }
 message RevisionRange {
-    string doc_id = 1;
+    string object_id = 1;
     int64 start = 2;
     int64 end = 3;
 }
 enum RevisionState {
-    Local = 0;
+    Sync = 0;
     Ack = 1;
 }
 enum RevType {

+ 9 - 9
shared-lib/flowy-collaboration/src/protobuf/proto/ws.proto

@@ -1,15 +1,15 @@
 syntax = "proto3";
 import "revision.proto";
 
-message DocumentClientWSData {
-    string doc_id = 1;
-    DocumentClientWSDataType ty = 2;
+message ClientRevisionWSData {
+    string object_id = 1;
+    ClientRevisionWSDataType ty = 2;
     RepeatedRevision revisions = 3;
-    string id = 4;
+    string data_id = 4;
 }
-message DocumentServerWSData {
-    string doc_id = 1;
-    DocumentServerWSDataType ty = 2;
+message ServerRevisionWSData {
+    string object_id = 1;
+    ServerRevisionWSDataType ty = 2;
     bytes data = 3;
 }
 message NewDocumentUser {
@@ -17,11 +17,11 @@ message NewDocumentUser {
     string doc_id = 2;
     bytes revision_data = 3;
 }
-enum DocumentClientWSDataType {
+enum ClientRevisionWSDataType {
     ClientPushRev = 0;
     ClientPing = 1;
 }
-enum DocumentServerWSDataType {
+enum ServerRevisionWSDataType {
     ServerAck = 0;
     ServerPushRev = 1;
     ServerPullRev = 2;

+ 12 - 12
shared-lib/flowy-collaboration/src/server_document/document_manager.rs

@@ -1,7 +1,7 @@
 use crate::{
-    entities::{doc::DocumentInfo, ws::DocumentServerWSDataBuilder},
+    entities::{doc::DocumentInfo, ws::ServerRevisionWSDataBuilder},
     errors::{internal_error, CollaborateError, CollaborateResult},
-    protobuf::{DocumentClientWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
+    protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
     server_document::{document_pad::ServerDocument, RevisionSynchronizer, RevisionUser, SyncResponse},
 };
 use async_stream::stream;
@@ -57,16 +57,16 @@ impl ServerDocumentManager {
     pub async fn handle_client_revisions(
         &self,
         user: Arc<dyn RevisionUser>,
-        mut client_data: DocumentClientWSData,
+        mut client_data: ClientRevisionWSData,
     ) -> Result<(), CollaborateError> {
         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 ack_id = rev_id_from_str(&client_data.data_id)?;
+        let object_id = client_data.object_id;
 
-        let result = match self.get_document_handler(&doc_id).await {
+        let result = match self.get_document_handler(&object_id).await {
             None => {
-                let _ = self.create_document(&doc_id, repeated_revision).await.map_err(|e| {
+                let _ = self.create_document(&object_id, repeated_revision).await.map_err(|e| {
                     CollaborateError::internal().context(format!("Server crate document failed: {}", e))
                 })?;
                 Ok(())
@@ -78,8 +78,8 @@ impl ServerDocumentManager {
         };
 
         if result.is_ok() {
-            cloned_user.receive(SyncResponse::Ack(DocumentServerWSDataBuilder::build_ack_message(
-                &doc_id, ack_id,
+            cloned_user.receive(SyncResponse::Ack(ServerRevisionWSDataBuilder::build_ack_message(
+                &object_id, ack_id,
             )));
         }
         result
@@ -88,10 +88,10 @@ impl ServerDocumentManager {
     pub async fn handle_client_ping(
         &self,
         user: Arc<dyn RevisionUser>,
-        client_data: DocumentClientWSData,
+        client_data: ClientRevisionWSData,
     ) -> Result<(), CollaborateError> {
-        let rev_id = rev_id_from_str(&client_data.id)?;
-        let doc_id = client_data.doc_id.clone();
+        let rev_id = rev_id_from_str(&client_data.data_id)?;
+        let doc_id = client_data.object_id.clone();
         match self.get_document_handler(&doc_id).await {
             None => {
                 tracing::trace!("Document:{} doesn't exist, ignore client ping", doc_id);

+ 8 - 8
shared-lib/flowy-collaboration/src/server_document/revision_sync.rs

@@ -1,7 +1,7 @@
 use crate::{
     entities::{
         revision::RevisionRange,
-        ws::{DocumentServerWSData, DocumentServerWSDataBuilder},
+        ws::{ServerRevisionWSData, ServerRevisionWSDataBuilder},
     },
     errors::CollaborateError,
     protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
@@ -26,9 +26,9 @@ pub trait RevisionUser: Send + Sync + Debug {
 }
 
 pub enum SyncResponse {
-    Pull(DocumentServerWSData),
-    Push(DocumentServerWSData),
-    Ack(DocumentServerWSData),
+    Pull(ServerRevisionWSData),
+    Push(ServerRevisionWSData),
+    Ack(ServerRevisionWSData),
 }
 
 pub struct RevisionSynchronizer {
@@ -65,7 +65,7 @@ impl RevisionSynchronizer {
             // Return all the revisions to client
             let revisions = self.persistence.read_revisions(&doc_id, None).await?;
             let repeated_revision = repeated_revision_from_revision_pbs(revisions)?;
-            let data = DocumentServerWSDataBuilder::build_push_message(&doc_id, repeated_revision);
+            let data = ServerRevisionWSDataBuilder::build_push_message(&doc_id, repeated_revision);
             user.receive(SyncResponse::Push(data));
             return Ok(());
         }
@@ -89,11 +89,11 @@ impl RevisionSynchronizer {
                 } else {
                     // The server document is outdated, pull the missing revision from the client.
                     let range = RevisionRange {
-                        doc_id: self.doc_id.clone(),
+                        object_id: self.doc_id.clone(),
                         start: server_rev_id,
                         end: first_revision.rev_id,
                     };
-                    let msg = DocumentServerWSDataBuilder::build_pull_message(&self.doc_id, range);
+                    let msg = ServerRevisionWSDataBuilder::build_pull_message(&self.doc_id, range);
                     user.receive(SyncResponse::Pull(msg));
                 }
             },
@@ -220,7 +220,7 @@ impl RevisionSynchronizer {
         tracing::debug!("Push revision: {} -> {} to client", from, to);
         match repeated_revision_from_revision_pbs(revisions) {
             Ok(repeated_revision) => {
-                let data = DocumentServerWSDataBuilder::build_push_message(&self.doc_id, repeated_revision);
+                let data = ServerRevisionWSDataBuilder::build_push_message(&self.doc_id, repeated_revision);
                 user.receive(SyncResponse::Push(data));
             },
             Err(e) => tracing::error!("{}", e),

+ 4 - 4
shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -41,8 +41,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "RepeatedRevision"
         | "RevId"
         | "RevisionRange"
-        | "DocumentClientWSData"
-        | "DocumentServerWSData"
+        | "ClientRevisionWSData"
+        | "ServerRevisionWSData"
         | "NewDocumentUser"
         | "Workspace"
         | "RepeatedWorkspace"
@@ -89,8 +89,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "UserNotification"
         | "RevisionState"
         | "RevType"
-        | "DocumentClientWSDataType"
-        | "DocumentServerWSDataType"
+        | "ClientRevisionWSDataType"
+        | "ServerRevisionWSDataType"
         | "ExportType"
         | "TrashType"
         | "ViewType"