Browse Source

separate DocumentWSData into DocumentWSClientData and DocumentWSServerData

appflowy 3 years ago
parent
commit
0c7c3621d7
28 changed files with 968 additions and 515 deletions
  1. 12 19
      backend/src/services/document/ws_actor.rs
  2. 2 2
      backend/src/services/web_socket/entities/connect.rs
  3. 20 8
      backend/src/services/web_socket/entities/message.rs
  4. 5 5
      backend/src/services/web_socket/ws_client.rs
  5. 4 4
      backend/src/services/web_socket/ws_server.rs
  6. 103 164
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pb.dart
  7. 106 17
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pb.dart
  8. 26 13
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbenum.dart
  9. 37 14
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws.pbjson.dart
  10. 13 13
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pb.dart
  11. 5 5
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart
  12. 14 14
      frontend/rust-lib/flowy-document/src/services/doc/web_socket/http_ws_impl.rs
  13. 2 2
      frontend/rust-lib/flowy-document/src/services/doc/web_socket/local_ws_impl.rs
  14. 30 27
      frontend/rust-lib/flowy-document/src/services/doc/web_socket/web_socket.rs
  15. 4 4
      frontend/rust-lib/flowy-document/src/services/ws_receivers.rs
  16. 2 2
      frontend/rust-lib/flowy-net/src/services/ws/conn.rs
  17. 2 2
      frontend/rust-lib/flowy-net/src/services/ws/manager.rs
  18. 11 4
      frontend/rust-lib/flowy-net/src/services/ws/ws_local.rs
  19. 5 5
      frontend/rust-lib/flowy-sdk/src/deps_resolve/document_deps.rs
  20. 57 36
      shared-lib/flowy-collaboration/src/entities/ws.rs
  21. 435 94
      shared-lib/flowy-collaboration/src/protobuf/model/ws.rs
  22. 15 6
      shared-lib/flowy-collaboration/src/protobuf/proto/ws.proto
  23. 8 7
      shared-lib/flowy-collaboration/src/sync/synchronizer.rs
  24. 5 3
      shared-lib/flowy-derive/src/derive_cache/derive_cache.rs
  25. 3 3
      shared-lib/lib-ws/src/msg.rs
  26. 35 35
      shared-lib/lib-ws/src/protobuf/model/msg.rs
  27. 1 1
      shared-lib/lib-ws/src/protobuf/proto/msg.proto
  28. 6 6
      shared-lib/lib-ws/src/ws.rs

+ 12 - 19
backend/src/services/document/ws_actor.rs

@@ -1,19 +1,16 @@
 use crate::{
-    services::web_socket::{entities::Socket, WSClientData, WSMessageAdaptor, WSUser},
+    context::FlowyPersistence,
+    services::web_socket::{entities::Socket, WSClientData, WSUser, WebSocketMessage},
     util::serde_ext::{md5, parse_from_bytes},
 };
 use actix_rt::task::spawn_blocking;
-
-use crate::context::FlowyPersistence;
 use async_stream::stream;
 use backend_service::errors::{internal_error, Result, ServerError};
-use flowy_collaboration::protobuf::{DocumentWSData, DocumentWSDataType, NewDocumentUser, Revision};
-use futures::stream::StreamExt;
-
 use flowy_collaboration::{
-    protobuf::RepeatedRevision,
+    protobuf::{DocumentClientWSData, DocumentClientWSDataType, RepeatedRevision, Revision},
     sync::{RevisionUser, ServerDocumentManager, SyncResponse},
 };
+use futures::stream::StreamExt;
 use std::{convert::TryInto, sync::Arc};
 use tokio::sync::{mpsc, oneshot};
 
@@ -71,7 +68,7 @@ impl DocumentWebSocketActor {
     async fn handle_client_data(&self, client_data: WSClientData, persistence: Arc<FlowyPersistence>) -> Result<()> {
         let WSClientData { user, socket, data } = client_data;
         let document_data = spawn_blocking(move || {
-            let document_data: DocumentWSData = parse_from_bytes(&data)?;
+            let document_data: DocumentClientWSData = parse_from_bytes(&data)?;
             Result::Ok(document_data)
         })
         .await
@@ -89,19 +86,15 @@ impl DocumentWebSocketActor {
             socket,
             persistence,
         });
-        let result = match &document_data.ty {
-            DocumentWSDataType::Ack => Ok(()),
-            DocumentWSDataType::PushRev => self.handle_pushed_rev(user, document_data.data).await,
-            DocumentWSDataType::PullRev => Ok(()),
-            DocumentWSDataType::UserConnect => Ok(()),
-        };
-        match result {
+
+        match match &document_data.ty {
+            DocumentClientWSDataType::ClientPushRev => self.handle_pushed_rev(user, document_data.data).await,
+        } {
             Ok(_) => {},
             Err(e) => {
                 tracing::error!("[HTTP_SERVER_WS]: process client data error {:?}", e);
             },
         }
-
         Ok(())
     }
 
@@ -155,15 +148,15 @@ impl RevisionUser for ServerDocUser {
     fn receive(&self, resp: SyncResponse) {
         let result = match resp {
             SyncResponse::Pull(data) => {
-                let msg: WSMessageAdaptor = data.into();
+                let msg: WebSocketMessage = data.into();
                 self.socket.try_send(msg).map_err(internal_error)
             },
             SyncResponse::Push(data) => {
-                let msg: WSMessageAdaptor = data.into();
+                let msg: WebSocketMessage = data.into();
                 self.socket.try_send(msg).map_err(internal_error)
             },
             SyncResponse::Ack(data) => {
-                let msg: WSMessageAdaptor = data.into();
+                let msg: WebSocketMessage = data.into();
                 self.socket.try_send(msg).map_err(internal_error)
             },
             SyncResponse::NewRevision(revisions) => {

+ 2 - 2
backend/src/services/web_socket/entities/connect.rs

@@ -1,10 +1,10 @@
-use crate::services::web_socket::WSMessageAdaptor;
+use crate::services::web_socket::WebSocketMessage;
 use actix::{Message, Recipient};
 use backend_service::errors::ServerError;
 use serde::{Deserialize, Serialize};
 use std::fmt::Formatter;
 
-pub type Socket = Recipient<WSMessageAdaptor>;
+pub type Socket = Recipient<WebSocketMessage>;
 
 #[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
 pub struct SessionId(pub String);

+ 20 - 8
backend/src/services/web_socket/entities/message.rs

@@ -1,28 +1,40 @@
 use actix::Message;
 use bytes::Bytes;
-use flowy_collaboration::entities::ws::DocumentWSData;
-use lib_ws::{WSMessage, WSModule};
+use flowy_collaboration::entities::ws::{DocumentClientWSData, DocumentServerWSData};
+use lib_ws::{WSModule, WebScoketRawMessage};
 use std::convert::TryInto;
 
 #[derive(Debug, Message, Clone)]
 #[rtype(result = "()")]
-pub struct WSMessageAdaptor(pub Bytes);
+pub struct WebSocketMessage(pub Bytes);
 
-impl std::ops::Deref for WSMessageAdaptor {
+impl std::ops::Deref for WebSocketMessage {
     type Target = Bytes;
 
     fn deref(&self) -> &Self::Target { &self.0 }
 }
 
-impl std::convert::From<DocumentWSData> for WSMessageAdaptor {
-    fn from(data: DocumentWSData) -> Self {
+impl std::convert::From<DocumentClientWSData> for WebSocketMessage {
+    fn from(data: DocumentClientWSData) -> Self {
         let bytes: Bytes = data.try_into().unwrap();
-        let msg = WSMessage {
+        let msg = WebScoketRawMessage {
             module: WSModule::Doc,
             data: bytes.to_vec(),
         };
 
         let bytes: Bytes = msg.try_into().unwrap();
-        WSMessageAdaptor(bytes)
+        WebSocketMessage(bytes)
+    }
+}
+
+impl std::convert::From<DocumentServerWSData> for WebSocketMessage {
+    fn from(data: DocumentServerWSData) -> Self {
+        let bytes: Bytes = data.try_into().unwrap();
+        let msg = WebScoketRawMessage {
+            module: WSModule::Doc,
+            data: bytes.to_vec(),
+        };
+        let bytes: Bytes = msg.try_into().unwrap();
+        WebSocketMessage(bytes)
     }
 }

+ 5 - 5
backend/src/services/web_socket/ws_client.rs

@@ -3,15 +3,15 @@ use crate::{
     entities::logged_user::LoggedUser,
     services::web_socket::{
         entities::{Connect, Disconnect, Socket},
-        WSMessageAdaptor,
         WSServer,
+        WebSocketMessage,
     },
 };
 use actix::*;
 use actix_web::web::Data;
 use actix_web_actors::{ws, ws::Message::Text};
 use bytes::Bytes;
-use lib_ws::{WSMessage, WSModule};
+use lib_ws::{WSModule, WebScoketRawMessage};
 use std::{collections::HashMap, convert::TryFrom, sync::Arc, time::Instant};
 
 pub trait WebSocketReceiver: Send + Sync {
@@ -85,7 +85,7 @@ impl WSClient {
 
     fn handle_binary_message(&self, bytes: Bytes, socket: Socket) {
         // TODO: ok to unwrap?
-        let message: WSMessage = WSMessage::try_from(bytes).unwrap();
+        let message: WebScoketRawMessage = WebScoketRawMessage::try_from(bytes).unwrap();
         match self.ws_receivers.get(&message.module) {
             None => {
                 log::error!("Can't find the receiver for {:?}", message.module);
@@ -134,10 +134,10 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSClient {
     }
 }
 
-impl Handler<WSMessageAdaptor> for WSClient {
+impl Handler<WebSocketMessage> for WSClient {
     type Result = ();
 
-    fn handle(&mut self, msg: WSMessageAdaptor, ctx: &mut Self::Context) { ctx.binary(msg.0); }
+    fn handle(&mut self, msg: WebSocketMessage, ctx: &mut Self::Context) { ctx.binary(msg.0); }
 }
 
 impl Actor for WSClient {

+ 4 - 4
backend/src/services/web_socket/ws_server.rs

@@ -1,6 +1,6 @@
 use crate::services::web_socket::{
     entities::{Connect, Disconnect, Session, SessionId},
-    WSMessageAdaptor,
+    WebSocketMessage,
 };
 use actix::{Actor, Context, Handler};
 use backend_service::errors::ServerError;
@@ -20,7 +20,7 @@ impl std::default::Default for WSServer {
 impl WSServer {
     pub fn new() -> Self { WSServer::default() }
 
-    pub fn send(&self, _msg: WSMessageAdaptor) { unimplemented!() }
+    pub fn send(&self, _msg: WebSocketMessage) { unimplemented!() }
 }
 
 impl Actor for WSServer {
@@ -46,10 +46,10 @@ impl Handler<Disconnect> for WSServer {
     }
 }
 
-impl Handler<WSMessageAdaptor> for WSServer {
+impl Handler<WebSocketMessage> for WSServer {
     type Result = ();
 
-    fn handle(&mut self, _msg: WSMessageAdaptor, _ctx: &mut Context<Self>) -> Self::Result { unimplemented!() }
+    fn handle(&mut self, _msg: WebSocketMessage, _ctx: &mut Context<Self>) -> Self::Result { unimplemented!() }
 }
 
 impl actix::Supervised for WSServer {

+ 103 - 164
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pb.dart

@@ -13,13 +13,11 @@ import 'package:protobuf/protobuf.dart' as $pb;
 import 'revision.pb.dart' as $0;
 
 class CreateDocParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateDocParams',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateDocParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions',
-        subBuilder: $0.RepeatedRevision.create)
-    ..hasRequiredFields = false;
+    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
+    ..hasRequiredFields = false
+  ;
 
   CreateDocParams._() : super();
   factory CreateDocParams({
@@ -35,38 +33,31 @@ class CreateDocParams extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory CreateDocParams.fromBuffer($core.List<$core.int> i,
-          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory CreateDocParams.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')
+  factory CreateDocParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateDocParams.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')
   CreateDocParams clone() => CreateDocParams()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  CreateDocParams copyWith(void Function(CreateDocParams) updates) =>
-      super.copyWith((message) => updates(message as CreateDocParams))
-          as CreateDocParams; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateDocParams copyWith(void Function(CreateDocParams) updates) => super.copyWith((message) => updates(message as CreateDocParams)) as CreateDocParams; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static CreateDocParams create() => CreateDocParams._();
   CreateDocParams createEmptyInstance() => create();
   static $pb.PbList<CreateDocParams> createRepeated() => $pb.PbList<CreateDocParams>();
   @$core.pragma('dart2js:noInline')
-  static CreateDocParams getDefault() =>
-      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateDocParams>(create);
+  static CreateDocParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateDocParams>(create);
   static CreateDocParams? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get id => $_getSZ(0);
   @$pb.TagNumber(1)
-  set id($core.String v) {
-    $_setString(0, v);
-  }
-
+  set id($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasId() => $_has(0);
   @$pb.TagNumber(1)
@@ -75,10 +66,7 @@ class CreateDocParams extends $pb.GeneratedMessage {
   @$pb.TagNumber(2)
   $0.RepeatedRevision get revisions => $_getN(1);
   @$pb.TagNumber(2)
-  set revisions($0.RepeatedRevision v) {
-    setField(2, v);
-  }
-
+  set revisions($0.RepeatedRevision v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasRevisions() => $_has(1);
   @$pb.TagNumber(2)
@@ -88,14 +76,13 @@ class CreateDocParams extends $pb.GeneratedMessage {
 }
 
 class DocumentInfo extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentInfo',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentInfo', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'text')
     ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
     ..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId')
-    ..hasRequiredFields = false;
+    ..hasRequiredFields = false
+  ;
 
   DocumentInfo._() : super();
   factory DocumentInfo({
@@ -119,19 +106,18 @@ class DocumentInfo extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory DocumentInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory DocumentInfo.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')
+  factory DocumentInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DocumentInfo.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')
   DocumentInfo clone() => DocumentInfo()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  DocumentInfo copyWith(void Function(DocumentInfo) updates) =>
-      super.copyWith((message) => updates(message as DocumentInfo)) as DocumentInfo; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DocumentInfo copyWith(void Function(DocumentInfo) updates) => super.copyWith((message) => updates(message as DocumentInfo)) as DocumentInfo; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static DocumentInfo create() => DocumentInfo._();
@@ -144,10 +130,7 @@ class DocumentInfo extends $pb.GeneratedMessage {
   @$pb.TagNumber(1)
   $core.String get id => $_getSZ(0);
   @$pb.TagNumber(1)
-  set id($core.String v) {
-    $_setString(0, v);
-  }
-
+  set id($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasId() => $_has(0);
   @$pb.TagNumber(1)
@@ -156,10 +139,7 @@ class DocumentInfo extends $pb.GeneratedMessage {
   @$pb.TagNumber(2)
   $core.String get text => $_getSZ(1);
   @$pb.TagNumber(2)
-  set text($core.String v) {
-    $_setString(1, v);
-  }
-
+  set text($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
   $core.bool hasText() => $_has(1);
   @$pb.TagNumber(2)
@@ -168,10 +148,7 @@ class DocumentInfo extends $pb.GeneratedMessage {
   @$pb.TagNumber(3)
   $fixnum.Int64 get revId => $_getI64(2);
   @$pb.TagNumber(3)
-  set revId($fixnum.Int64 v) {
-    $_setInt64(2, v);
-  }
-
+  set revId($fixnum.Int64 v) { $_setInt64(2, v); }
   @$pb.TagNumber(3)
   $core.bool hasRevId() => $_has(2);
   @$pb.TagNumber(3)
@@ -180,10 +157,7 @@ class DocumentInfo extends $pb.GeneratedMessage {
   @$pb.TagNumber(4)
   $fixnum.Int64 get baseRevId => $_getI64(3);
   @$pb.TagNumber(4)
-  set baseRevId($fixnum.Int64 v) {
-    $_setInt64(3, v);
-  }
-
+  set baseRevId($fixnum.Int64 v) { $_setInt64(3, v); }
   @$pb.TagNumber(4)
   $core.bool hasBaseRevId() => $_has(3);
   @$pb.TagNumber(4)
@@ -191,13 +165,11 @@ class DocumentInfo extends $pb.GeneratedMessage {
 }
 
 class ResetDocumentParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetDocumentParams',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetDocumentParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions',
-        subBuilder: $0.RepeatedRevision.create)
-    ..hasRequiredFields = false;
+    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
+    ..hasRequiredFields = false
+  ;
 
   ResetDocumentParams._() : super();
   factory ResetDocumentParams({
@@ -213,38 +185,31 @@ class ResetDocumentParams extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory ResetDocumentParams.fromBuffer($core.List<$core.int> i,
-          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory ResetDocumentParams.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')
+  factory ResetDocumentParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ResetDocumentParams.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')
   ResetDocumentParams clone() => ResetDocumentParams()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  ResetDocumentParams copyWith(void Function(ResetDocumentParams) updates) =>
-      super.copyWith((message) => updates(message as ResetDocumentParams))
-          as ResetDocumentParams; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ResetDocumentParams copyWith(void Function(ResetDocumentParams) updates) => super.copyWith((message) => updates(message as ResetDocumentParams)) as ResetDocumentParams; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static ResetDocumentParams create() => ResetDocumentParams._();
   ResetDocumentParams createEmptyInstance() => create();
   static $pb.PbList<ResetDocumentParams> createRepeated() => $pb.PbList<ResetDocumentParams>();
   @$core.pragma('dart2js:noInline')
-  static ResetDocumentParams getDefault() =>
-      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ResetDocumentParams>(create);
+  static ResetDocumentParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ResetDocumentParams>(create);
   static ResetDocumentParams? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) {
-    $_setString(0, v);
-  }
-
+  set docId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasDocId() => $_has(0);
   @$pb.TagNumber(1)
@@ -253,10 +218,7 @@ class ResetDocumentParams extends $pb.GeneratedMessage {
   @$pb.TagNumber(2)
   $0.RepeatedRevision get revisions => $_getN(1);
   @$pb.TagNumber(2)
-  set revisions($0.RepeatedRevision v) {
-    setField(2, v);
-  }
-
+  set revisions($0.RepeatedRevision v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasRevisions() => $_has(1);
   @$pb.TagNumber(2)
@@ -266,12 +228,11 @@ class ResetDocumentParams extends $pb.GeneratedMessage {
 }
 
 class DocumentDelta extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentDelta',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentDelta', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'text')
-    ..hasRequiredFields = false;
+    ..hasRequiredFields = false
+  ;
 
   DocumentDelta._() : super();
   factory DocumentDelta({
@@ -287,19 +248,18 @@ class DocumentDelta extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory DocumentDelta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory DocumentDelta.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')
+  factory DocumentDelta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DocumentDelta.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')
   DocumentDelta clone() => DocumentDelta()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  DocumentDelta copyWith(void Function(DocumentDelta) updates) =>
-      super.copyWith((message) => updates(message as DocumentDelta)) as DocumentDelta; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DocumentDelta copyWith(void Function(DocumentDelta) updates) => super.copyWith((message) => updates(message as DocumentDelta)) as DocumentDelta; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static DocumentDelta create() => DocumentDelta._();
@@ -312,10 +272,7 @@ class DocumentDelta extends $pb.GeneratedMessage {
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) {
-    $_setString(0, v);
-  }
-
+  set docId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasDocId() => $_has(0);
   @$pb.TagNumber(1)
@@ -324,10 +281,7 @@ class DocumentDelta extends $pb.GeneratedMessage {
   @$pb.TagNumber(2)
   $core.String get text => $_getSZ(1);
   @$pb.TagNumber(2)
-  set text($core.String v) {
-    $_setString(1, v);
-  }
-
+  set text($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
   $core.bool hasText() => $_has(1);
   @$pb.TagNumber(2)
@@ -335,13 +289,12 @@ class DocumentDelta extends $pb.GeneratedMessage {
 }
 
 class NewDocUser extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NewDocUser',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NewDocUser', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
     ..aInt64(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..hasRequiredFields = false;
+    ..hasRequiredFields = false
+  ;
 
   NewDocUser._() : super();
   factory NewDocUser({
@@ -361,19 +314,18 @@ class NewDocUser extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory NewDocUser.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory NewDocUser.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')
+  factory NewDocUser.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory NewDocUser.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')
   NewDocUser clone() => NewDocUser()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  NewDocUser copyWith(void Function(NewDocUser) updates) =>
-      super.copyWith((message) => updates(message as NewDocUser)) as NewDocUser; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  NewDocUser copyWith(void Function(NewDocUser) updates) => super.copyWith((message) => updates(message as NewDocUser)) as NewDocUser; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static NewDocUser create() => NewDocUser._();
@@ -386,10 +338,7 @@ class NewDocUser extends $pb.GeneratedMessage {
   @$pb.TagNumber(1)
   $core.String get userId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set userId($core.String v) {
-    $_setString(0, v);
-  }
-
+  set userId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasUserId() => $_has(0);
   @$pb.TagNumber(1)
@@ -398,10 +347,7 @@ class NewDocUser extends $pb.GeneratedMessage {
   @$pb.TagNumber(2)
   $fixnum.Int64 get revId => $_getI64(1);
   @$pb.TagNumber(2)
-  set revId($fixnum.Int64 v) {
-    $_setInt64(1, v);
-  }
-
+  set revId($fixnum.Int64 v) { $_setInt64(1, v); }
   @$pb.TagNumber(2)
   $core.bool hasRevId() => $_has(1);
   @$pb.TagNumber(2)
@@ -410,10 +356,7 @@ class NewDocUser extends $pb.GeneratedMessage {
   @$pb.TagNumber(3)
   $core.String get docId => $_getSZ(2);
   @$pb.TagNumber(3)
-  set docId($core.String v) {
-    $_setString(2, v);
-  }
-
+  set docId($core.String v) { $_setString(2, v); }
   @$pb.TagNumber(3)
   $core.bool hasDocId() => $_has(2);
   @$pb.TagNumber(3)
@@ -421,11 +364,10 @@ class NewDocUser extends $pb.GeneratedMessage {
 }
 
 class DocIdentifier extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
-      const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocIdentifier',
-      createEmptyInstance: create)
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocIdentifier', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..hasRequiredFields = false;
+    ..hasRequiredFields = false
+  ;
 
   DocIdentifier._() : super();
   factory DocIdentifier({
@@ -437,19 +379,18 @@ class DocIdentifier extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory DocIdentifier.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
-      create()..mergeFromBuffer(i, r);
-  factory DocIdentifier.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')
+  factory DocIdentifier.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DocIdentifier.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')
   DocIdentifier clone() => DocIdentifier()..mergeFromMessage(this);
-  @$core.Deprecated('Using this can add significant overhead to your binary. '
-      'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-      'Will be removed in next major version')
-  DocIdentifier copyWith(void Function(DocIdentifier) updates) =>
-      super.copyWith((message) => updates(message as DocIdentifier)) as DocIdentifier; // ignore: deprecated_member_use
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DocIdentifier copyWith(void Function(DocIdentifier) updates) => super.copyWith((message) => updates(message as DocIdentifier)) as DocIdentifier; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   static DocIdentifier create() => DocIdentifier._();
@@ -462,12 +403,10 @@ class DocIdentifier extends $pb.GeneratedMessage {
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set docId($core.String v) {
-    $_setString(0, v);
-  }
-
+  set docId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
   $core.bool hasDocId() => $_has(0);
   @$pb.TagNumber(1)
   void clearDocId() => clearField(1);
 }
+

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

@@ -13,19 +13,19 @@ import 'ws.pbenum.dart';
 
 export 'ws.pbenum.dart';
 
-class DocumentWSData extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentWSData', createEmptyInstance: create)
+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<DocumentWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: DocumentWSDataType.Ack, valueOf: DocumentWSDataType.valueOf, enumValues: DocumentWSDataType.values)
+    ..e<DocumentClientWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: DocumentClientWSDataType.ClientPushRev, valueOf: DocumentClientWSDataType.valueOf, enumValues: DocumentClientWSDataType.values)
     ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
     ..hasRequiredFields = false
   ;
 
-  DocumentWSData._() : super();
-  factory DocumentWSData({
+  DocumentClientWSData._() : super();
+  factory DocumentClientWSData({
     $core.String? docId,
-    DocumentWSDataType? ty,
+    DocumentClientWSDataType? ty,
     $core.List<$core.int>? data,
     $core.String? id,
   }) {
@@ -44,26 +44,26 @@ class DocumentWSData extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory DocumentWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory DocumentWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  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);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  DocumentWSData clone() => DocumentWSData()..mergeFromMessage(this);
+  DocumentClientWSData clone() => DocumentClientWSData()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  DocumentWSData copyWith(void Function(DocumentWSData) updates) => super.copyWith((message) => updates(message as DocumentWSData)) as DocumentWSData; // ignore: deprecated_member_use
+  DocumentClientWSData copyWith(void Function(DocumentClientWSData) updates) => super.copyWith((message) => updates(message as DocumentClientWSData)) as DocumentClientWSData; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static DocumentWSData create() => DocumentWSData._();
-  DocumentWSData createEmptyInstance() => create();
-  static $pb.PbList<DocumentWSData> createRepeated() => $pb.PbList<DocumentWSData>();
+  static DocumentClientWSData create() => DocumentClientWSData._();
+  DocumentClientWSData createEmptyInstance() => create();
+  static $pb.PbList<DocumentClientWSData> createRepeated() => $pb.PbList<DocumentClientWSData>();
   @$core.pragma('dart2js:noInline')
-  static DocumentWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentWSData>(create);
-  static DocumentWSData? _defaultInstance;
+  static DocumentClientWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentClientWSData>(create);
+  static DocumentClientWSData? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);
@@ -75,9 +75,98 @@ class DocumentWSData extends $pb.GeneratedMessage {
   void clearDocId() => clearField(1);
 
   @$pb.TagNumber(2)
-  DocumentWSDataType get ty => $_getN(1);
+  DocumentClientWSDataType get ty => $_getN(1);
   @$pb.TagNumber(2)
-  set ty(DocumentWSDataType v) { setField(2, v); }
+  set ty(DocumentClientWSDataType v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasTy() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearTy() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.List<$core.int> get data => $_getN(2);
+  @$pb.TagNumber(3)
+  set data($core.List<$core.int> v) { $_setBytes(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasData() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearData() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get id => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set id($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasId() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearId() => 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)
+    ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
+    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
+    ..hasRequiredFields = false
+  ;
+
+  DocumentServerWSData._() : super();
+  factory DocumentServerWSData({
+    $core.String? docId,
+    DocumentServerWSDataType? ty,
+    $core.List<$core.int>? data,
+    $core.String? id,
+  }) {
+    final _result = create();
+    if (docId != null) {
+      _result.docId = docId;
+    }
+    if (ty != null) {
+      _result.ty = ty;
+    }
+    if (data != null) {
+      _result.data = data;
+    }
+    if (id != null) {
+      _result.id = id;
+    }
+    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);
+  @$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);
+  @$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
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static DocumentServerWSData create() => DocumentServerWSData._();
+  DocumentServerWSData createEmptyInstance() => create();
+  static $pb.PbList<DocumentServerWSData> createRepeated() => $pb.PbList<DocumentServerWSData>();
+  @$core.pragma('dart2js:noInline')
+  static DocumentServerWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentServerWSData>(create);
+  static DocumentServerWSData? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get docId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set docId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasDocId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearDocId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  DocumentServerWSDataType get ty => $_getN(1);
+  @$pb.TagNumber(2)
+  set ty(DocumentServerWSDataType v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasTy() => $_has(1);
   @$pb.TagNumber(2)

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

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

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

@@ -8,32 +8,55 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use documentWSDataTypeDescriptor instead')
-const DocumentWSDataType$json = const {
-  '1': 'DocumentWSDataType',
+@$core.Deprecated('Use documentClientWSDataTypeDescriptor instead')
+const DocumentClientWSDataType$json = const {
+  '1': 'DocumentClientWSDataType',
   '2': const [
-    const {'1': 'Ack', '2': 0},
-    const {'1': 'PushRev', '2': 1},
-    const {'1': 'PullRev', '2': 2},
+    const {'1': 'ClientPushRev', '2': 0},
+  ],
+};
+
+/// Descriptor for `DocumentClientWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List documentClientWSDataTypeDescriptor = $convert.base64Decode('ChhEb2N1bWVudENsaWVudFdTRGF0YVR5cGUSEQoNQ2xpZW50UHVzaFJldhAA');
+@$core.Deprecated('Use documentServerWSDataTypeDescriptor instead')
+const DocumentServerWSDataType$json = const {
+  '1': 'DocumentServerWSDataType',
+  '2': const [
+    const {'1': 'ServerAck', '2': 0},
+    const {'1': 'ServerPushRev', '2': 1},
+    const {'1': 'ServerPullRev', '2': 2},
     const {'1': 'UserConnect', '2': 3},
   ],
 };
 
-/// Descriptor for `DocumentWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List documentWSDataTypeDescriptor = $convert.base64Decode('ChJEb2N1bWVudFdTRGF0YVR5cGUSBwoDQWNrEAASCwoHUHVzaFJldhABEgsKB1B1bGxSZXYQAhIPCgtVc2VyQ29ubmVjdBAD');
-@$core.Deprecated('Use documentWSDataDescriptor instead')
-const DocumentWSData$json = const {
-  '1': 'DocumentWSData',
+/// 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',
+  '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': 'data', '3': 3, '4': 1, '5': 12, '10': 'data'},
+    const {'1': 'id', '3': 4, '4': 1, '5': 9, '10': 'id'},
+  ],
+};
+
+/// Descriptor for `DocumentClientWSData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List documentClientWSDataDescriptor = $convert.base64Decode('ChREb2N1bWVudENsaWVudFdTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEikKAnR5GAIgASgOMhkuRG9jdW1lbnRDbGllbnRXU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRhEg4KAmlkGAQgASgJUgJpZA==');
+@$core.Deprecated('Use documentServerWSDataDescriptor instead')
+const DocumentServerWSData$json = const {
+  '1': 'DocumentServerWSData',
   '2': const [
     const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
-    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.DocumentWSDataType', '10': 'ty'},
+    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.DocumentServerWSDataType', '10': 'ty'},
     const {'1': 'data', '3': 3, '4': 1, '5': 12, '10': 'data'},
     const {'1': 'id', '3': 4, '4': 1, '5': 9, '10': 'id'},
   ],
 };
 
-/// Descriptor for `DocumentWSData`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List documentWSDataDescriptor = $convert.base64Decode('Cg5Eb2N1bWVudFdTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEiMKAnR5GAIgASgOMhMuRG9jdW1lbnRXU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRhEg4KAmlkGAQgASgJUgJpZA==');
+/// Descriptor for `DocumentServerWSData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List documentServerWSDataDescriptor = $convert.base64Decode('ChREb2N1bWVudFNlcnZlcldTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEikKAnR5GAIgASgOMhkuRG9jdW1lbnRTZXJ2ZXJXU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRhEg4KAmlkGAQgASgJUgJpZA==');
 @$core.Deprecated('Use newDocumentUserDescriptor instead')
 const NewDocumentUser$json = const {
   '1': 'NewDocumentUser',

+ 13 - 13
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pb.dart

@@ -13,15 +13,15 @@ import 'msg.pbenum.dart';
 
 export 'msg.pbenum.dart';
 
-class WSMessage extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WSMessage', createEmptyInstance: create)
+class WebScoketRawMessage extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WebScoketRawMessage', createEmptyInstance: create)
     ..e<WSModule>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'module', $pb.PbFieldType.OE, defaultOrMaker: WSModule.Doc, valueOf: WSModule.valueOf, enumValues: WSModule.values)
     ..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
     ..hasRequiredFields = false
   ;
 
-  WSMessage._() : super();
-  factory WSMessage({
+  WebScoketRawMessage._() : super();
+  factory WebScoketRawMessage({
     WSModule? module,
     $core.List<$core.int>? data,
   }) {
@@ -34,26 +34,26 @@ class WSMessage extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory WSMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory WSMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory WebScoketRawMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory WebScoketRawMessage.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')
-  WSMessage clone() => WSMessage()..mergeFromMessage(this);
+  WebScoketRawMessage clone() => WebScoketRawMessage()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  WSMessage copyWith(void Function(WSMessage) updates) => super.copyWith((message) => updates(message as WSMessage)) as WSMessage; // ignore: deprecated_member_use
+  WebScoketRawMessage copyWith(void Function(WebScoketRawMessage) updates) => super.copyWith((message) => updates(message as WebScoketRawMessage)) as WebScoketRawMessage; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static WSMessage create() => WSMessage._();
-  WSMessage createEmptyInstance() => create();
-  static $pb.PbList<WSMessage> createRepeated() => $pb.PbList<WSMessage>();
+  static WebScoketRawMessage create() => WebScoketRawMessage._();
+  WebScoketRawMessage createEmptyInstance() => create();
+  static $pb.PbList<WebScoketRawMessage> createRepeated() => $pb.PbList<WebScoketRawMessage>();
   @$core.pragma('dart2js:noInline')
-  static WSMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WSMessage>(create);
-  static WSMessage? _defaultInstance;
+  static WebScoketRawMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WebScoketRawMessage>(create);
+  static WebScoketRawMessage? _defaultInstance;
 
   @$pb.TagNumber(1)
   WSModule get module => $_getN(0);

+ 5 - 5
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart

@@ -18,14 +18,14 @@ const WSModule$json = const {
 
 /// Descriptor for `WSModule`. Decode as a `google.protobuf.EnumDescriptorProto`.
 final $typed_data.Uint8List wSModuleDescriptor = $convert.base64Decode('CghXU01vZHVsZRIHCgNEb2MQAA==');
-@$core.Deprecated('Use wSMessageDescriptor instead')
-const WSMessage$json = const {
-  '1': 'WSMessage',
+@$core.Deprecated('Use webScoketRawMessageDescriptor instead')
+const WebScoketRawMessage$json = const {
+  '1': 'WebScoketRawMessage',
   '2': const [
     const {'1': 'module', '3': 1, '4': 1, '5': 14, '6': '.WSModule', '10': 'module'},
     const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'},
   ],
 };
 
-/// Descriptor for `WSMessage`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List wSMessageDescriptor = $convert.base64Decode('CglXU01lc3NhZ2USIQoGbW9kdWxlGAEgASgOMgkuV1NNb2R1bGVSBm1vZHVsZRISCgRkYXRhGAIgASgMUgRkYXRh');
+/// Descriptor for `WebScoketRawMessage`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List webScoketRawMessageDescriptor = $convert.base64Decode('ChNXZWJTY29rZXRSYXdNZXNzYWdlEiEKBm1vZHVsZRgBIAEoDjIJLldTTW9kdWxlUgZtb2R1bGUSEgoEZGF0YRgCIAEoDFIEZGF0YQ==');

+ 14 - 14
frontend/rust-lib/flowy-document/src/services/doc/web_socket/http_ws_impl.rs

@@ -6,7 +6,7 @@ use async_stream::stream;
 use bytes::Bytes;
 use flowy_collaboration::entities::{
     revision::RevisionRange,
-    ws::{DocumentWSData, DocumentWSDataType, NewDocumentUser},
+    ws::{DocumentClientWSData, DocumentServerWSData, DocumentServerWSDataType, NewDocumentUser},
 };
 use flowy_error::{internal_error, FlowyError, FlowyResult};
 use futures::stream::StreamExt;
@@ -28,8 +28,8 @@ pub(crate) struct HttpWebSocketManager {
     data_provider: Arc<dyn DocumentWSSinkDataProvider>,
     stream_consumer: Arc<dyn DocumentWSSteamConsumer>,
     ws: Arc<dyn DocumentWebSocket>,
-    ws_msg_tx: UnboundedSender<DocumentWSData>,
-    ws_msg_rx: Option<UnboundedReceiver<DocumentWSData>>,
+    ws_msg_tx: UnboundedSender<DocumentServerWSData>,
+    ws_msg_rx: Option<UnboundedReceiver<DocumentServerWSData>>,
     stop_sync_tx: SinkStopTx,
     state: broadcast::Sender<WSConnectState>,
 }
@@ -91,7 +91,7 @@ impl DocumentWebSocketManager for Arc<HttpWebSocketManager> {
 }
 
 impl DocumentWSReceiver for HttpWebSocketManager {
-    fn receive_ws_data(&self, doc_data: DocumentWSData) {
+    fn receive_ws_data(&self, doc_data: DocumentServerWSData) {
         match self.ws_msg_tx.send(doc_data) {
             Ok(_) => {},
             Err(e) => tracing::error!("❌Propagate ws message failed. {}", e),
@@ -108,7 +108,7 @@ impl DocumentWSReceiver for HttpWebSocketManager {
 
 pub trait DocumentWSSteamConsumer: Send + Sync {
     fn receive_push_revision(&self, bytes: Bytes) -> FutureResult<(), FlowyError>;
-    fn receive_ack(&self, id: String, ty: DocumentWSDataType) -> FutureResult<(), FlowyError>;
+    fn receive_ack(&self, id: String, ty: DocumentServerWSDataType) -> FutureResult<(), FlowyError>;
     fn receive_new_user_connect(&self, new_user: NewDocumentUser) -> FutureResult<(), FlowyError>;
     fn pull_revisions_in_range(&self, range: RevisionRange) -> FutureResult<(), FlowyError>;
 }
@@ -116,7 +116,7 @@ pub trait DocumentWSSteamConsumer: Send + Sync {
 pub struct DocumentWSStream {
     doc_id: String,
     consumer: Arc<dyn DocumentWSSteamConsumer>,
-    ws_msg_rx: Option<mpsc::UnboundedReceiver<DocumentWSData>>,
+    ws_msg_rx: Option<mpsc::UnboundedReceiver<DocumentServerWSData>>,
     stop_rx: Option<SinkStopRx>,
 }
 
@@ -124,7 +124,7 @@ impl DocumentWSStream {
     pub fn new(
         doc_id: &str,
         consumer: Arc<dyn DocumentWSSteamConsumer>,
-        ws_msg_rx: mpsc::UnboundedReceiver<DocumentWSData>,
+        ws_msg_rx: mpsc::UnboundedReceiver<DocumentServerWSData>,
         stop_rx: SinkStopRx,
     ) -> Self {
         DocumentWSStream {
@@ -171,8 +171,8 @@ impl DocumentWSStream {
             .await;
     }
 
-    async fn handle_message(&self, msg: DocumentWSData) -> FlowyResult<()> {
-        let DocumentWSData {
+    async fn handle_message(&self, msg: DocumentServerWSData) -> FlowyResult<()> {
+        let DocumentServerWSData {
             doc_id: _,
             ty,
             data,
@@ -184,18 +184,18 @@ impl DocumentWSStream {
 
         tracing::debug!("[DocumentStream]: receives new message: {:?}", ty);
         match ty {
-            DocumentWSDataType::PushRev => {
+            DocumentServerWSDataType::ServerPushRev => {
                 let _ = self.consumer.receive_push_revision(bytes).await?;
                 let _ = self.consumer.receive_ack(id, ty).await;
             },
-            DocumentWSDataType::PullRev => {
+            DocumentServerWSDataType::ServerPullRev => {
                 let range = RevisionRange::try_from(bytes)?;
                 let _ = self.consumer.pull_revisions_in_range(range).await?;
             },
-            DocumentWSDataType::Ack => {
+            DocumentServerWSDataType::ServerAck => {
                 let _ = self.consumer.receive_ack(id, ty).await;
             },
-            DocumentWSDataType::UserConnect => {
+            DocumentServerWSDataType::UserConnect => {
                 let new_user = NewDocumentUser::try_from(bytes)?;
                 let _ = self.consumer.receive_new_user_connect(new_user).await;
                 // Notify the user that someone has connected to this document
@@ -211,7 +211,7 @@ pub type SinkStopRx = broadcast::Receiver<()>;
 pub type SinkStopTx = broadcast::Sender<()>;
 
 pub trait DocumentWSSinkDataProvider: Send + Sync {
-    fn next(&self) -> FutureResult<Option<DocumentWSData>, FlowyError>;
+    fn next(&self) -> FutureResult<Option<DocumentClientWSData>, FlowyError>;
 }
 
 pub struct DocumentWSSink {

+ 2 - 2
frontend/rust-lib/flowy-document/src/services/doc/web_socket/local_ws_impl.rs

@@ -1,5 +1,5 @@
 use crate::services::doc::{web_socket::DocumentWebSocketManager, DocumentWSReceiver};
-use flowy_collaboration::entities::ws::DocumentWSData;
+use flowy_collaboration::entities::ws::DocumentServerWSData;
 use lib_ws::WSConnectState;
 use std::sync::Arc;
 
@@ -12,7 +12,7 @@ impl DocumentWebSocketManager for Arc<LocalWebSocketManager> {
 }
 
 impl DocumentWSReceiver for LocalWebSocketManager {
-    fn receive_ws_data(&self, _doc_data: DocumentWSData) {}
+    fn receive_ws_data(&self, _doc_data: DocumentServerWSData) {}
 
     fn connect_state_changed(&self, _state: &WSConnectState) {}
 }

+ 30 - 27
frontend/rust-lib/flowy-document/src/services/doc/web_socket/web_socket.rs

@@ -16,13 +16,14 @@ use bytes::Bytes;
 use flowy_collaboration::{
     entities::{
         revision::{RepeatedRevision, RevType, Revision, RevisionRange},
-        ws::{DocumentWSData, DocumentWSDataBuilder, DocumentWSDataType, NewDocumentUser},
+        ws::{DocumentClientWSData, DocumentClientWSDataType, DocumentServerWSDataBuilder, NewDocumentUser},
     },
     errors::CollaborateResult,
 };
 use flowy_error::{internal_error, FlowyError, FlowyResult};
 use lib_infra::future::FutureResult;
 
+use flowy_collaboration::entities::ws::DocumentServerWSDataType;
 use lib_ws::WSConnectState;
 use std::{
     collections::VecDeque,
@@ -74,22 +75,24 @@ async fn notify_user_has_connected(
     rev_manager: Arc<RevisionManager>,
     shared_sink: Arc<SharedWSSinkDataProvider>,
 ) {
-    let need_notify = match shared_sink.front().await {
-        None => true,
-        Some(data) => data.ty != DocumentWSDataType::UserConnect,
-    };
-
-    if need_notify {
-        let revision_data: Bytes = rev_manager.latest_revision().await.try_into().unwrap();
-        let new_connect = NewDocumentUser {
-            user_id: user_id.to_owned(),
-            doc_id: doc_id.to_owned(),
-            revision_data: revision_data.to_vec(),
-        };
-
-        let data = DocumentWSDataBuilder::build_new_document_user_message(doc_id, new_connect);
-        shared_sink.push_front(data).await;
-    }
+    // let need_notify = match shared_sink.front().await {
+    //     None => true,
+    //     Some(data) => data.ty != DocumentClientWSDataType::UserConnect,
+    // };
+    //
+    // if need_notify {
+    //     let revision_data: Bytes =
+    // rev_manager.latest_revision().await.try_into().unwrap();
+    //     let new_connect = NewDocumentUser {
+    //         user_id: user_id.to_owned(),
+    //         doc_id: doc_id.to_owned(),
+    //         revision_data: revision_data.to_vec(),
+    //     };
+    //
+    //     let data =
+    // DocumentWSDataBuilder::build_new_document_user_message(doc_id,
+    // new_connect);     shared_sink.push_front(data).await;
+    // }
 }
 
 fn listen_document_ws_state(
@@ -135,7 +138,7 @@ impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
         })
     }
 
-    fn receive_ack(&self, id: String, ty: DocumentWSDataType) -> FutureResult<(), FlowyError> {
+    fn receive_ack(&self, id: String, ty: DocumentServerWSDataType) -> FutureResult<(), FlowyError> {
         let shared_sink = self.shared_sink.clone();
         FutureResult::new(async move { shared_sink.ack(id, ty).await })
     }
@@ -154,7 +157,7 @@ impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
                 .await?
                 .into_iter()
                 .map(|revision| revision.into())
-                .collect::<Vec<DocumentWSData>>();
+                .collect::<Vec<DocumentClientWSData>>();
 
             shared_sink.append(data).await;
             Ok(())
@@ -164,7 +167,7 @@ impl DocumentWSSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
 
 pub(crate) struct DocumentWSSinkDataProviderAdapter(pub(crate) Arc<SharedWSSinkDataProvider>);
 impl DocumentWSSinkDataProvider for DocumentWSSinkDataProviderAdapter {
-    fn next(&self) -> FutureResult<Option<DocumentWSData>, FlowyError> {
+    fn next(&self) -> FutureResult<Option<DocumentClientWSData>, FlowyError> {
         let shared_sink = self.0.clone();
         FutureResult::new(async move { shared_sink.next().await })
     }
@@ -251,7 +254,7 @@ enum SourceType {
 
 #[derive(Clone)]
 pub(crate) struct SharedWSSinkDataProvider {
-    shared: Arc<RwLock<VecDeque<DocumentWSData>>>,
+    shared: Arc<RwLock<VecDeque<DocumentClientWSData>>>,
     rev_manager: Arc<RevisionManager>,
     source_ty: Arc<RwLock<SourceType>>,
 }
@@ -266,18 +269,18 @@ impl SharedWSSinkDataProvider {
     }
 
     // TODO: return Option<&DocumentWSData> would be better
-    pub(crate) async fn front(&self) -> Option<DocumentWSData> { self.shared.read().await.front().cloned() }
+    pub(crate) async fn front(&self) -> Option<DocumentClientWSData> { self.shared.read().await.front().cloned() }
 
-    pub(crate) async fn push_front(&self, data: DocumentWSData) { self.shared.write().await.push_front(data); }
+    pub(crate) async fn push_front(&self, data: DocumentClientWSData) { self.shared.write().await.push_front(data); }
 
-    async fn push_back(&self, data: DocumentWSData) { self.shared.write().await.push_back(data); }
+    async fn push_back(&self, data: DocumentClientWSData) { self.shared.write().await.push_back(data); }
 
-    async fn append(&self, data: Vec<DocumentWSData>) {
+    async fn append(&self, data: Vec<DocumentClientWSData>) {
         let mut buf: VecDeque<_> = data.into_iter().collect();
         self.shared.write().await.append(&mut buf);
     }
 
-    async fn next(&self) -> FlowyResult<Option<DocumentWSData>> {
+    async fn next(&self) -> FlowyResult<Option<DocumentClientWSData>> {
         let source_ty = self.source_ty.read().await.clone();
         match source_ty {
             SourceType::Shared => match self.shared.read().await.front() {
@@ -307,7 +310,7 @@ impl SharedWSSinkDataProvider {
         }
     }
 
-    async fn ack(&self, id: String, _ty: DocumentWSDataType) -> FlowyResult<()> {
+    async fn ack(&self, id: String, _ty: DocumentServerWSDataType) -> FlowyResult<()> {
         // let _ = self.rev_manager.ack_revision(id).await?;
         let source_ty = self.source_ty.read().await.clone();
         match source_ty {

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

@@ -1,18 +1,18 @@
 use crate::errors::FlowyError;
 use bytes::Bytes;
 use dashmap::DashMap;
-use flowy_collaboration::entities::ws::DocumentWSData;
+use flowy_collaboration::entities::ws::{DocumentClientWSData, DocumentServerWSData};
 use lib_ws::WSConnectState;
 use std::{convert::TryInto, sync::Arc};
 
 pub(crate) trait DocumentWSReceiver: Send + Sync {
-    fn receive_ws_data(&self, data: DocumentWSData);
+    fn receive_ws_data(&self, data: DocumentServerWSData);
     fn connect_state_changed(&self, state: &WSConnectState);
 }
 
 pub type WSStateReceiver = tokio::sync::broadcast::Receiver<WSConnectState>;
 pub trait DocumentWebSocket: Send + Sync {
-    fn send(&self, data: DocumentWSData) -> Result<(), FlowyError>;
+    fn send(&self, data: DocumentClientWSData) -> Result<(), FlowyError>;
     fn subscribe_state_changed(&self) -> WSStateReceiver;
 }
 
@@ -41,7 +41,7 @@ impl DocumentWSReceivers {
     pub(crate) fn remove_receiver(&self, id: &str) { self.receivers.remove(id); }
 
     pub fn did_receive_data(&self, data: Bytes) {
-        let data: DocumentWSData = data.try_into().unwrap();
+        let data: DocumentServerWSData = data.try_into().unwrap();
         match self.receivers.get(&data.doc_id) {
             None => {
                 log::error!("Can't find any source handler for {:?}", data.doc_id);

+ 2 - 2
frontend/rust-lib/flowy-net/src/services/ws/conn.rs

@@ -3,7 +3,7 @@ use std::sync::Arc;
 use tokio::sync::broadcast;
 
 pub use flowy_error::FlowyError;
-pub use lib_ws::{WSConnectState, WSMessage, WSMessageReceiver};
+pub use lib_ws::{WSConnectState, WSMessageReceiver, WebScoketRawMessage};
 
 pub trait FlowyWebSocket: Send + Sync {
     fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError>;
@@ -15,5 +15,5 @@ pub trait FlowyWebSocket: Send + Sync {
 }
 
 pub trait FlowyWsSender: Send + Sync {
-    fn send(&self, msg: WSMessage) -> Result<(), FlowyError>;
+    fn send(&self, msg: WebScoketRawMessage) -> Result<(), FlowyError>;
 }

+ 2 - 2
frontend/rust-lib/flowy-net/src/services/ws/manager.rs

@@ -4,7 +4,7 @@ use crate::{
 };
 use flowy_error::{internal_error, FlowyError};
 use lib_infra::future::FutureResult;
-use lib_ws::{WSConnectState, WSController, WSMessage, WSMessageReceiver, WSSender};
+use lib_ws::{WSConnectState, WSController, WSMessageReceiver, WSSender, WebScoketRawMessage};
 use parking_lot::RwLock;
 use std::sync::Arc;
 use tokio::sync::{broadcast, broadcast::Receiver};
@@ -154,7 +154,7 @@ impl FlowyWebSocket for Arc<WSController> {
 }
 
 impl FlowyWsSender for WSSender {
-    fn send(&self, msg: WSMessage) -> Result<(), FlowyError> {
+    fn send(&self, msg: WebScoketRawMessage) -> Result<(), FlowyError> {
         let _ = self.send_msg(msg).map_err(internal_error)?;
         Ok(())
     }

+ 11 - 4
frontend/rust-lib/flowy-net/src/services/ws/ws_local.rs

@@ -1,11 +1,18 @@
-use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WSConnectState, WSMessage, WSMessageReceiver};
+use crate::services::ws::{
+    FlowyError,
+    FlowyWebSocket,
+    FlowyWsSender,
+    WSConnectState,
+    WSMessageReceiver,
+    WebScoketRawMessage,
+};
 use lib_infra::future::FutureResult;
 use std::sync::Arc;
 use tokio::sync::{broadcast, broadcast::Receiver};
 
 pub(crate) struct LocalWebSocket {
     state_sender: broadcast::Sender<WSConnectState>,
-    ws_sender: broadcast::Sender<WSMessage>,
+    ws_sender: broadcast::Sender<WebScoketRawMessage>,
 }
 
 impl std::default::Default for LocalWebSocket {
@@ -33,8 +40,8 @@ impl FlowyWebSocket for Arc<LocalWebSocket> {
     fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> { Ok(Arc::new(self.ws_sender.clone())) }
 }
 
-impl FlowyWsSender for broadcast::Sender<WSMessage> {
-    fn send(&self, msg: WSMessage) -> Result<(), FlowyError> {
+impl FlowyWsSender for broadcast::Sender<WebScoketRawMessage> {
+    fn send(&self, msg: WebScoketRawMessage) -> Result<(), FlowyError> {
         let _ = self.send(msg);
         Ok(())
     }

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

@@ -1,5 +1,5 @@
 use bytes::Bytes;
-use flowy_collaboration::entities::ws::DocumentWSData;
+use flowy_collaboration::entities::ws::DocumentClientWSData;
 use flowy_database::ConnectionPool;
 use flowy_document::{
     context::DocumentUser,
@@ -8,7 +8,7 @@ use flowy_document::{
 };
 use flowy_net::services::ws::WsManager;
 use flowy_user::services::user::UserSession;
-use lib_ws::{WSMessage, WSMessageReceiver, WSModule};
+use lib_ws::{WSMessageReceiver, WSModule, WebScoketRawMessage};
 use std::{convert::TryInto, path::Path, sync::Arc};
 
 pub struct DocumentDepsResolver();
@@ -65,9 +65,9 @@ struct DocumentWebSocketAdapter {
 }
 
 impl DocumentWebSocket for DocumentWebSocketAdapter {
-    fn send(&self, data: DocumentWSData) -> Result<(), FlowyError> {
+    fn send(&self, data: DocumentClientWSData) -> Result<(), FlowyError> {
         let bytes: Bytes = data.try_into().unwrap();
-        let msg = WSMessage {
+        let msg = WebScoketRawMessage {
             module: WSModule::Doc,
             data: bytes.to_vec(),
         };
@@ -84,5 +84,5 @@ struct WSMessageReceiverAdaptor(Arc<DocumentWSReceivers>);
 
 impl WSMessageReceiver for WSMessageReceiverAdaptor {
     fn source(&self) -> WSModule { WSModule::Doc }
-    fn receive_message(&self, msg: WSMessage) { self.0.did_receive_data(Bytes::from(msg.data)); }
+    fn receive_message(&self, msg: WebScoketRawMessage) { self.0.did_receive_data(Bytes::from(msg.data)); }
 }

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

@@ -7,17 +7,11 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use std::convert::{TryFrom, TryInto};
 
 #[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
-pub enum DocumentWSDataType {
-    // The frontend receives the Ack means the backend has received the revision
-    Ack         = 0,
-    // The frontend receives the PushRev event means the backend is pushing the new revision to frontend
-    PushRev     = 1,
-    // The fronted receives the PullRev event means the backend try to pull the revision from frontend
-    PullRev     = 2,
-    UserConnect = 3,
+pub enum DocumentClientWSDataType {
+    ClientPushRev = 0,
 }
 
-impl DocumentWSDataType {
+impl DocumentClientWSDataType {
     pub fn data<T>(&self, bytes: Bytes) -> Result<T, CollaborateError>
     where
         T: TryFrom<Bytes, Error = CollaborateError>,
@@ -26,17 +20,17 @@ impl DocumentWSDataType {
     }
 }
 
-impl std::default::Default for DocumentWSDataType {
-    fn default() -> Self { DocumentWSDataType::Ack }
+impl std::default::Default for DocumentClientWSDataType {
+    fn default() -> Self { DocumentClientWSDataType::ClientPushRev }
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
-pub struct DocumentWSData {
+pub struct DocumentClientWSData {
     #[pb(index = 1)]
     pub doc_id: String,
 
     #[pb(index = 2)]
-    pub ty: DocumentWSDataType,
+    pub ty: DocumentClientWSDataType,
 
     #[pb(index = 3)]
     pub data: Vec<u8>,
@@ -45,66 +39,93 @@ pub struct DocumentWSData {
     pub id: String,
 }
 
-impl std::convert::From<Revision> for DocumentWSData {
+impl std::convert::From<Revision> for DocumentClientWSData {
     fn from(revision: Revision) -> Self {
         let doc_id = revision.doc_id.clone();
         let rev_id = revision.rev_id;
         let bytes: Bytes = revision.try_into().unwrap();
         Self {
             doc_id,
-            ty: DocumentWSDataType::PushRev,
+            ty: DocumentClientWSDataType::ClientPushRev,
             data: bytes.to_vec(),
             id: rev_id.to_string(),
         }
     }
 }
 
-pub struct DocumentWSDataBuilder();
-impl DocumentWSDataBuilder {
+#[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
+pub enum DocumentServerWSDataType {
+    ServerAck     = 0,
+    ServerPushRev = 1,
+    ServerPullRev = 2,
+    UserConnect   = 3,
+}
+
+impl std::default::Default for DocumentServerWSDataType {
+    fn default() -> Self { DocumentServerWSDataType::ServerPushRev }
+}
+
+#[derive(ProtoBuf, Default, Debug, Clone)]
+pub struct DocumentServerWSData {
+    #[pb(index = 1)]
+    pub doc_id: String,
+
+    #[pb(index = 2)]
+    pub ty: DocumentServerWSDataType,
+
+    #[pb(index = 3)]
+    pub data: Vec<u8>,
+
+    #[pb(index = 4)]
+    pub id: String,
+}
+
+pub struct DocumentServerWSDataBuilder();
+impl DocumentServerWSDataBuilder {
     // DocumentWSDataType::PushRev -> Revision
-    pub fn build_push_message(doc_id: &str, revisions: Vec<Revision>, id: &str) -> DocumentWSData {
+    pub fn build_push_message(doc_id: &str, revisions: Vec<Revision>, id: &str) -> DocumentServerWSData {
         let repeated_revision = RepeatedRevision { items: revisions };
         let bytes: Bytes = repeated_revision.try_into().unwrap();
-        DocumentWSData {
+        DocumentServerWSData {
             doc_id: doc_id.to_string(),
-            ty: DocumentWSDataType::PushRev,
+            ty: DocumentServerWSDataType::ServerPushRev,
             data: bytes.to_vec(),
             id: id.to_string(),
         }
     }
 
     // DocumentWSDataType::PullRev -> RevisionRange
-    pub fn build_pull_message(doc_id: &str, range: RevisionRange, rev_id: i64) -> DocumentWSData {
+    pub fn build_pull_message(doc_id: &str, range: RevisionRange, rev_id: i64) -> DocumentServerWSData {
         let bytes: Bytes = range.try_into().unwrap();
-        DocumentWSData {
+        DocumentServerWSData {
             doc_id: doc_id.to_string(),
-            ty: DocumentWSDataType::PullRev,
+            ty: DocumentServerWSDataType::ServerPullRev,
             data: bytes.to_vec(),
             id: rev_id.to_string(),
         }
     }
 
     // DocumentWSDataType::Ack -> RevId
-    pub fn build_ack_message(doc_id: &str, id: &str) -> DocumentWSData {
-        DocumentWSData {
+    pub fn build_ack_message(doc_id: &str, id: &str) -> DocumentServerWSData {
+        DocumentServerWSData {
             doc_id: doc_id.to_string(),
-            ty: DocumentWSDataType::Ack,
+            ty: DocumentServerWSDataType::ServerAck,
             data: vec![],
             id: id.to_string(),
         }
     }
 
     // DocumentWSDataType::UserConnect -> DocumentConnected
-    pub fn build_new_document_user_message(doc_id: &str, new_document_user: NewDocumentUser) -> DocumentWSData {
-        let id = new_document_user.user_id.clone();
-        let bytes: Bytes = new_document_user.try_into().unwrap();
-        DocumentWSData {
-            doc_id: doc_id.to_string(),
-            ty: DocumentWSDataType::UserConnect,
-            data: bytes.to_vec(),
-            id,
-        }
-    }
+    // pub fn build_new_document_user_message(doc_id: &str, new_document_user:
+    // NewDocumentUser) -> DocumentServerWSData {     let id =
+    // new_document_user.user_id.clone();     let bytes: Bytes =
+    // new_document_user.try_into().unwrap();     DocumentServerWSData {
+    //         doc_id: doc_id.to_string(),
+    //         ty: DocumentServerWSDataType::UserConnect,
+    //         data: bytes.to_vec(),
+    //         id,
+    //     }
+    // }
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]

+ 435 - 94
shared-lib/flowy-collaboration/src/protobuf/model/ws.rs

@@ -24,10 +24,10 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(PartialEq,Clone,Default)]
-pub struct DocumentWSData {
+pub struct DocumentClientWSData {
     // message fields
     pub doc_id: ::std::string::String,
-    pub ty: DocumentWSDataType,
+    pub ty: DocumentClientWSDataType,
     pub data: ::std::vec::Vec<u8>,
     pub id: ::std::string::String,
     // special fields
@@ -35,14 +35,14 @@ pub struct DocumentWSData {
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a DocumentWSData {
-    fn default() -> &'a DocumentWSData {
-        <DocumentWSData as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a DocumentClientWSData {
+    fn default() -> &'a DocumentClientWSData {
+        <DocumentClientWSData as ::protobuf::Message>::default_instance()
     }
 }
 
-impl DocumentWSData {
-    pub fn new() -> DocumentWSData {
+impl DocumentClientWSData {
+    pub fn new() -> DocumentClientWSData {
         ::std::default::Default::default()
     }
 
@@ -72,18 +72,18 @@ impl DocumentWSData {
         ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
     }
 
-    // .DocumentWSDataType ty = 2;
+    // .DocumentClientWSDataType ty = 2;
 
 
-    pub fn get_ty(&self) -> DocumentWSDataType {
+    pub fn get_ty(&self) -> DocumentClientWSDataType {
         self.ty
     }
     pub fn clear_ty(&mut self) {
-        self.ty = DocumentWSDataType::Ack;
+        self.ty = DocumentClientWSDataType::ClientPushRev;
     }
 
     // Param is passed by value, moved
-    pub fn set_ty(&mut self, v: DocumentWSDataType) {
+    pub fn set_ty(&mut self, v: DocumentClientWSDataType) {
         self.ty = v;
     }
 
@@ -140,7 +140,7 @@ impl DocumentWSData {
     }
 }
 
-impl ::protobuf::Message for DocumentWSData {
+impl ::protobuf::Message for DocumentClientWSData {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -176,7 +176,7 @@ impl ::protobuf::Message for DocumentWSData {
         if !self.doc_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.doc_id);
         }
-        if self.ty != DocumentWSDataType::Ack {
+        if self.ty != DocumentClientWSDataType::ClientPushRev {
             my_size += ::protobuf::rt::enum_size(2, self.ty);
         }
         if !self.data.is_empty() {
@@ -194,7 +194,7 @@ impl ::protobuf::Message for DocumentWSData {
         if !self.doc_id.is_empty() {
             os.write_string(1, &self.doc_id)?;
         }
-        if self.ty != DocumentWSDataType::Ack {
+        if self.ty != DocumentClientWSDataType::ClientPushRev {
             os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
         }
         if !self.data.is_empty() {
@@ -233,8 +233,8 @@ impl ::protobuf::Message for DocumentWSData {
         Self::descriptor_static()
     }
 
-    fn new() -> DocumentWSData {
-        DocumentWSData::new()
+    fn new() -> DocumentClientWSData {
+        DocumentClientWSData::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -243,55 +243,329 @@ impl ::protobuf::Message for DocumentWSData {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "doc_id",
-                |m: &DocumentWSData| { &m.doc_id },
-                |m: &mut DocumentWSData| { &mut m.doc_id },
+                |m: &DocumentClientWSData| { &m.doc_id },
+                |m: &mut DocumentClientWSData| { &mut m.doc_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentWSDataType>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentClientWSDataType>>(
                 "ty",
-                |m: &DocumentWSData| { &m.ty },
-                |m: &mut DocumentWSData| { &mut m.ty },
+                |m: &DocumentClientWSData| { &m.ty },
+                |m: &mut DocumentClientWSData| { &mut m.ty },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
                 "data",
-                |m: &DocumentWSData| { &m.data },
-                |m: &mut DocumentWSData| { &mut m.data },
+                |m: &DocumentClientWSData| { &m.data },
+                |m: &mut DocumentClientWSData| { &mut m.data },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "id",
-                |m: &DocumentWSData| { &m.id },
-                |m: &mut DocumentWSData| { &mut m.id },
+                |m: &DocumentClientWSData| { &m.id },
+                |m: &mut DocumentClientWSData| { &mut m.id },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentWSData>(
-                "DocumentWSData",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentClientWSData>(
+                "DocumentClientWSData",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static DocumentWSData {
-        static instance: ::protobuf::rt::LazyV2<DocumentWSData> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(DocumentWSData::new)
+    fn default_instance() -> &'static DocumentClientWSData {
+        static instance: ::protobuf::rt::LazyV2<DocumentClientWSData> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(DocumentClientWSData::new)
     }
 }
 
-impl ::protobuf::Clear for DocumentWSData {
+impl ::protobuf::Clear for DocumentClientWSData {
     fn clear(&mut self) {
         self.doc_id.clear();
-        self.ty = DocumentWSDataType::Ack;
+        self.ty = DocumentClientWSDataType::ClientPushRev;
         self.data.clear();
         self.id.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for DocumentWSData {
+impl ::std::fmt::Debug for DocumentClientWSData {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentWSData {
+impl ::protobuf::reflect::ProtobufValue for DocumentClientWSData {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
+#[derive(PartialEq,Clone,Default)]
+pub struct DocumentServerWSData {
+    // message fields
+    pub doc_id: ::std::string::String,
+    pub ty: DocumentServerWSDataType,
+    pub data: ::std::vec::Vec<u8>,
+    pub id: ::std::string::String,
+    // 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 DocumentServerWSData {
+    pub fn new() -> DocumentServerWSData {
+        ::std::default::Default::default()
+    }
+
+    // string doc_id = 1;
+
+
+    pub fn get_doc_id(&self) -> &str {
+        &self.doc_id
+    }
+    pub fn clear_doc_id(&mut self) {
+        self.doc_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_doc_id(&mut self, v: ::std::string::String) {
+        self.doc_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
+    }
+
+    // Take field
+    pub fn take_doc_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    }
+
+    // .DocumentServerWSDataType ty = 2;
+
+
+    pub fn get_ty(&self) -> DocumentServerWSDataType {
+        self.ty
+    }
+    pub fn clear_ty(&mut self) {
+        self.ty = DocumentServerWSDataType::ServerAck;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_ty(&mut self, v: DocumentServerWSDataType) {
+        self.ty = v;
+    }
+
+    // bytes data = 3;
+
+
+    pub fn get_data(&self) -> &[u8] {
+        &self.data
+    }
+    pub fn clear_data(&mut self) {
+        self.data.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) {
+        self.data = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> {
+        &mut self.data
+    }
+
+    // Take field
+    pub fn take_data(&mut self) -> ::std::vec::Vec<u8> {
+        ::std::mem::replace(&mut self.data, ::std::vec::Vec::new())
+    }
+
+    // string id = 4;
+
+
+    pub fn get_id(&self) -> &str {
+        &self.id
+    }
+    pub fn clear_id(&mut self) {
+        self.id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_id(&mut self, v: ::std::string::String) {
+        self.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
+    }
+
+    // Take field
+    pub fn take_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.id, ::std::string::String::new())
+    }
+}
+
+impl ::protobuf::Message for DocumentServerWSData {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            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)?;
+                },
+                2 => {
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 2, &mut self.unknown_fields)?
+                },
+                3 => {
+                    ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?;
+                },
+                4 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[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.ty != DocumentServerWSDataType::ServerAck {
+            my_size += ::protobuf::rt::enum_size(2, self.ty);
+        }
+        if !self.data.is_empty() {
+            my_size += ::protobuf::rt::bytes_size(3, &self.data);
+        }
+        if !self.id.is_empty() {
+            my_size += ::protobuf::rt::string_size(4, &self.id);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    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.ty != DocumentServerWSDataType::ServerAck {
+            os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
+        }
+        if !self.data.is_empty() {
+            os.write_bytes(3, &self.data)?;
+        }
+        if !self.id.is_empty() {
+            os.write_string(4, &self.id)?;
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> DocumentServerWSData {
+        DocumentServerWSData::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        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 },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentServerWSDataType>>(
+                "ty",
+                |m: &DocumentServerWSData| { &m.ty },
+                |m: &mut DocumentServerWSData| { &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 },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "id",
+                |m: &DocumentServerWSData| { &m.id },
+                |m: &mut DocumentServerWSData| { &mut m.id },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentServerWSData>(
+                "DocumentServerWSData",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static DocumentServerWSData {
+        static instance: ::protobuf::rt::LazyV2<DocumentServerWSData> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(DocumentServerWSData::new)
+    }
+}
+
+impl ::protobuf::Clear for DocumentServerWSData {
+    fn clear(&mut self) {
+        self.doc_id.clear();
+        self.ty = DocumentServerWSDataType::ServerAck;
+        self.data.clear();
+        self.id.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for DocumentServerWSData {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for DocumentServerWSData {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -540,27 +814,26 @@ impl ::protobuf::reflect::ProtobufValue for NewDocumentUser {
     }
 }
 
-impl ::protobuf::ProtobufEnum for DocumentWSDataType {
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum DocumentClientWSDataType {
+    ClientPushRev = 0,
+}
+
+impl ::protobuf::ProtobufEnum for DocumentClientWSDataType {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<DocumentWSDataType> {
+    fn from_i32(value: i32) -> ::std::option::Option<DocumentClientWSDataType> {
         match value {
-            0 => ::std::option::Option::Some(DocumentWSDataType::Ack),
-            1 => ::std::option::Option::Some(DocumentWSDataType::PushRev),
-            2 => ::std::option::Option::Some(DocumentWSDataType::PullRev),
-            3 => ::std::option::Option::Some(DocumentWSDataType::UserConnect),
+            0 => ::std::option::Option::Some(DocumentClientWSDataType::ClientPushRev),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [DocumentWSDataType] = &[
-            DocumentWSDataType::Ack,
-            DocumentWSDataType::PushRev,
-            DocumentWSDataType::PullRev,
-            DocumentWSDataType::UserConnect,
+        static values: &'static [DocumentClientWSDataType] = &[
+            DocumentClientWSDataType::ClientPushRev,
         ];
         values
     }
@@ -568,75 +841,143 @@ impl ::protobuf::ProtobufEnum for DocumentWSDataType {
     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::<DocumentWSDataType>("DocumentWSDataType", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<DocumentClientWSDataType>("DocumentClientWSDataType", file_descriptor_proto())
         })
     }
 }
 
+impl ::std::marker::Copy for DocumentClientWSDataType {
+}
+
+impl ::std::default::Default for DocumentClientWSDataType {
+    fn default() -> Self {
+        DocumentClientWSDataType::ClientPushRev
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for DocumentClientWSDataType {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum DocumentWSDataType {
-    Ack = 0,
-    PushRev = 1,
-    PullRev = 2,
+pub enum DocumentServerWSDataType {
+    ServerAck = 0,
+    ServerPushRev = 1,
+    ServerPullRev = 2,
     UserConnect = 3,
 }
 
-impl ::std::marker::Copy for DocumentWSDataType {
+impl ::protobuf::ProtobufEnum for DocumentServerWSDataType {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<DocumentServerWSDataType> {
+        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),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [DocumentServerWSDataType] = &[
+            DocumentServerWSDataType::ServerAck,
+            DocumentServerWSDataType::ServerPushRev,
+            DocumentServerWSDataType::ServerPullRev,
+            DocumentServerWSDataType::UserConnect,
+        ];
+        values
+    }
+
+    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())
+        })
+    }
+}
+
+impl ::std::marker::Copy for DocumentServerWSDataType {
 }
 
-impl ::std::default::Default for DocumentWSDataType {
+impl ::std::default::Default for DocumentServerWSDataType {
     fn default() -> Self {
-        DocumentWSDataType::Ack
+        DocumentServerWSDataType::ServerAck
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DocumentWSDataType {
+impl ::protobuf::reflect::ProtobufValue for DocumentServerWSDataType {
     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\"p\n\x0eDocumentWSData\x12\x15\n\x06doc_id\x18\x01\x20\
-    \x01(\tR\x05docId\x12#\n\x02ty\x18\x02\x20\x01(\x0e2\x13.DocumentWSDataT\
-    ypeR\x02ty\x12\x12\n\x04data\x18\x03\x20\x01(\x0cR\x04data\x12\x0e\n\x02\
-    id\x18\x04\x20\x01(\tR\x02id\"f\n\x0fNewDocumentUser\x12\x17\n\x07user_i\
-    d\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\x06doc_id\x18\x02\x20\x01(\tR\
-    \x05docId\x12#\n\rrevision_data\x18\x03\x20\x01(\x0cR\x0crevisionData*H\
-    \n\x12DocumentWSDataType\x12\x07\n\x03Ack\x10\0\x12\x0b\n\x07PushRev\x10\
-    \x01\x12\x0b\n\x07PullRev\x10\x02\x12\x0f\n\x0bUserConnect\x10\x03J\xff\
-    \x04\n\x06\x12\x04\0\0\x12\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
-    \x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x16\n\
-    \x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\x05\x04\0\x02\0\x05\
-    \x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x11\n\x0c\
-    \n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\0\x02\x01\x12\
-    \x03\x04\x04\x1e\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x04\x04\x16\n\x0c\
-    \n\x05\x04\0\x02\x01\x01\x12\x03\x04\x17\x19\n\x0c\n\x05\x04\0\x02\x01\
-    \x03\x12\x03\x04\x1c\x1d\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x13\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\x0e\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x11\x12\
-    \n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x12\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\r\n\
-    \x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x10\x11\n\n\n\x02\x04\x01\x12\
-    \x04\x08\0\x0c\x01\n\n\n\x03\x04\x01\x01\x12\x03\x08\x08\x17\n\x0b\n\x04\
-    \x04\x01\x02\0\x12\x03\t\x04\x17\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\t\
-    \x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\t\x0b\x12\n\x0c\n\x05\x04\
-    \x01\x02\0\x03\x12\x03\t\x15\x16\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\n\
-    \x04\x16\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\
-    \x01\x02\x01\x01\x12\x03\n\x0b\x11\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\
-    \x03\n\x14\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0b\x04\x1c\n\x0c\n\
-    \x05\x04\x01\x02\x02\x05\x12\x03\x0b\x04\t\n\x0c\n\x05\x04\x01\x02\x02\
-    \x01\x12\x03\x0b\n\x17\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0b\x1a\
-    \x1b\n\n\n\x02\x05\0\x12\x04\r\0\x12\x01\n\n\n\x03\x05\0\x01\x12\x03\r\
-    \x05\x17\n\x0b\n\x04\x05\0\x02\0\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x05\0\
-    \x02\0\x01\x12\x03\x0e\x04\x07\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x0e\n\
-    \x0b\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x0f\x04\x10\n\x0c\n\x05\x05\0\x02\
-    \x01\x01\x12\x03\x0f\x04\x0b\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x0f\
-    \x0e\x0f\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x10\x04\x10\n\x0c\n\x05\x05\0\
-    \x02\x02\x01\x12\x03\x10\x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\
-    \x10\x0e\x0f\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x11\x04\x14\n\x0c\n\x05\
-    \x05\0\x02\x03\x01\x12\x03\x11\x04\x0f\n\x0c\n\x05\x05\0\x02\x03\x02\x12\
-    \x03\x11\x12\x13b\x06proto3\
+    \n\x08ws.proto\"|\n\x14DocumentClientWSData\x12\x15\n\x06doc_id\x18\x01\
+    \x20\x01(\tR\x05docId\x12)\n\x02ty\x18\x02\x20\x01(\x0e2\x19.DocumentCli\
+    entWSDataTypeR\x02ty\x12\x12\n\x04data\x18\x03\x20\x01(\x0cR\x04data\x12\
+    \x0e\n\x02id\x18\x04\x20\x01(\tR\x02id\"|\n\x14DocumentServerWSData\x12\
+    \x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12)\n\x02ty\x18\x02\x20\
+    \x01(\x0e2\x19.DocumentServerWSDataTypeR\x02ty\x12\x12\n\x04data\x18\x03\
+    \x20\x01(\x0cR\x04data\x12\x0e\n\x02id\x18\x04\x20\x01(\tR\x02id\"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\rrevision_data\
+    \x18\x03\x20\x01(\x0cR\x0crevisionData*-\n\x18DocumentClientWSDataType\
+    \x12\x11\n\rClientPushRev\x10\0*`\n\x18DocumentServerWSDataType\x12\r\n\
+    \tServerAck\x10\0\x12\x11\n\rServerPushRev\x10\x01\x12\x11\n\rServerPull\
+    Rev\x10\x02\x12\x0f\n\x0bUserConnect\x10\x03J\xb4\x07\n\x06\x12\x04\0\0\
+    \x1b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\
+    \x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x1c\n\x0b\n\x04\x04\0\x02\0\
+    \x12\x03\x03\x04\x16\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\
+    \n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\
+    \x12\x03\x03\x14\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04$\n\x0c\n\
+    \x05\x04\0\x02\x01\x06\x12\x03\x04\x04\x1c\n\x0c\n\x05\x04\0\x02\x01\x01\
+    \x12\x03\x04\x1d\x1f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\"#\n\x0b\
+    \n\x04\x04\0\x02\x02\x12\x03\x05\x04\x13\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\x0e\n\x0c\
+    \n\x05\x04\0\x02\x02\x03\x12\x03\x05\x11\x12\n\x0b\n\x04\x04\0\x02\x03\
+    \x12\x03\x06\x04\x12\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\r\n\x0c\n\x05\x04\0\x02\x03\
+    \x03\x12\x03\x06\x10\x11\n\n\n\x02\x04\x01\x12\x04\x08\0\r\x01\n\n\n\x03\
+    \x04\x01\x01\x12\x03\x08\x08\x1c\n\x0b\n\x04\x04\x01\x02\0\x12\x03\t\x04\
+    \x16\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\
+    \x02\0\x01\x12\x03\t\x0b\x11\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\t\x14\
+    \x15\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\n\x04$\n\x0c\n\x05\x04\x01\x02\
+    \x01\x06\x12\x03\n\x04\x1c\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\n\x1d\
+    \x1f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\n\"#\n\x0b\n\x04\x04\x01\
+    \x02\x02\x12\x03\x0b\x04\x13\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0b\
+    \x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0b\n\x0e\n\x0c\n\x05\x04\
+    \x01\x02\x02\x03\x12\x03\x0b\x11\x12\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\
+    \x0c\x04\x12\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\x0c\x04\n\n\x0c\n\
+    \x05\x04\x01\x02\x03\x01\x12\x03\x0c\x0b\r\n\x0c\n\x05\x04\x01\x02\x03\
+    \x03\x12\x03\x0c\x10\x11\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\x15\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\n\
+    \n\x02\x05\x01\x12\x04\x16\0\x1b\x01\n\n\n\x03\x05\x01\x01\x12\x03\x16\
+    \x05\x1d\n\x0b\n\x04\x05\x01\x02\0\x12\x03\x17\x04\x12\n\x0c\n\x05\x05\
+    \x01\x02\0\x01\x12\x03\x17\x04\r\n\x0c\n\x05\x05\x01\x02\0\x02\x12\x03\
+    \x17\x10\x11\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x18\x04\x16\n\x0c\n\x05\
+    \x05\x01\x02\x01\x01\x12\x03\x18\x04\x11\n\x0c\n\x05\x05\x01\x02\x01\x02\
+    \x12\x03\x18\x14\x15\n\x0b\n\x04\x05\x01\x02\x02\x12\x03\x19\x04\x16\n\
+    \x0c\n\x05\x05\x01\x02\x02\x01\x12\x03\x19\x04\x11\n\x0c\n\x05\x05\x01\
+    \x02\x02\x02\x12\x03\x19\x14\x15\n\x0b\n\x04\x05\x01\x02\x03\x12\x03\x1a\
+    \x04\x14\n\x0c\n\x05\x05\x01\x02\x03\x01\x12\x03\x1a\x04\x0f\n\x0c\n\x05\
+    \x05\x01\x02\x03\x02\x12\x03\x1a\x12\x13b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -1,8 +1,14 @@
 syntax = "proto3";
 
-message DocumentWSData {
+message DocumentClientWSData {
     string doc_id = 1;
-    DocumentWSDataType ty = 2;
+    DocumentClientWSDataType ty = 2;
+    bytes data = 3;
+    string id = 4;
+}
+message DocumentServerWSData {
+    string doc_id = 1;
+    DocumentServerWSDataType ty = 2;
     bytes data = 3;
     string id = 4;
 }
@@ -11,9 +17,12 @@ message NewDocumentUser {
     string doc_id = 2;
     bytes revision_data = 3;
 }
-enum DocumentWSDataType {
-    Ack = 0;
-    PushRev = 1;
-    PullRev = 2;
+enum DocumentClientWSDataType {
+    ClientPushRev = 0;
+}
+enum DocumentServerWSDataType {
+    ServerAck = 0;
+    ServerPushRev = 1;
+    ServerPullRev = 2;
     UserConnect = 3;
 }

+ 8 - 7
shared-lib/flowy-collaboration/src/sync/synchronizer.rs

@@ -2,7 +2,7 @@ use crate::{
     document::Document,
     entities::{
         revision::{Revision, RevisionRange},
-        ws::{DocumentWSData, DocumentWSDataBuilder},
+        ws::{DocumentServerWSData, DocumentServerWSDataBuilder},
     },
     sync::DocumentPersistence,
 };
@@ -24,9 +24,9 @@ pub trait RevisionUser: Send + Sync + Debug {
 }
 
 pub enum SyncResponse {
-    Pull(DocumentWSData),
-    Push(DocumentWSData),
-    Ack(DocumentWSData),
+    Pull(DocumentServerWSData),
+    Push(DocumentServerWSData),
+    Ack(DocumentServerWSData),
     NewRevision(Vec<Revision>),
 }
 
@@ -83,7 +83,8 @@ impl RevisionSynchronizer {
                         start: server_rev_id,
                         end: first_revision.rev_id,
                     };
-                    let msg = DocumentWSDataBuilder::build_pull_message(&self.doc_id, range, first_revision.rev_id);
+                    let msg =
+                        DocumentServerWSDataBuilder::build_pull_message(&self.doc_id, range, first_revision.rev_id);
                     user.receive(SyncResponse::Pull(msg));
                 }
             },
@@ -110,12 +111,12 @@ impl RevisionSynchronizer {
                     },
                 };
 
-                let data = DocumentWSDataBuilder::build_push_message(&self.doc_id, revisions, &id);
+                let data = DocumentServerWSDataBuilder::build_push_message(&self.doc_id, revisions, &id);
                 user.receive(SyncResponse::Push(data));
             },
         }
 
-        user.receive(SyncResponse::Ack(DocumentWSDataBuilder::build_ack_message(
+        user.receive(SyncResponse::Ack(DocumentServerWSDataBuilder::build_ack_message(
             &first_revision.doc_id,
             &first_revision.rev_id.to_string(),
         )));

+ 5 - 3
shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -41,7 +41,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "RepeatedRevision"
         | "RevId"
         | "RevisionRange"
-        | "DocumentWSData"
+        | "DocumentClientWSData"
+        | "DocumentServerWSData"
         | "NewDocumentUser"
         | "QueryAppRequest"
         | "AppIdentifier"
@@ -77,7 +78,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "ExportRequest"
         | "ExportData"
         | "WSError"
-        | "WSMessage"
+        | "WebScoketRawMessage"
         => TypeCategory::Protobuf,
         "WorkspaceEvent"
         | "WorkspaceNotification"
@@ -89,7 +90,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "UserNotification"
         | "RevType"
         | "RevState"
-        | "DocumentWSDataType"
+        | "DocumentClientWSDataType"
+        | "DocumentServerWSDataType"
         | "TrashType"
         | "ViewType"
         | "ExportType"

+ 3 - 3
shared-lib/lib-ws/src/msg.rs

@@ -4,7 +4,7 @@ use std::convert::TryInto;
 use tokio_tungstenite::tungstenite::Message as TokioMessage;
 
 #[derive(ProtoBuf, Debug, Clone, Default)]
-pub struct WSMessage {
+pub struct WebScoketRawMessage {
     #[pb(index = 1)]
     pub module: WSModule,
 
@@ -29,8 +29,8 @@ impl ToString for WSModule {
     }
 }
 
-impl std::convert::From<WSMessage> for TokioMessage {
-    fn from(msg: WSMessage) -> Self {
+impl std::convert::From<WebScoketRawMessage> for TokioMessage {
+    fn from(msg: WebScoketRawMessage) -> Self {
         let result: Result<Bytes, ::protobuf::ProtobufError> = msg.try_into();
         match result {
             Ok(bytes) => TokioMessage::Binary(bytes.to_vec()),

+ 35 - 35
shared-lib/lib-ws/src/protobuf/model/msg.rs

@@ -24,7 +24,7 @@
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(PartialEq,Clone,Default)]
-pub struct WSMessage {
+pub struct WebScoketRawMessage {
     // message fields
     pub module: WSModule,
     pub data: ::std::vec::Vec<u8>,
@@ -33,14 +33,14 @@ pub struct WSMessage {
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a WSMessage {
-    fn default() -> &'a WSMessage {
-        <WSMessage as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a WebScoketRawMessage {
+    fn default() -> &'a WebScoketRawMessage {
+        <WebScoketRawMessage as ::protobuf::Message>::default_instance()
     }
 }
 
-impl WSMessage {
-    pub fn new() -> WSMessage {
+impl WebScoketRawMessage {
+    pub fn new() -> WebScoketRawMessage {
         ::std::default::Default::default()
     }
 
@@ -86,7 +86,7 @@ impl WSMessage {
     }
 }
 
-impl ::protobuf::Message for WSMessage {
+impl ::protobuf::Message for WebScoketRawMessage {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -161,8 +161,8 @@ impl ::protobuf::Message for WSMessage {
         Self::descriptor_static()
     }
 
-    fn new() -> WSMessage {
-        WSMessage::new()
+    fn new() -> WebScoketRawMessage {
+        WebScoketRawMessage::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -171,29 +171,29 @@ impl ::protobuf::Message for WSMessage {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<WSModule>>(
                 "module",
-                |m: &WSMessage| { &m.module },
-                |m: &mut WSMessage| { &mut m.module },
+                |m: &WebScoketRawMessage| { &m.module },
+                |m: &mut WebScoketRawMessage| { &mut m.module },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
                 "data",
-                |m: &WSMessage| { &m.data },
-                |m: &mut WSMessage| { &mut m.data },
+                |m: &WebScoketRawMessage| { &m.data },
+                |m: &mut WebScoketRawMessage| { &mut m.data },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<WSMessage>(
-                "WSMessage",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<WebScoketRawMessage>(
+                "WebScoketRawMessage",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static WSMessage {
-        static instance: ::protobuf::rt::LazyV2<WSMessage> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(WSMessage::new)
+    fn default_instance() -> &'static WebScoketRawMessage {
+        static instance: ::protobuf::rt::LazyV2<WebScoketRawMessage> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(WebScoketRawMessage::new)
     }
 }
 
-impl ::protobuf::Clear for WSMessage {
+impl ::protobuf::Clear for WebScoketRawMessage {
     fn clear(&mut self) {
         self.module = WSModule::Doc;
         self.data.clear();
@@ -201,13 +201,13 @@ impl ::protobuf::Clear for WSMessage {
     }
 }
 
-impl ::std::fmt::Debug for WSMessage {
+impl ::std::fmt::Debug for WebScoketRawMessage {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for WSMessage {
+impl ::protobuf::reflect::ProtobufValue for WebScoketRawMessage {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -261,20 +261,20 @@ impl ::protobuf::reflect::ProtobufValue for WSModule {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\tmsg.proto\"B\n\tWSMessage\x12!\n\x06module\x18\x01\x20\x01(\x0e2\t.W\
-    SModuleR\x06module\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data*\x13\
-    \n\x08WSModule\x12\x07\n\x03Doc\x10\0J\xd9\x01\n\x06\x12\x04\0\0\x08\x01\
-    \n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\
-    \n\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\
-    \x03\x04\x18\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0c\n\x0c\n\x05\
-    \x04\0\x02\0\x01\x12\x03\x03\r\x13\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\
-    \x03\x16\x17\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\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\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\x12\n\n\n\
-    \x02\x05\0\x12\x04\x06\0\x08\x01\n\n\n\x03\x05\0\x01\x12\x03\x06\x05\r\n\
-    \x0b\n\x04\x05\0\x02\0\x12\x03\x07\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x01\
-    \x12\x03\x07\x04\x07\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\n\x0bb\x06p\
-    roto3\
+    \n\tmsg.proto\"L\n\x13WebScoketRawMessage\x12!\n\x06module\x18\x01\x20\
+    \x01(\x0e2\t.WSModuleR\x06module\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\
+    \x04data*\x13\n\x08WSModule\x12\x07\n\x03Doc\x10\0J\xd9\x01\n\x06\x12\
+    \x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\
+    \x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x1b\n\x0b\n\x04\x04\0\
+    \x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\
+    \x0c\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\r\x13\n\x0c\n\x05\x04\0\x02\
+    \0\x03\x12\x03\x03\x16\x17\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x13\
+    \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\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x11\
+    \x12\n\n\n\x02\x05\0\x12\x04\x06\0\x08\x01\n\n\n\x03\x05\0\x01\x12\x03\
+    \x06\x05\r\n\x0b\n\x04\x05\0\x02\0\x12\x03\x07\x04\x0c\n\x0c\n\x05\x05\0\
+    \x02\0\x01\x12\x03\x07\x04\x07\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\n\
+    \x0bb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 1
shared-lib/lib-ws/src/protobuf/proto/msg.proto

@@ -1,6 +1,6 @@
 syntax = "proto3";
 
-message WSMessage {
+message WebScoketRawMessage {
     WSModule module = 1;
     bytes data = 2;
 }

+ 6 - 6
shared-lib/lib-ws/src/ws.rs

@@ -2,8 +2,8 @@
 use crate::{
     connect::{WSConnectionFuture, WSStream},
     errors::WSError,
-    WSMessage,
     WSModule,
+    WebScoketRawMessage,
 };
 use backend_service::errors::ServerError;
 use bytes::Bytes;
@@ -34,7 +34,7 @@ type Handlers = DashMap<WSModule, Arc<dyn WSMessageReceiver>>;
 
 pub trait WSMessageReceiver: Sync + Send + 'static {
     fn source(&self) -> WSModule;
-    fn receive_message(&self, msg: WSMessage);
+    fn receive_message(&self, msg: WebScoketRawMessage);
 }
 
 pub struct WSController {
@@ -175,7 +175,7 @@ impl WSHandlerFuture {
 
     fn handle_binary_message(&self, bytes: Vec<u8>) {
         let bytes = Bytes::from(bytes);
-        match WSMessage::try_from(bytes) {
+        match WebScoketRawMessage::try_from(bytes) {
             Ok(message) => match self.handlers.get(&message.module) {
                 None => log::error!("Can't find any handler for message: {:?}", message),
                 Some(handler) => handler.receive_message(message.clone()),
@@ -207,7 +207,7 @@ pub struct WSSender {
 }
 
 impl WSSender {
-    pub fn send_msg<T: Into<WSMessage>>(&self, msg: T) -> Result<(), WSError> {
+    pub fn send_msg<T: Into<WebScoketRawMessage>>(&self, msg: T) -> Result<(), WSError> {
         let msg = msg.into();
         let _ = self
             .ws_tx
@@ -217,7 +217,7 @@ impl WSSender {
     }
 
     pub fn send_text(&self, source: &WSModule, text: &str) -> Result<(), WSError> {
-        let msg = WSMessage {
+        let msg = WebScoketRawMessage {
             module: source.clone(),
             data: text.as_bytes().to_vec(),
         };
@@ -225,7 +225,7 @@ impl WSSender {
     }
 
     pub fn send_binary(&self, source: &WSModule, bytes: Vec<u8>) -> Result<(), WSError> {
-        let msg = WSMessage {
+        let msg = WebScoketRawMessage {
             module: source.clone(),
             data: bytes,
         };