Переглянути джерело

mv websocket to flowy-net crate

appflowy 3 роки тому
батько
коміт
72a8f7a9e3
75 змінених файлів з 1041 додано та 375 видалено
  1. 22 1
      backend/Cargo.lock
  2. 1 0
      backend/Cargo.toml
  3. 6 1
      backend/tests/document/helper.rs
  4. 2 2
      frontend/app_flowy/lib/user/infrastructure/network_monitor.dart
  5. 17 17
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
  6. 4 2
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart
  7. 6 6
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/error.dart
  8. 74 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pb.dart
  9. 24 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbenum.dart
  10. 31 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbjson.dart
  11. 9 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbserver.dart
  12. 2 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/protobuf.dart
  13. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pb.dart
  14. 24 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbenum.dart
  15. 7 8
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbjson.dart
  16. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbserver.dart
  17. 1 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/protobuf.dart
  18. 0 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart
  19. 1 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart
  20. 0 26
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/cache.pbenum.dart
  21. 15 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/model.pbenum.dart
  22. 11 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/model.pbjson.dart
  23. 0 1
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/protobuf.dart
  24. 1 0
      frontend/rust-lib/Cargo.toml
  25. 1 1
      frontend/rust-lib/flowy-document/Cargo.toml
  26. 2 2
      frontend/rust-lib/flowy-document/src/services/doc/revision/cache/cache.rs
  27. 1 1
      frontend/rust-lib/flowy-document/src/services/doc/revision/cache/memory.rs
  28. 2 2
      frontend/rust-lib/flowy-document/src/services/ws/ws_manager.rs
  29. 2 2
      frontend/rust-lib/flowy-document/src/sql_tables/doc/rev_table.rs
  30. 5 5
      frontend/rust-lib/flowy-document/tests/editor/revision_test.rs
  31. 13 0
      frontend/rust-lib/flowy-error/Cargo.toml
  32. 3 0
      frontend/rust-lib/flowy-error/Flowy.toml
  33. 84 0
      frontend/rust-lib/flowy-error/src/errors.rs
  34. 4 0
      frontend/rust-lib/flowy-error/src/lib.rs
  35. 4 0
      frontend/rust-lib/flowy-error/src/protobuf/mod.rs
  36. 293 0
      frontend/rust-lib/flowy-error/src/protobuf/model/errors.rs
  37. 5 0
      frontend/rust-lib/flowy-error/src/protobuf/model/mod.rs
  38. 9 0
      frontend/rust-lib/flowy-error/src/protobuf/proto/errors.proto
  39. 18 1
      frontend/rust-lib/flowy-net/Cargo.toml
  40. 2 2
      frontend/rust-lib/flowy-net/Flowy.toml
  41. 9 0
      frontend/rust-lib/flowy-net/src/event.rs
  42. 12 0
      frontend/rust-lib/flowy-net/src/handlers/mod.rs
  43. 4 0
      frontend/rust-lib/flowy-net/src/lib.rs
  44. 10 0
      frontend/rust-lib/flowy-net/src/module.rs
  45. 18 23
      frontend/rust-lib/flowy-net/src/protobuf/model/event.rs
  46. 3 0
      frontend/rust-lib/flowy-net/src/protobuf/model/mod.rs
  47. 5 0
      frontend/rust-lib/flowy-net/src/protobuf/proto/event.proto
  48. 3 0
      frontend/rust-lib/flowy-net/src/services/mock/mod.rs
  49. 11 15
      frontend/rust-lib/flowy-net/src/services/mock/ws_mock.rs
  50. 4 0
      frontend/rust-lib/flowy-net/src/services/mod.rs
  51. 18 0
      frontend/rust-lib/flowy-net/src/services/ws/conn.rs
  52. 44 50
      frontend/rust-lib/flowy-net/src/services/ws/manager.rs
  53. 15 0
      frontend/rust-lib/flowy-net/src/services/ws/mod.rs
  54. 6 10
      frontend/rust-lib/flowy-net/src/services/ws/ws_local.rs
  55. 15 18
      frontend/rust-lib/flowy-sdk/src/deps_resolve/document_deps.rs
  56. 45 18
      frontend/rust-lib/flowy-sdk/src/lib.rs
  57. 7 11
      frontend/rust-lib/flowy-sdk/src/module.rs
  58. 1 5
      frontend/rust-lib/flowy-user/Cargo.toml
  59. 0 10
      frontend/rust-lib/flowy-user/src/errors.rs
  60. 7 10
      frontend/rust-lib/flowy-user/src/event.rs
  61. 0 7
      frontend/rust-lib/flowy-user/src/handlers/user_handler.rs
  62. 0 1
      frontend/rust-lib/flowy-user/src/module.rs
  63. 20 26
      frontend/rust-lib/flowy-user/src/protobuf/model/event.rs
  64. 0 1
      frontend/rust-lib/flowy-user/src/protobuf/proto/event.proto
  65. 0 11
      frontend/rust-lib/flowy-user/src/services/server/mod.rs
  66. 0 1
      frontend/rust-lib/flowy-user/src/services/user/mod.rs
  67. 2 13
      frontend/rust-lib/flowy-user/src/services/user/notifier.rs
  68. 2 37
      frontend/rust-lib/flowy-user/src/services/user/user_session.rs
  69. 2 0
      shared-lib/flowy-collaboration/src/lib.rs
  70. 3 0
      shared-lib/flowy-derive/src/derive_cache/derive_cache.rs
  71. 0 3
      shared-lib/lib-ot/src/protobuf/model/mod.rs
  72. 59 3
      shared-lib/lib-ot/src/protobuf/model/model.rs
  73. 0 6
      shared-lib/lib-ot/src/protobuf/proto/cache.proto
  74. 4 0
      shared-lib/lib-ot/src/protobuf/proto/model.proto
  75. 2 8
      shared-lib/lib-ot/src/revision/model.rs

+ 22 - 1
backend/Cargo.lock

@@ -458,6 +458,7 @@ dependencies = [
  "flowy-collaboration",
  "flowy-core-infra",
  "flowy-document",
+ "flowy-net",
  "flowy-sdk",
  "flowy-test",
  "flowy-user",
@@ -1338,13 +1339,34 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "flowy-error"
+version = "0.1.0"
+dependencies = [
+ "bytes",
+ "derive_more",
+ "flowy-derive",
+ "lib-dispatch",
+ "protobuf",
+]
+
 [[package]]
 name = "flowy-net"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
  "bytes",
  "flowy-derive",
+ "flowy-error",
+ "lib-dispatch",
+ "lib-infra",
+ "lib-ws",
+ "parking_lot",
  "protobuf",
+ "strum",
+ "strum_macros",
+ "tokio",
+ "tracing",
 ]
 
 [[package]]
@@ -1416,7 +1438,6 @@ dependencies = [
  "lib-dispatch",
  "lib-infra",
  "lib-sqlite",
- "lib-ws",
  "log",
  "once_cell",
  "parking_lot",

+ 1 - 0
backend/Cargo.toml

@@ -103,4 +103,5 @@ flowy-sdk = { path = "../frontend/rust-lib/flowy-sdk", features = ["http_server"
 flowy-user = { path = "../frontend/rust-lib/flowy-user", features = ["http_server"] }
 flowy-document = { path = "../frontend/rust-lib/flowy-document", features = ["flowy_unit_test", "http_server"] }
 flowy-test = { path = "../frontend/rust-lib/flowy-test" }
+flowy-net = { path = "../frontend/rust-lib/flowy-net" }
 

+ 6 - 1
backend/tests/document/helper.rs

@@ -16,6 +16,7 @@ use lib_ot::rich_text::{RichTextAttribute, RichTextDelta};
 use parking_lot::RwLock;
 use lib_ot::core::Interval;
 use flowy_collaboration::core::sync::ServerDocManager;
+use flowy_net::services::ws::WsManager;
 
 pub struct DocumentTest {
     server: TestServer,
@@ -53,6 +54,7 @@ struct ScriptContext {
     client_edit_context: Option<Arc<ClientEditDocContext>>,
     client_sdk: FlowySDKTest,
     client_user_session: Arc<UserSession>,
+    ws_manager: Arc<WsManager>,
     server_doc_manager: Arc<ServerDocManager>,
     server_pg_pool: Data<PgPool>,
     doc_id: String,
@@ -61,12 +63,14 @@ struct ScriptContext {
 impl ScriptContext {
     async fn new(client_sdk: FlowySDKTest, server: TestServer) -> Self {
         let user_session = client_sdk.user_session.clone();
+        let ws_manager = client_sdk.ws_manager.clone();
         let doc_id = create_doc(&client_sdk).await;
 
         Self {
             client_edit_context: None,
             client_sdk,
             client_user_session: user_session,
+            ws_manager,
             server_doc_manager: server.app_ctx.document_core.manager.clone(),
             server_pg_pool: Data::new(server.pg_pool.clone()),
             doc_id,
@@ -99,9 +103,10 @@ async fn run_scripts(context: Arc<RwLock<ScriptContext>>, scripts: Vec<DocScript
             match script {
                 DocScript::ClientConnectWs => {
                     // sleep(Duration::from_millis(300)).await;
+                    let ws_manager = context.read().ws_manager.clone();
                     let user_session = context.read().client_user_session.clone();
                     let token = user_session.token().unwrap();
-                    let _ = user_session.start_ws_connection(&token).await.unwrap();
+                    let _ = ws_manager.start(token).await.unwrap();
                 },
                 DocScript::ClientOpenDoc => {
                     context.write().open_doc().await;

+ 2 - 2
frontend/app_flowy/lib/user/infrastructure/network_monitor.dart

@@ -3,7 +3,7 @@ import 'dart:async';
 import 'package:connectivity_plus/connectivity_plus.dart';
 import 'package:flowy_log/flowy_log.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
-import 'package:flowy_sdk/protobuf/lib-infra/protobuf.dart';
+import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart';
 import 'package:flutter/services.dart';
 
 class NetworkMonitor {
@@ -45,7 +45,7 @@ class NetworkMonitor {
     }();
     Log.info("Network type: $networkType");
     final state = NetworkState.create()..ty = networkType;
-    UserEventUpdateNetworkType(state).send().then((result) {
+    NetworkEventUpdateNetworkType(state).send().then((result) {
       result.fold(
         (l) {},
         (e) => Log.error(e),

+ 17 - 17
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -412,6 +412,23 @@ class WorkspaceEventExportDocument {
     }
 }
 
+class NetworkEventUpdateNetworkType {
+     NetworkState request;
+     NetworkEventUpdateNetworkType(this.request);
+
+    Future<Either<Unit, FlowyError>> send() {
+    final request = FFIRequest.create()
+          ..event = NetworkEvent.UpdateNetworkType.toString()
+          ..payload = requestToBytes(this.request);
+
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+           (bytes) => left(unit),
+           (errBytes) => right(FlowyError.fromBuffer(errBytes)),
+        ));
+    }
+}
+
 class UserEventInitUser {
     UserEventInitUser();
 
@@ -519,20 +536,3 @@ class UserEventCheckUser {
     }
 }
 
-class UserEventUpdateNetworkType {
-     NetworkState request;
-     UserEventUpdateNetworkType(this.request);
-
-    Future<Either<Unit, UserError>> send() {
-    final request = FFIRequest.create()
-          ..event = UserEvent.UpdateNetworkType.toString()
-          ..payload = requestToBytes(this.request);
-
-    return Dispatch.asyncRequest(request)
-        .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(UserError.fromBuffer(errBytes)),
-        ));
-    }
-}
-

+ 4 - 2
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart

@@ -3,6 +3,8 @@ import 'package:dartz/dartz.dart';
 import 'package:flowy_log/flowy_log.dart';
 // ignore: unnecessary_import
 import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-net/event.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/event.pb.dart';
@@ -53,7 +55,7 @@ class Dispatch {
   }
 }
 
-Future<Either<Uint8List, Uint8List>> _extractPayload(Future<Either<FFIResponse, FlowyError>> responseFuture) {
+Future<Either<Uint8List, Uint8List>> _extractPayload(Future<Either<FFIResponse, FlowyInternalError>> responseFuture) {
   return responseFuture.then((result) {
     return result.fold(
       (response) {
@@ -79,7 +81,7 @@ Future<Either<Uint8List, Uint8List>> _extractPayload(Future<Either<FFIResponse,
   });
 }
 
-Future<Either<FFIResponse, FlowyError>> _extractResponse(Completer<Uint8List> bytesFuture) {
+Future<Either<FFIResponse, FlowyInternalError>> _extractResponse(Completer<Uint8List> bytesFuture) {
   return bytesFuture.future.then((bytes) {
     try {
       final response = FFIResponse.fromBuffer(bytes);

+ 6 - 6
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/error.dart

@@ -1,6 +1,6 @@
 import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart';
 
-class FlowyError {
+class FlowyInternalError {
   late FFIStatusCode _statusCode;
   late String _error;
 
@@ -20,13 +20,13 @@ class FlowyError {
     return "$_statusCode: $_error";
   }
 
-  FlowyError({required FFIStatusCode statusCode, required String error}) {
+  FlowyInternalError({required FFIStatusCode statusCode, required String error}) {
     _statusCode = statusCode;
     _error = error;
   }
 
-  factory FlowyError.from(FFIResponse resp) {
-    return FlowyError(statusCode: resp.code, error: "");
+  factory FlowyInternalError.from(FFIResponse resp) {
+    return FlowyInternalError(statusCode: resp.code, error: "");
   }
 }
 
@@ -38,8 +38,8 @@ class StackTraceError {
     this.trace,
   );
 
-  FlowyError asFlowyError() {
-    return FlowyError(statusCode: FFIStatusCode.Err, error: this.toString());
+  FlowyInternalError asFlowyError() {
+    return FlowyInternalError(statusCode: FFIStatusCode.Err, error: this.toString());
   }
 
   String toString() {

+ 74 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pb.dart

@@ -0,0 +1,74 @@
+///
+//  Generated code. Do not modify.
+//  source: errors.proto
+//
+// @dart = 2.12
+// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+export 'errors.pbenum.dart';
+
+class FlowyError extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FlowyError', createEmptyInstance: create)
+    ..a<$core.int>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.O3)
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'msg')
+    ..hasRequiredFields = false
+  ;
+
+  FlowyError._() : super();
+  factory FlowyError({
+    $core.int? code,
+    $core.String? msg,
+  }) {
+    final _result = create();
+    if (code != null) {
+      _result.code = code;
+    }
+    if (msg != null) {
+      _result.msg = msg;
+    }
+    return _result;
+  }
+  factory FlowyError.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory FlowyError.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')
+  FlowyError clone() => FlowyError()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  FlowyError copyWith(void Function(FlowyError) updates) => super.copyWith((message) => updates(message as FlowyError)) as FlowyError; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static FlowyError create() => FlowyError._();
+  FlowyError createEmptyInstance() => create();
+  static $pb.PbList<FlowyError> createRepeated() => $pb.PbList<FlowyError>();
+  @$core.pragma('dart2js:noInline')
+  static FlowyError getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FlowyError>(create);
+  static FlowyError? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get code => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set code($core.int v) { $_setSignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasCode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearCode() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get msg => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set msg($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasMsg() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearMsg() => clearField(2);
+}
+

+ 24 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbenum.dart

@@ -0,0 +1,24 @@
+///
+//  Generated code. Do not modify.
+//  source: errors.proto
+//
+// @dart = 2.12
+// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+// ignore_for_file: UNDEFINED_SHOWN_NAME
+import 'dart:core' as $core;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class ErrorCode extends $pb.ProtobufEnum {
+  static const ErrorCode Internal = ErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Internal');
+
+  static const $core.List<ErrorCode> values = <ErrorCode> [
+    Internal,
+  ];
+
+  static final $core.Map<$core.int, ErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ErrorCode? valueOf($core.int value) => _byValue[value];
+
+  const ErrorCode._($core.int v, $core.String n) : super(v, n);
+}
+

+ 31 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbjson.dart

@@ -0,0 +1,31 @@
+///
+//  Generated code. Do not modify.
+//  source: errors.proto
+//
+// @dart = 2.12
+// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
+
+import 'dart:core' as $core;
+import 'dart:convert' as $convert;
+import 'dart:typed_data' as $typed_data;
+@$core.Deprecated('Use errorCodeDescriptor instead')
+const ErrorCode$json = const {
+  '1': 'ErrorCode',
+  '2': const [
+    const {'1': 'Internal', '2': 0},
+  ],
+};
+
+/// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQAA==');
+@$core.Deprecated('Use flowyErrorDescriptor instead')
+const FlowyError$json = const {
+  '1': 'FlowyError',
+  '2': const [
+    const {'1': 'code', '3': 1, '4': 1, '5': 5, '10': 'code'},
+    const {'1': 'msg', '3': 2, '4': 1, '5': 9, '10': 'msg'},
+  ],
+};
+
+/// Descriptor for `FlowyError`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List flowyErrorDescriptor = $convert.base64Decode('CgpGbG93eUVycm9yEhIKBGNvZGUYASABKAVSBGNvZGUSEAoDbXNnGAIgASgJUgNtc2c=');

+ 9 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/errors.pbserver.dart

@@ -0,0 +1,9 @@
+///
+//  Generated code. Do not modify.
+//  source: errors.proto
+//
+// @dart = 2.12
+// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
+
+export 'errors.pb.dart';
+

+ 2 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error/protobuf.dart

@@ -0,0 +1,2 @@
+// Auto-generated, do not edit 
+export './errors.pb.dart';

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/cache.pb.dart → frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pb.dart

@@ -1,11 +1,11 @@
 ///
 //  Generated code. Do not modify.
-//  source: cache.proto
+//  source: event.proto
 //
 // @dart = 2.12
 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
 
 import 'dart:core' as $core;
 
-export 'cache.pbenum.dart';
+export 'event.pbenum.dart';
 

+ 24 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbenum.dart

@@ -0,0 +1,24 @@
+///
+//  Generated code. Do not modify.
+//  source: event.proto
+//
+// @dart = 2.12
+// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+// ignore_for_file: UNDEFINED_SHOWN_NAME
+import 'dart:core' as $core;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class NetworkEvent extends $pb.ProtobufEnum {
+  static const NetworkEvent UpdateNetworkType = NetworkEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateNetworkType');
+
+  static const $core.List<NetworkEvent> values = <NetworkEvent> [
+    UpdateNetworkType,
+  ];
+
+  static final $core.Map<$core.int, NetworkEvent> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static NetworkEvent? valueOf($core.int value) => _byValue[value];
+
+  const NetworkEvent._($core.int v, $core.String n) : super(v, n);
+}
+

+ 7 - 8
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/cache.pbjson.dart → frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbjson.dart

@@ -1,6 +1,6 @@
 ///
 //  Generated code. Do not modify.
-//  source: cache.proto
+//  source: event.proto
 //
 // @dart = 2.12
 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
@@ -8,14 +8,13 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use revStateDescriptor instead')
-const RevState$json = const {
-  '1': 'RevState',
+@$core.Deprecated('Use networkEventDescriptor instead')
+const NetworkEvent$json = const {
+  '1': 'NetworkEvent',
   '2': const [
-    const {'1': 'Local', '2': 0},
-    const {'1': 'Acked', '2': 1},
+    const {'1': 'UpdateNetworkType', '2': 0},
   ],
 };
 
-/// Descriptor for `RevState`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List revStateDescriptor = $convert.base64Decode('CghSZXZTdGF0ZRIJCgVMb2NhbBAAEgkKBUFja2VkEAE=');
+/// Descriptor for `NetworkEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List networkEventDescriptor = $convert.base64Decode('CgxOZXR3b3JrRXZlbnQSFQoRVXBkYXRlTmV0d29ya1R5cGUQAA==');

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/cache.pbserver.dart → frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/event.pbserver.dart

@@ -1,9 +1,9 @@
 ///
 //  Generated code. Do not modify.
-//  source: cache.proto
+//  source: event.proto
 //
 // @dart = 2.12
 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
 
-export 'cache.pb.dart';
+export 'event.pb.dart';
 

+ 1 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-net/protobuf.dart

@@ -1,2 +1,3 @@
 // Auto-generated, do not edit 
 export './network_state.pb.dart';
+export './event.pb.dart';

+ 0 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart

@@ -17,7 +17,6 @@ class UserEvent extends $pb.ProtobufEnum {
   static const UserEvent UpdateUser = UserEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateUser');
   static const UserEvent GetUserProfile = UserEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetUserProfile');
   static const UserEvent CheckUser = UserEvent._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CheckUser');
-  static const UserEvent UpdateNetworkType = UserEvent._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateNetworkType');
 
   static const $core.List<UserEvent> values = <UserEvent> [
     InitUser,
@@ -27,7 +26,6 @@ class UserEvent extends $pb.ProtobufEnum {
     UpdateUser,
     GetUserProfile,
     CheckUser,
-    UpdateNetworkType,
   ];
 
   static final $core.Map<$core.int, UserEvent> _byValue = $pb.ProtobufEnum.initByValue(values);

+ 1 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart

@@ -19,9 +19,8 @@ const UserEvent$json = const {
     const {'1': 'UpdateUser', '2': 4},
     const {'1': 'GetUserProfile', '2': 5},
     const {'1': 'CheckUser', '2': 6},
-    const {'1': 'UpdateNetworkType', '2': 10},
   ],
 };
 
 /// Descriptor for `UserEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAYSFQoRVXBkYXRlTmV0d29ya1R5cGUQCg==');
+final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAY=');

+ 0 - 26
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/cache.pbenum.dart

@@ -1,26 +0,0 @@
-///
-//  Generated code. Do not modify.
-//  source: cache.proto
-//
-// @dart = 2.12
-// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
-
-// ignore_for_file: UNDEFINED_SHOWN_NAME
-import 'dart:core' as $core;
-import 'package:protobuf/protobuf.dart' as $pb;
-
-class RevState extends $pb.ProtobufEnum {
-  static const RevState Local = RevState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Local');
-  static const RevState Acked = RevState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Acked');
-
-  static const $core.List<RevState> values = <RevState> [
-    Local,
-    Acked,
-  ];
-
-  static final $core.Map<$core.int, RevState> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static RevState? valueOf($core.int value) => _byValue[value];
-
-  const RevState._($core.int v, $core.String n) : super(v, n);
-}
-

+ 15 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/model.pbenum.dart

@@ -24,3 +24,18 @@ class RevType extends $pb.ProtobufEnum {
   const RevType._($core.int v, $core.String n) : super(v, n);
 }
 
+class RevState extends $pb.ProtobufEnum {
+  static const RevState StateLocal = RevState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'StateLocal');
+  static const RevState Acked = RevState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Acked');
+
+  static const $core.List<RevState> values = <RevState> [
+    StateLocal,
+    Acked,
+  ];
+
+  static final $core.Map<$core.int, RevState> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static RevState? valueOf($core.int value) => _byValue[value];
+
+  const RevState._($core.int v, $core.String n) : super(v, n);
+}
+

+ 11 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/model.pbjson.dart

@@ -19,6 +19,17 @@ const RevType$json = const {
 
 /// Descriptor for `RevType`. Decode as a `google.protobuf.EnumDescriptorProto`.
 final $typed_data.Uint8List revTypeDescriptor = $convert.base64Decode('CgdSZXZUeXBlEgkKBUxvY2FsEAASCgoGUmVtb3RlEAE=');
+@$core.Deprecated('Use revStateDescriptor instead')
+const RevState$json = const {
+  '1': 'RevState',
+  '2': const [
+    const {'1': 'StateLocal', '2': 0},
+    const {'1': 'Acked', '2': 1},
+  ],
+};
+
+/// Descriptor for `RevState`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List revStateDescriptor = $convert.base64Decode('CghSZXZTdGF0ZRIOCgpTdGF0ZUxvY2FsEAASCQoFQWNrZWQQAQ==');
 @$core.Deprecated('Use revisionDescriptor instead')
 const Revision$json = const {
   '1': 'Revision',

+ 0 - 1
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ot/protobuf.dart

@@ -1,3 +1,2 @@
 // Auto-generated, do not edit 
-export './cache.pb.dart';
 export './model.pb.dart';

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

@@ -11,6 +11,7 @@ members = [
   "flowy-core",
   "dart-notify",
   "flowy-document",
+  "flowy-error",
 ]
 
 exclude = ["../backend"]

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

@@ -52,7 +52,7 @@ color-eyre = { version = "0.5", default-features = false }
 criterion = "0.3"
 rand = "0.7.3"
 env_logger = "0.8.2"
-flowy-user = { path = "../flowy-user", features = ["ws_mock"] }
+flowy-net = { path = "../flowy-net", features = ["ws_mock"] }
 
 [features]
 http_server = []

+ 2 - 2
frontend/rust-lib/flowy-document/src/services/doc/revision/cache/cache.rs

@@ -63,7 +63,7 @@ impl RevisionCache {
         }
         let record = RevisionRecord {
             revision,
-            state: RevState::Local,
+            state: RevState::StateLocal,
         };
         self.memory_cache.add_revision(record).await?;
         self.save_revisions().await;
@@ -77,7 +77,7 @@ impl RevisionCache {
         }
         let record = RevisionRecord {
             revision,
-            state: RevState::Local,
+            state: RevState::StateLocal,
         };
         self.memory_cache.add_revision(record).await?;
         self.save_revisions().await;

+ 1 - 1
frontend/rust-lib/flowy-document/src/services/doc/revision/cache/memory.rs

@@ -35,7 +35,7 @@ impl RevisionMemoryCache {
         }
 
         match record.state {
-            RevState::Local => {
+            RevState::StateLocal => {
                 tracing::debug!("{}:add revision {}", record.revision.doc_id, record.revision.rev_id);
                 self.local_revs.write().await.push_back(record.revision.rev_id);
             },

+ 2 - 2
frontend/rust-lib/flowy-document/src/services/ws/ws_manager.rs

@@ -13,7 +13,7 @@ pub(crate) trait WsDocumentHandler: Send + Sync {
 pub type WsStateReceiver = tokio::sync::broadcast::Receiver<WsConnectState>;
 pub trait DocumentWebSocket: Send + Sync {
     fn send(&self, data: WsDocumentData) -> Result<(), DocError>;
-    fn state_notify(&self) -> WsStateReceiver;
+    fn subscribe_state_changed(&self) -> WsStateReceiver;
 }
 
 pub struct WsDocumentManager {
@@ -56,7 +56,7 @@ impl WsDocumentManager {
 
 #[tracing::instrument(level = "debug", skip(ws, handlers))]
 fn listen_ws_state_changed(ws: Arc<dyn DocumentWebSocket>, handlers: Arc<DashMap<String, Arc<dyn WsDocumentHandler>>>) {
-    let mut notify = ws.state_notify();
+    let mut notify = ws.subscribe_state_changed();
     tokio::spawn(async move {
         while let Ok(state) = notify.recv().await {
             handlers.iter().for_each(|handle| {

+ 2 - 2
frontend/rust-lib/flowy-document/src/sql_tables/doc/rev_table.rs

@@ -49,7 +49,7 @@ impl_sql_integer_expression!(RevTableState);
 impl std::convert::From<RevTableState> for RevState {
     fn from(s: RevTableState) -> Self {
         match s {
-            RevTableState::Local => RevState::Local,
+            RevTableState::Local => RevState::StateLocal,
             RevTableState::Acked => RevState::Acked,
         }
     }
@@ -58,7 +58,7 @@ impl std::convert::From<RevTableState> for RevState {
 impl std::convert::From<RevState> for RevTableState {
     fn from(s: RevState) -> Self {
         match s {
-            RevState::Local => RevTableState::Local,
+            RevState::StateLocal => RevTableState::Local,
             RevState::Acked => RevTableState::Acked,
         }
     }

+ 5 - 5
frontend/rust-lib/flowy-document/tests/editor/revision_test.rs

@@ -6,7 +6,7 @@ async fn doc_rev_state_test1() {
     let scripts = vec![
         InsertText("123", 0),
         AssertCurrentRevId(1),
-        AssertRevisionState(1, RevState::Local),
+        AssertRevisionState(1, RevState::StateLocal),
         SimulateAckedMessage(1),
         AssertRevisionState(1, RevState::Acked),
         AssertNextSendingRevision(None),
@@ -22,9 +22,9 @@ async fn doc_rev_state_test2() {
         InsertText("2", 1),
         InsertText("3", 2),
         AssertCurrentRevId(3),
-        AssertRevisionState(1, RevState::Local),
-        AssertRevisionState(2, RevState::Local),
-        AssertRevisionState(3, RevState::Local),
+        AssertRevisionState(1, RevState::StateLocal),
+        AssertRevisionState(2, RevState::StateLocal),
+        AssertRevisionState(3, RevState::StateLocal),
         SimulateAckedMessage(1),
         AssertRevisionState(1, RevState::Acked),
         AssertNextSendingRevision(Some(2)),
@@ -32,7 +32,7 @@ async fn doc_rev_state_test2() {
         AssertRevisionState(2, RevState::Acked),
         //
         AssertNextSendingRevision(Some(3)),
-        AssertRevisionState(3, RevState::Local),
+        AssertRevisionState(3, RevState::StateLocal),
         AssertJson(r#"[{"insert":"123\n"}]"#),
     ];
     EditorTest::new().await.run_scripts(scripts).await;

+ 13 - 0
frontend/rust-lib/flowy-error/Cargo.toml

@@ -0,0 +1,13 @@
+[package]
+name = "flowy-error"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+flowy-derive = { path = "../../../shared-lib/flowy-derive" }
+derive_more = {version = "0.99", features = ["display"]}
+lib-dispatch = { path = "../lib-dispatch" }
+protobuf = {version = "2.20.0"}
+bytes = "1.0"

+ 3 - 0
frontend/rust-lib/flowy-error/Flowy.toml

@@ -0,0 +1,3 @@
+
+proto_crates = ["src/errors.rs",]
+event_files = []

+ 84 - 0
frontend/rust-lib/flowy-error/src/errors.rs

@@ -0,0 +1,84 @@
+use crate::protobuf::ErrorCode as ProtoBufErrorCode;
+use bytes::Bytes;
+use derive_more::Display;
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+use lib_dispatch::prelude::{EventResponse, ResponseBuilder};
+use protobuf::ProtobufEnum;
+use std::{
+    convert::{TryFrom, TryInto},
+    fmt::Debug,
+};
+
+#[derive(Debug, Default, Clone, ProtoBuf)]
+pub struct FlowyError {
+    #[pb(index = 1)]
+    pub code: i32,
+
+    #[pb(index = 2)]
+    pub msg: String,
+}
+
+macro_rules! static_any_error {
+    ($name:ident, $code:expr) => {
+        #[allow(non_snake_case, missing_docs)]
+        pub fn $name() -> FlowyError { $code.into() }
+    };
+}
+
+impl FlowyError {
+    pub fn new(code: ErrorCode, msg: &str) -> Self {
+        Self {
+            code: code.value(),
+            msg: msg.to_owned(),
+        }
+    }
+    pub fn context<T: Debug>(mut self, error: T) -> Self {
+        self.msg = format!("{:?}", error);
+        self
+    }
+
+    static_any_error!(internal, ErrorCode::Internal);
+}
+
+impl std::convert::From<ErrorCode> for FlowyError {
+    fn from(code: ErrorCode) -> Self {
+        FlowyError {
+            code: code.value(),
+            msg: format!("{}", code),
+        }
+    }
+}
+
+#[derive(Debug, Clone, ProtoBuf_Enum, Display, PartialEq, Eq)]
+pub enum ErrorCode {
+    #[display(fmt = "Internal error")]
+    Internal = 0,
+}
+
+impl ErrorCode {
+    pub fn value(&self) -> i32 {
+        let code: ProtoBufErrorCode = self.clone().try_into().unwrap();
+        code.value()
+    }
+
+    pub fn from_i32(value: i32) -> Self {
+        match ProtoBufErrorCode::from_i32(value) {
+            None => ErrorCode::Internal,
+            Some(code) => ErrorCode::try_from(&code).unwrap(),
+        }
+    }
+}
+
+pub fn internal_error<T>(e: T) -> FlowyError
+where
+    T: std::fmt::Debug,
+{
+    FlowyError::internal().context(e)
+}
+
+impl lib_dispatch::Error for FlowyError {
+    fn as_response(&self) -> EventResponse {
+        let bytes: Bytes = self.clone().try_into().unwrap();
+        ResponseBuilder::Err().data(bytes).build()
+    }
+}

+ 4 - 0
frontend/rust-lib/flowy-error/src/lib.rs

@@ -0,0 +1,4 @@
+mod errors;
+pub mod protobuf;
+
+pub use errors::*;

+ 4 - 0
frontend/rust-lib/flowy-error/src/protobuf/mod.rs

@@ -0,0 +1,4 @@
+#![cfg_attr(rustfmt, rustfmt::skip)]
+// Auto-generated, do not edit
+mod model;
+pub use model::*;

+ 293 - 0
frontend/rust-lib/flowy-error/src/protobuf/model/errors.rs

@@ -0,0 +1,293 @@
+// This file is generated by rust-protobuf 2.22.1. Do not edit
+// @generated
+
+// https://github.com/rust-lang/rust-clippy/issues/702
+#![allow(unknown_lints)]
+#![allow(clippy::all)]
+
+#![allow(unused_attributes)]
+#![cfg_attr(rustfmt, rustfmt::skip)]
+
+#![allow(box_pointers)]
+#![allow(dead_code)]
+#![allow(missing_docs)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+#![allow(trivial_casts)]
+#![allow(unused_imports)]
+#![allow(unused_results)]
+//! Generated file from `errors.proto`
+
+/// Generated files are compatible only with the same version
+/// of protobuf runtime.
+// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
+
+#[derive(PartialEq,Clone,Default)]
+pub struct FlowyError {
+    // message fields
+    pub code: i32,
+    pub msg: ::std::string::String,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a FlowyError {
+    fn default() -> &'a FlowyError {
+        <FlowyError as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl FlowyError {
+    pub fn new() -> FlowyError {
+        ::std::default::Default::default()
+    }
+
+    // int32 code = 1;
+
+
+    pub fn get_code(&self) -> i32 {
+        self.code
+    }
+    pub fn clear_code(&mut self) {
+        self.code = 0;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_code(&mut self, v: i32) {
+        self.code = v;
+    }
+
+    // string msg = 2;
+
+
+    pub fn get_msg(&self) -> &str {
+        &self.msg
+    }
+    pub fn clear_msg(&mut self) {
+        self.msg.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_msg(&mut self, v: ::std::string::String) {
+        self.msg = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_msg(&mut self) -> &mut ::std::string::String {
+        &mut self.msg
+    }
+
+    // Take field
+    pub fn take_msg(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.msg, ::std::string::String::new())
+    }
+}
+
+impl ::protobuf::Message for FlowyError {
+    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 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    let tmp = is.read_int32()?;
+                    self.code = tmp;
+                },
+                2 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.msg)?;
+                },
+                _ => {
+                    ::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.code != 0 {
+            my_size += ::protobuf::rt::value_size(1, self.code, ::protobuf::wire_format::WireTypeVarint);
+        }
+        if !self.msg.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.msg);
+        }
+        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.code != 0 {
+            os.write_int32(1, self.code)?;
+        }
+        if !self.msg.is_empty() {
+            os.write_string(2, &self.msg)?;
+        }
+        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() -> FlowyError {
+        FlowyError::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::ProtobufTypeInt32>(
+                "code",
+                |m: &FlowyError| { &m.code },
+                |m: &mut FlowyError| { &mut m.code },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "msg",
+                |m: &FlowyError| { &m.msg },
+                |m: &mut FlowyError| { &mut m.msg },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<FlowyError>(
+                "FlowyError",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static FlowyError {
+        static instance: ::protobuf::rt::LazyV2<FlowyError> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(FlowyError::new)
+    }
+}
+
+impl ::protobuf::Clear for FlowyError {
+    fn clear(&mut self) {
+        self.code = 0;
+        self.msg.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for FlowyError {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for FlowyError {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum ErrorCode {
+    Internal = 0,
+}
+
+impl ::protobuf::ProtobufEnum for ErrorCode {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<ErrorCode> {
+        match value {
+            0 => ::std::option::Option::Some(ErrorCode::Internal),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [ErrorCode] = &[
+            ErrorCode::Internal,
+        ];
+        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::<ErrorCode>("ErrorCode", file_descriptor_proto())
+        })
+    }
+}
+
+impl ::std::marker::Copy for ErrorCode {
+}
+
+impl ::std::default::Default for ErrorCode {
+    fn default() -> Self {
+        ErrorCode::Internal
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for ErrorCode {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
+static file_descriptor_proto_data: &'static [u8] = b"\
+    \n\x0cerrors.proto\"2\n\nFlowyError\x12\x12\n\x04code\x18\x01\x20\x01(\
+    \x05R\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03msg*\x19\n\tErrorC\
+    ode\x12\x0c\n\x08Internal\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\x12\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
+    \x04\x13\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\
+    \x02\0\x01\x12\x03\x03\n\x0e\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x11\
+    \x12\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\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\
+    \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\x0e\n\x0b\n\
+    \x04\x05\0\x02\0\x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\
+    \x07\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0f\x10b\x06proto3\
+";
+
+static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
+
+fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
+    ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
+}
+
+pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
+    file_descriptor_proto_lazy.get(|| {
+        parse_descriptor_proto()
+    })
+}

+ 5 - 0
frontend/rust-lib/flowy-error/src/protobuf/model/mod.rs

@@ -0,0 +1,5 @@
+#![cfg_attr(rustfmt, rustfmt::skip)]
+// Auto-generated, do not edit
+
+mod errors;
+pub use errors::*;

+ 9 - 0
frontend/rust-lib/flowy-error/src/protobuf/proto/errors.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+message FlowyError {
+    int32 code = 1;
+    string msg = 2;
+}
+enum ErrorCode {
+    Internal = 0;
+}

+ 18 - 1
frontend/rust-lib/flowy-net/Cargo.toml

@@ -6,6 +6,23 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+lib-dispatch = { path = "../lib-dispatch" }
+flowy-error = { path = "../flowy-error" }
 flowy-derive = { path = "../../../shared-lib/flowy-derive" }
+lib-infra = { path = "../../../shared-lib/lib-infra" }
+lib-ws = { path = "../../../shared-lib/lib-ws" }
 protobuf = {version = "2.18.0"}
-bytes = { version = "1.0" }
+bytes = { version = "1.0" }
+anyhow = "1.0"
+tokio = {version = "1", features = ["sync"]}
+parking_lot = "0.11"
+strum = "0.21"
+strum_macros = "0.21"
+tracing = { version = "0.1", features = ["log"] }
+
+flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration", optional = true}
+lazy_static = {version = "1.4.0", optional = true}
+dashmap = {version = "4.0", optional = true}
+
+[features]
+ws_mock = ["flowy-collaboration", "lazy_static", "dashmap"]

+ 2 - 2
frontend/rust-lib/flowy-net/Flowy.toml

@@ -1,2 +1,2 @@
-proto_crates = ["src/entities"]
-event_files = []
+proto_crates = ["src/event.rs", "src/entities"]
+event_files = ["src/event.rs"]

+ 9 - 0
frontend/rust-lib/flowy-net/src/event.rs

@@ -0,0 +1,9 @@
+use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
+use strum_macros::Display;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
+#[event_err = "FlowyError"]
+pub enum NetworkEvent {
+    #[event(input = "NetworkState")]
+    UpdateNetworkType = 0,
+}

+ 12 - 0
frontend/rust-lib/flowy-net/src/handlers/mod.rs

@@ -0,0 +1,12 @@
+use crate::{entities::NetworkState, services::ws::WsManager};
+use bytes::Bytes;
+use flowy_error::FlowyError;
+use lib_dispatch::prelude::{Data, Unit};
+use std::sync::Arc;
+
+#[tracing::instrument(skip(data, ws_manager))]
+pub async fn update_network_ty(data: Data<NetworkState>, ws_manager: Unit<Arc<WsManager>>) -> Result<(), FlowyError> {
+    let network_state = data.into_inner();
+    ws_manager.update_network_type(&network_state.ty);
+    Ok(())
+}

+ 4 - 0
frontend/rust-lib/flowy-net/src/lib.rs

@@ -1,2 +1,6 @@
 pub mod entities;
+mod event;
+mod handlers;
+pub mod module;
 pub mod protobuf;
+pub mod services;

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

@@ -0,0 +1,10 @@
+use crate::{event::NetworkEvent, handlers::*, services::ws::WsManager};
+use lib_dispatch::prelude::*;
+use std::sync::Arc;
+
+pub fn create(ws_manager: Arc<WsManager>) -> Module {
+    Module::new()
+        .name("Flowy-Network")
+        .data(ws_manager.clone())
+        .event(NetworkEvent::UpdateNetworkType, update_network_ty)
+}

+ 18 - 23
shared-lib/lib-ot/src/protobuf/model/cache.rs → frontend/rust-lib/flowy-net/src/protobuf/model/event.rs

@@ -17,35 +17,32 @@
 #![allow(trivial_casts)]
 #![allow(unused_imports)]
 #![allow(unused_results)]
-//! Generated file from `cache.proto`
+//! Generated file from `event.proto`
 
 /// Generated files are compatible only with the same version
 /// of protobuf runtime.
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum RevState {
-    Local = 0,
-    Acked = 1,
+pub enum NetworkEvent {
+    UpdateNetworkType = 0,
 }
 
-impl ::protobuf::ProtobufEnum for RevState {
+impl ::protobuf::ProtobufEnum for NetworkEvent {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<RevState> {
+    fn from_i32(value: i32) -> ::std::option::Option<NetworkEvent> {
         match value {
-            0 => ::std::option::Option::Some(RevState::Local),
-            1 => ::std::option::Option::Some(RevState::Acked),
+            0 => ::std::option::Option::Some(NetworkEvent::UpdateNetworkType),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [RevState] = &[
-            RevState::Local,
-            RevState::Acked,
+        static values: &'static [NetworkEvent] = &[
+            NetworkEvent::UpdateNetworkType,
         ];
         values
     }
@@ -53,34 +50,32 @@ impl ::protobuf::ProtobufEnum for RevState {
     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::<RevState>("RevState", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<NetworkEvent>("NetworkEvent", file_descriptor_proto())
         })
     }
 }
 
-impl ::std::marker::Copy for RevState {
+impl ::std::marker::Copy for NetworkEvent {
 }
 
-impl ::std::default::Default for RevState {
+impl ::std::default::Default for NetworkEvent {
     fn default() -> Self {
-        RevState::Local
+        NetworkEvent::UpdateNetworkType
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for RevState {
+impl ::protobuf::reflect::ProtobufValue for NetworkEvent {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bcache.proto*\x20\n\x08RevState\x12\t\n\x05Local\x10\0\x12\t\n\x05A\
-    cked\x10\x01J|\n\x06\x12\x04\0\0\x05\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\
-    \n\n\n\x02\x05\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\
-    \x05\r\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x0e\n\x0c\n\x05\x05\0\x02\
-    \0\x01\x12\x03\x03\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x0c\r\n\
-    \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0e\n\x0c\n\x05\x05\0\x02\x01\
-    \x01\x12\x03\x04\x04\t\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x0c\rb\
+    \n\x0bevent.proto*%\n\x0cNetworkEvent\x12\x15\n\x11UpdateNetworkType\x10\
+    \0JS\n\x06\x12\x04\0\0\x04\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
+    \x05\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x11\n\
+    \x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x05\0\x02\0\x01\
+    \x12\x03\x03\x04\x15\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x18\x19b\
     \x06proto3\
 ";
 

+ 3 - 0
frontend/rust-lib/flowy-net/src/protobuf/model/mod.rs

@@ -3,3 +3,6 @@
 
 mod network_state;
 pub use network_state::*;
+
+mod event;
+pub use event::*;

+ 5 - 0
frontend/rust-lib/flowy-net/src/protobuf/proto/event.proto

@@ -0,0 +1,5 @@
+syntax = "proto3";
+
+enum NetworkEvent {
+    UpdateNetworkType = 0;
+}

+ 3 - 0
frontend/rust-lib/flowy-net/src/services/mock/mod.rs

@@ -0,0 +1,3 @@
+mod ws_mock;
+
+pub use ws_mock::*;

+ 11 - 15
frontend/rust-lib/flowy-user/src/services/server/ws_mock.rs → frontend/rust-lib/flowy-net/src/services/mock/ws_mock.rs

@@ -1,23 +1,19 @@
-use crate::{
-    errors::UserError,
-    services::user::ws_manager::{FlowyWebSocket, FlowyWsSender},
-};
+use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WsConnectState, WsMessage, WsMessageHandler};
 use bytes::Bytes;
 use dashmap::DashMap;
 use flowy_collaboration::{
-    core::sync::{ServerDocManager, ServerDocPersistence},
+    core::sync::{RevisionUser, ServerDocManager, ServerDocPersistence, SyncResponse},
     entities::{
         doc::Doc,
         ws::{WsDataType, WsDocumentData},
     },
     errors::CollaborateError,
+    Revision,
+    RichTextDelta,
 };
 use lazy_static::lazy_static;
 use lib_infra::future::{FutureResult, FutureResultSend};
-use lib_ot::{revision::Revision, rich_text::RichTextDelta};
-use lib_ws::{WsConnectState, WsMessage, WsMessageHandler, WsModule};
-
-use flowy_collaboration::core::sync::{RevisionUser, SyncResponse};
+use lib_ws::WsModule;
 use std::{
     convert::{TryFrom, TryInto},
     sync::Arc,
@@ -47,7 +43,7 @@ impl MockWebSocket {
 }
 
 impl FlowyWebSocket for Arc<MockWebSocket> {
-    fn start_connect(&self, _addr: String) -> FutureResult<(), UserError> {
+    fn start_connect(&self, _addr: String) -> FutureResult<(), FlowyError> {
         let mut ws_receiver = self.ws_sender.subscribe();
         let cloned_ws = self.clone();
         tokio::spawn(async move {
@@ -56,7 +52,7 @@ impl FlowyWebSocket for Arc<MockWebSocket> {
                 let mut rx = DOC_SERVER.handle_ws_data(ws_data).await;
                 let new_ws_message = rx.recv().await.unwrap();
                 match cloned_ws.handlers.get(&new_ws_message.module) {
-                    None => log::error!("Can't find any handler for message: {:?}", new_ws_message),
+                    None => tracing::error!("Can't find any handler for message: {:?}", new_ws_message),
                     Some(handler) => handler.receive_message(new_ws_message.clone()),
                 }
             }
@@ -67,18 +63,18 @@ impl FlowyWebSocket for Arc<MockWebSocket> {
 
     fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
 
-    fn reconnect(&self, _count: usize) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
+    fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
 
-    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> {
+    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), FlowyError> {
         let source = handler.source();
         if self.handlers.contains_key(&source) {
-            log::error!("WsSource's {:?} is already registered", source);
+            tracing::error!("WsSource's {:?} is already registered", source);
         }
         self.handlers.insert(source, handler);
         Ok(())
     }
 
-    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> { Ok(Arc::new(self.ws_sender.clone())) }
+    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> { Ok(Arc::new(self.ws_sender.clone())) }
 }
 
 lazy_static! {

+ 4 - 0
frontend/rust-lib/flowy-net/src/services/mod.rs

@@ -0,0 +1,4 @@
+pub mod ws;
+
+#[cfg(feature = "ws_mock")]
+mod mock;

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

@@ -0,0 +1,18 @@
+use lib_infra::future::FutureResult;
+use std::sync::Arc;
+use tokio::sync::broadcast;
+
+pub use flowy_error::FlowyError;
+pub use lib_ws::{WsConnectState, WsMessage, WsMessageHandler};
+
+pub trait FlowyWebSocket: Send + Sync {
+    fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError>;
+    fn conn_state_subscribe(&self) -> broadcast::Receiver<WsConnectState>;
+    fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError>;
+    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), FlowyError>;
+    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError>;
+}
+
+pub trait FlowyWsSender: Send + Sync {
+    fn send(&self, msg: WsMessage) -> Result<(), FlowyError>;
+}

+ 44 - 50
frontend/rust-lib/flowy-user/src/services/user/ws_manager.rs → frontend/rust-lib/flowy-net/src/services/ws/manager.rs

@@ -1,42 +1,52 @@
-use crate::errors::UserError;
-
-use flowy_net::entities::NetworkType;
+use crate::{
+    entities::NetworkType,
+    services::ws::{local_web_socket, FlowyWebSocket, FlowyWsSender},
+};
+use flowy_error::{internal_error, FlowyError};
 use lib_infra::future::FutureResult;
 use lib_ws::{WsConnectState, WsController, WsMessage, WsMessageHandler, WsSender};
 use parking_lot::RwLock;
 use std::sync::Arc;
 use tokio::sync::{broadcast, broadcast::Receiver};
 
-pub trait FlowyWebSocket: Send + Sync {
-    fn start_connect(&self, addr: String) -> FutureResult<(), UserError>;
-    fn conn_state_subscribe(&self) -> broadcast::Receiver<WsConnectState>;
-    fn reconnect(&self, count: usize) -> FutureResult<(), UserError>;
-    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError>;
-    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError>;
-}
-
-pub trait FlowyWsSender: Send + Sync {
-    fn send(&self, msg: WsMessage) -> Result<(), UserError>;
-}
-
 pub struct WsManager {
     inner: Arc<dyn FlowyWebSocket>,
     connect_type: RwLock<NetworkType>,
+    status_notifier: broadcast::Sender<NetworkType>,
+    addr: String,
 }
 
 impl WsManager {
-    pub fn new() -> Self { WsManager::default() }
+    pub fn new(addr: String) -> Self {
+        let ws: Arc<dyn FlowyWebSocket> = if cfg!(feature = "http_server") {
+            Arc::new(Arc::new(WsController::new()))
+        } else {
+            local_web_socket()
+        };
+
+        let (status_notifier, _) = broadcast::channel(10);
+        WsManager {
+            inner: ws,
+            connect_type: RwLock::new(NetworkType::default()),
+            status_notifier,
+            addr,
+        }
+    }
 
-    pub async fn start(&self, addr: String) -> Result<(), UserError> {
+    pub async fn start(&self, token: String) -> Result<(), FlowyError> {
+        let addr = format!("{}/{}", self.addr, token);
         self.listen_on_websocket();
         let _ = self.inner.start_connect(addr).await?;
         Ok(())
     }
 
     pub fn update_network_type(&self, new_type: &NetworkType) {
+        tracing::debug!("Network new state: {:?}", new_type);
         let old_type = self.connect_type.read().clone();
+        let _ = self.status_notifier.send(new_type.clone());
+
         if &old_type != new_type {
-            log::debug!("Connect type switch from {:?} to {:?}", old_type, new_type);
+            tracing::debug!("Connect type switch from {:?} to {:?}", old_type, new_type);
             match (old_type.is_connect(), new_type.is_connect()) {
                 (false, true) => {
                     let ws_controller = self.inner.clone();
@@ -69,7 +79,7 @@ impl WsManager {
                         }
                     },
                     Err(e) => {
-                        log::error!("Websocket state notify error: {:?}", e);
+                        tracing::error!("Websocket state notify error: {:?}", e);
                         break;
                     },
                 }
@@ -77,76 +87,60 @@ impl WsManager {
         });
     }
 
-    pub fn state_subscribe(&self) -> broadcast::Receiver<WsConnectState> { self.inner.conn_state_subscribe() }
+    pub fn subscribe_websocket_state(&self) -> broadcast::Receiver<WsConnectState> { self.inner.conn_state_subscribe() }
+
+    pub fn subscribe_network_ty(&self) -> broadcast::Receiver<NetworkType> { self.status_notifier.subscribe() }
 
-    pub fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> {
+    pub fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), FlowyError> {
         let _ = self.inner.add_handler(handler)?;
         Ok(())
     }
 
-    pub fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> {
-        //
-        self.inner.ws_sender()
-    }
+    pub fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> { self.inner.ws_sender() }
 }
 
 async fn retry_connect(ws: Arc<dyn FlowyWebSocket>, count: usize) {
     match ws.reconnect(count).await {
         Ok(_) => {},
         Err(e) => {
-            log::error!("websocket connect failed: {:?}", e);
+            tracing::error!("websocket connect failed: {:?}", e);
         },
     }
 }
 
-impl std::default::Default for WsManager {
-    fn default() -> Self {
-        let ws: Arc<dyn FlowyWebSocket> = if cfg!(feature = "http_server") {
-            Arc::new(Arc::new(WsController::new()))
-        } else {
-            crate::services::server::local_web_socket()
-        };
-
-        WsManager {
-            inner: ws,
-            connect_type: RwLock::new(NetworkType::default()),
-        }
-    }
-}
-
 impl FlowyWebSocket for Arc<WsController> {
-    fn start_connect(&self, addr: String) -> FutureResult<(), UserError> {
+    fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError> {
         let cloned_ws = self.clone();
         FutureResult::new(async move {
-            let _ = cloned_ws.start(addr).await?;
+            let _ = cloned_ws.start(addr).await.map_err(internal_error)?;
             Ok(())
         })
     }
 
     fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_subscribe() }
 
-    fn reconnect(&self, count: usize) -> FutureResult<(), UserError> {
+    fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError> {
         let cloned_ws = self.clone();
         FutureResult::new(async move {
-            let _ = cloned_ws.retry(count).await?;
+            let _ = cloned_ws.retry(count).await.map_err(internal_error)?;
             Ok(())
         })
     }
 
-    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> {
+    fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), FlowyError> {
         let _ = self.add_handler(handler)?;
         Ok(())
     }
 
-    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> {
-        let sender = self.sender()?;
+    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> {
+        let sender = self.sender().map_err(internal_error)?;
         Ok(sender)
     }
 }
 
 impl FlowyWsSender for WsSender {
-    fn send(&self, msg: WsMessage) -> Result<(), UserError> {
-        let _ = self.send_msg(msg)?;
+    fn send(&self, msg: WsMessage) -> Result<(), FlowyError> {
+        let _ = self.send_msg(msg).map_err(internal_error)?;
         Ok(())
     }
 }

+ 15 - 0
frontend/rust-lib/flowy-net/src/services/ws/mod.rs

@@ -0,0 +1,15 @@
+pub use conn::*;
+pub use manager::*;
+use std::sync::Arc;
+
+mod conn;
+mod manager;
+mod ws_local;
+
+#[cfg(not(feature = "ws_mock"))]
+pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> { Arc::new(Arc::new(ws_local::LocalWebSocket::default())) }
+
+#[cfg(feature = "ws_mock")]
+pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> {
+    Arc::new(Arc::new(crate::services::mock::MockWebSocket::default()))
+}

+ 6 - 10
frontend/rust-lib/flowy-user/src/services/server/ws_local.rs → frontend/rust-lib/flowy-net/src/services/ws/ws_local.rs

@@ -1,9 +1,5 @@
-use crate::{
-    errors::UserError,
-    services::user::ws_manager::{FlowyWebSocket, FlowyWsSender},
-};
+use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WsConnectState, WsMessage, WsMessageHandler};
 use lib_infra::future::FutureResult;
-use lib_ws::{WsConnectState, WsMessage, WsMessageHandler};
 use std::sync::Arc;
 use tokio::sync::{broadcast, broadcast::Receiver};
 
@@ -24,19 +20,19 @@ impl std::default::Default for LocalWebSocket {
 }
 
 impl FlowyWebSocket for Arc<LocalWebSocket> {
-    fn start_connect(&self, _addr: String) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
+    fn start_connect(&self, _addr: String) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
 
     fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
 
-    fn reconnect(&self, _count: usize) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
+    fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
 
-    fn add_handler(&self, _handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> { Ok(()) }
+    fn add_handler(&self, _handler: Arc<dyn WsMessageHandler>) -> Result<(), FlowyError> { Ok(()) }
 
-    fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> { Ok(Arc::new(self.ws_sender.clone())) }
+    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<(), UserError> {
+    fn send(&self, msg: WsMessage) -> Result<(), FlowyError> {
         let _ = self.send(msg);
         Ok(())
     }

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

@@ -6,6 +6,7 @@ use flowy_document::{
     module::DocumentUser,
     services::ws::{DocumentWebSocket, WsDocumentManager, WsStateReceiver},
 };
+use flowy_net::services::ws::WsManager;
 use flowy_user::{
     errors::{ErrorCode, UserError},
     services::user::UserSession,
@@ -13,27 +14,23 @@ use flowy_user::{
 use lib_ws::{WsMessage, WsMessageHandler, WsModule};
 use std::{convert::TryInto, path::Path, sync::Arc};
 
-pub struct DocumentDepsResolver {
-    user_session: Arc<UserSession>,
-}
-
+pub struct DocumentDepsResolver();
 impl DocumentDepsResolver {
-    pub fn new(user_session: Arc<UserSession>) -> Self { Self { user_session } }
-
-    pub fn split_into(self) -> (Arc<dyn DocumentUser>, Arc<WsDocumentManager>) {
+    pub fn resolve(
+        ws_manager: Arc<WsManager>,
+        user_session: Arc<UserSession>,
+    ) -> (Arc<dyn DocumentUser>, Arc<WsDocumentManager>) {
         let user = Arc::new(DocumentUserImpl {
-            user: self.user_session.clone(),
+            user: user_session.clone(),
         });
 
         let sender = Arc::new(WsSenderImpl {
-            user: self.user_session.clone(),
+            ws_manager: ws_manager.clone(),
         });
-        let ws_manager = Arc::new(WsDocumentManager::new(sender));
-        let ws_handler = Arc::new(DocumentWsMessageReceiver {
-            inner: ws_manager.clone(),
-        });
-        self.user_session.add_ws_handler(ws_handler);
-        (user, ws_manager)
+        let ws_doc = Arc::new(WsDocumentManager::new(sender));
+        let ws_handler = Arc::new(DocumentWsMessageReceiver { inner: ws_doc.clone() });
+        ws_manager.add_handler(ws_handler);
+        (user, ws_doc)
     }
 }
 
@@ -69,7 +66,7 @@ impl DocumentUser for DocumentUserImpl {
 }
 
 struct WsSenderImpl {
-    user: Arc<UserSession>,
+    ws_manager: Arc<WsManager>,
 }
 
 impl DocumentWebSocket for WsSenderImpl {
@@ -79,13 +76,13 @@ impl DocumentWebSocket for WsSenderImpl {
             module: WsModule::Doc,
             data: bytes.to_vec(),
         };
-        let sender = self.user.ws_sender().map_err(internal_error)?;
+        let sender = self.ws_manager.ws_sender().map_err(internal_error)?;
         sender.send(msg).map_err(internal_error)?;
 
         Ok(())
     }
 
-    fn state_notify(&self) -> WsStateReceiver { self.user.ws_state_notifier() }
+    fn subscribe_state_changed(&self) -> WsStateReceiver { self.ws_manager.subscribe_websocket_state() }
 }
 
 struct DocumentWsMessageReceiver {

+ 45 - 18
frontend/rust-lib/flowy-sdk/src/lib.rs

@@ -1,11 +1,11 @@
 mod deps_resolve;
 // mod flowy_server;
 pub mod module;
-use crate::deps_resolve::WorkspaceDepsResolver;
+use crate::deps_resolve::{DocumentDepsResolver, WorkspaceDepsResolver};
 use backend_service::configuration::ClientServerConfiguration;
 use flowy_core::{errors::WorkspaceError, module::init_core, prelude::CoreContext};
 use flowy_document::module::FlowyDocument;
-use flowy_net::entities::NetworkType;
+use flowy_net::{entities::NetworkType, services::ws::WsManager};
 use flowy_user::{
     prelude::UserStatus,
     services::user::{UserSession, UserSessionConfig},
@@ -53,6 +53,7 @@ fn crate_log_filter(level: Option<String>) -> String {
     filters.push(format!("flowy_user={}", level));
     filters.push(format!("flowy_document={}", level));
     filters.push(format!("flowy_document_infra={}", level));
+    filters.push(format!("flowy_net={}", level));
     filters.push(format!("dart_notify={}", level));
     filters.push(format!("lib_ot={}", level));
     filters.push(format!("lib_ws={}", level));
@@ -68,6 +69,7 @@ pub struct FlowySDK {
     pub flowy_document: Arc<FlowyDocument>,
     pub core: Arc<CoreContext>,
     pub dispatcher: Arc<EventDispatcher>,
+    pub ws_manager: Arc<WsManager>,
 }
 
 impl FlowySDK {
@@ -76,49 +78,59 @@ impl FlowySDK {
         init_kv(&config.root);
         tracing::debug!("🔥 {:?}", config);
 
-        let session_cache_key = format!("{}_session_cache", &config.name);
+        let ws_manager = Arc::new(WsManager::new(config.server_config.ws_addr()));
+        let user_session = mk_user_session(&config);
+        let flowy_document = mk_document(ws_manager.clone(), user_session.clone(), &config.server_config);
+        let core_ctx = mk_core_context(user_session.clone(), flowy_document.clone(), &config.server_config);
 
-        let user_config = UserSessionConfig::new(&config.root, &config.server_config, &session_cache_key);
-        let user_session = Arc::new(UserSession::new(user_config));
-        let flowy_document = mk_document_module(user_session.clone(), &config.server_config);
-        let core = mk_core(user_session.clone(), flowy_document.clone(), &config.server_config);
-
-        let modules = mk_modules(core.clone(), user_session.clone());
+        //
+        let modules = mk_modules(ws_manager.clone(), core_ctx.clone(), user_session.clone());
         let dispatcher = Arc::new(EventDispatcher::construct(|| modules));
-        _init(&dispatcher, user_session.clone(), core.clone());
+        _init(&dispatcher, ws_manager.clone(), user_session.clone(), core_ctx.clone());
 
         Self {
             config,
             user_session,
             flowy_document,
-            core,
+            core: core_ctx,
             dispatcher,
+            ws_manager,
         }
     }
 
     pub fn dispatcher(&self) -> Arc<EventDispatcher> { self.dispatcher.clone() }
 }
 
-fn _init(dispatch: &EventDispatcher, user_session: Arc<UserSession>, core: Arc<CoreContext>) {
-    let user_status_subscribe = user_session.notifier.user_status_subscribe();
-    let network_status_subscribe = user_session.notifier.network_type_subscribe();
+fn _init(
+    dispatch: &EventDispatcher,
+    ws_manager: Arc<WsManager>,
+    user_session: Arc<UserSession>,
+    core: Arc<CoreContext>,
+) {
+    let subscribe_user_status = user_session.notifier.subscribe_user_status();
+    let subscribe_network_type = ws_manager.subscribe_network_ty();
     let cloned_core = core.clone();
 
     dispatch.spawn(async move {
         user_session.init();
-        _listen_user_status(user_status_subscribe, core.clone()).await;
+        _listen_user_status(ws_manager, subscribe_user_status, core.clone()).await;
     });
     dispatch.spawn(async move {
-        _listen_network_status(network_status_subscribe, cloned_core).await;
+        _listen_network_status(subscribe_network_type, cloned_core).await;
     });
 }
 
-async fn _listen_user_status(mut subscribe: broadcast::Receiver<UserStatus>, core: Arc<CoreContext>) {
+async fn _listen_user_status(
+    ws_manager: Arc<WsManager>,
+    mut subscribe: broadcast::Receiver<UserStatus>,
+    core: Arc<CoreContext>,
+) {
     while let Ok(status) = subscribe.recv().await {
         let result = || async {
             match status {
                 UserStatus::Login { token } => {
                     let _ = core.user_did_sign_in(&token).await?;
+                    let _ = ws_manager.start(token).await.unwrap();
                 },
                 UserStatus::Logout { .. } => {
                     core.user_did_logout().await;
@@ -164,7 +176,13 @@ fn init_log(config: &FlowySDKConfig) {
     }
 }
 
-fn mk_core(
+fn mk_user_session(config: &FlowySDKConfig) -> Arc<UserSession> {
+    let session_cache_key = format!("{}_session_cache", &config.name);
+    let user_config = UserSessionConfig::new(&config.root, &config.server_config, &session_cache_key);
+    Arc::new(UserSession::new(user_config))
+}
+
+fn mk_core_context(
     user_session: Arc<UserSession>,
     flowy_document: Arc<FlowyDocument>,
     server_config: &ClientServerConfiguration,
@@ -173,3 +191,12 @@ fn mk_core(
     let (user, database) = workspace_deps.split_into();
     init_core(user, database, flowy_document, server_config)
 }
+
+pub fn mk_document(
+    ws_manager: Arc<WsManager>,
+    user_session: Arc<UserSession>,
+    server_config: &ClientServerConfiguration,
+) -> Arc<FlowyDocument> {
+    let (user, ws_doc) = DocumentDepsResolver::resolve(ws_manager, user_session);
+    Arc::new(FlowyDocument::new(user, ws_doc, server_config))
+}

+ 7 - 11
frontend/rust-lib/flowy-sdk/src/module.rs

@@ -2,24 +2,20 @@ use crate::deps_resolve::DocumentDepsResolver;
 use backend_service::configuration::ClientServerConfiguration;
 use flowy_core::prelude::CoreContext;
 use flowy_document::module::FlowyDocument;
+use flowy_net::services::ws::WsManager;
 use flowy_user::services::user::UserSession;
 use lib_dispatch::prelude::Module;
 use std::sync::Arc;
 
-pub fn mk_modules(core: Arc<CoreContext>, user_session: Arc<UserSession>) -> Vec<Module> {
+pub fn mk_modules(ws_manager: Arc<WsManager>, core: Arc<CoreContext>, user_session: Arc<UserSession>) -> Vec<Module> {
     let user_module = mk_user_module(user_session);
-    let workspace_module = mk_core_module(core);
-    vec![user_module, workspace_module]
+    let core_module = mk_core_module(core);
+    let network_module = mk_network_module(ws_manager);
+    vec![user_module, core_module, network_module]
 }
 
 fn mk_user_module(user_session: Arc<UserSession>) -> Module { flowy_user::module::create(user_session) }
+
 fn mk_core_module(core: Arc<CoreContext>) -> Module { flowy_core::module::create(core) }
 
-pub fn mk_document_module(
-    user_session: Arc<UserSession>,
-    server_config: &ClientServerConfiguration,
-) -> Arc<FlowyDocument> {
-    let document_deps = DocumentDepsResolver::new(user_session);
-    let (user, ws_manager) = document_deps.split_into();
-    Arc::new(FlowyDocument::new(user, ws_manager, server_config))
-}
+fn mk_network_module(ws_manager: Arc<WsManager>) -> Module { flowy_net::module::create(ws_manager) }

+ 1 - 5
frontend/rust-lib/flowy-user/Cargo.toml

@@ -9,13 +9,10 @@ edition = "2018"
 flowy-user-infra = { path = "../../../shared-lib/flowy-user-infra" }
 backend-service = { path = "../../../shared-lib/backend-service" }
 flowy-derive = { path = "../../../shared-lib/flowy-derive" }
-lib-ws = { path = "../../../shared-lib/lib-ws" }
 lib-sqlite = { path = "../../../shared-lib/lib-sqlite" }
 lib-infra = { path = "../../../shared-lib/lib-infra" }
 
-
 flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration", optional = true}
-lib-ot = { path = "../../../shared-lib/lib-ot", optional = true }
 
 derive_more = {version = "0.99", features = ["display"]}
 flowy-database = { path = "../flowy-database" }
@@ -51,5 +48,4 @@ futures = "0.3.15"
 serial_test = "0.5.1"
 
 [features]
-http_server = []
-ws_mock = ["flowy-collaboration", "lib-ot"]
+http_server = []

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

@@ -1,5 +1,4 @@
 use bytes::Bytes;
-
 use flowy_derive::ProtoBuf;
 pub use flowy_user_infra::errors::ErrorCode;
 use lib_dispatch::prelude::{EventResponse, ResponseBuilder};
@@ -77,15 +76,6 @@ impl std::convert::From<::r2d2::Error> for UserError {
     fn from(error: r2d2::Error) -> Self { UserError::internal().context(error) }
 }
 
-impl std::convert::From<lib_ws::errors::WsError> for UserError {
-    fn from(error: lib_ws::errors::WsError) -> Self {
-        match error.code {
-            lib_ws::errors::ErrorCode::InternalError => UserError::internal().context(error.msg),
-            _ => UserError::internal().context(error),
-        }
-    }
-}
-
 // use diesel::result::{Error, DatabaseErrorKind};
 // use lib_sqlite::ErrorKind;
 impl std::convert::From<lib_sqlite::Error> for UserError {

+ 7 - 10
frontend/rust-lib/flowy-user/src/event.rs

@@ -5,26 +5,23 @@ use strum_macros::Display;
 #[event_err = "UserError"]
 pub enum UserEvent {
     #[event()]
-    InitUser          = 0,
+    InitUser       = 0,
 
     #[event(input = "SignInRequest", output = "UserProfile")]
-    SignIn            = 1,
+    SignIn         = 1,
 
     #[event(input = "SignUpRequest", output = "UserProfile")]
-    SignUp            = 2,
+    SignUp         = 2,
 
     #[event(passthrough)]
-    SignOut           = 3,
+    SignOut        = 3,
 
     #[event(input = "UpdateUserRequest")]
-    UpdateUser        = 4,
+    UpdateUser     = 4,
 
     #[event(output = "UserProfile")]
-    GetUserProfile    = 5,
+    GetUserProfile = 5,
 
     #[event(output = "UserProfile")]
-    CheckUser         = 6,
-
-    #[event(input = "NetworkState")]
-    UpdateNetworkType = 10,
+    CheckUser      = 6,
 }

+ 0 - 7
frontend/rust-lib/flowy-user/src/handlers/user_handler.rs

@@ -36,10 +36,3 @@ pub async fn update_user_handler(
     session.update_user(params).await?;
     Ok(())
 }
-
-#[tracing::instrument(skip(data, session))]
-pub async fn update_network_ty(data: Data<NetworkState>, session: Unit<Arc<UserSession>>) -> Result<(), UserError> {
-    let network_state = data.into_inner();
-    session.set_network_state(network_state);
-    Ok(())
-}

+ 0 - 1
frontend/rust-lib/flowy-user/src/module.rs

@@ -14,5 +14,4 @@ pub fn create(user_session: Arc<UserSession>) -> Module {
         .event(UserEvent::SignOut, sign_out)
         .event(UserEvent::UpdateUser, update_user_handler)
         .event(UserEvent::CheckUser, check_user_handler)
-        .event(UserEvent::UpdateNetworkType, update_network_ty)
 }

+ 20 - 26
frontend/rust-lib/flowy-user/src/protobuf/model/event.rs

@@ -32,7 +32,6 @@ pub enum UserEvent {
     UpdateUser = 4,
     GetUserProfile = 5,
     CheckUser = 6,
-    UpdateNetworkType = 10,
 }
 
 impl ::protobuf::ProtobufEnum for UserEvent {
@@ -49,7 +48,6 @@ impl ::protobuf::ProtobufEnum for UserEvent {
             4 => ::std::option::Option::Some(UserEvent::UpdateUser),
             5 => ::std::option::Option::Some(UserEvent::GetUserProfile),
             6 => ::std::option::Option::Some(UserEvent::CheckUser),
-            10 => ::std::option::Option::Some(UserEvent::UpdateNetworkType),
             _ => ::std::option::Option::None
         }
     }
@@ -63,7 +61,6 @@ impl ::protobuf::ProtobufEnum for UserEvent {
             UserEvent::UpdateUser,
             UserEvent::GetUserProfile,
             UserEvent::CheckUser,
-            UserEvent::UpdateNetworkType,
         ];
         values
     }
@@ -92,29 +89,26 @@ impl ::protobuf::reflect::ProtobufValue for UserEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*\x88\x01\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\x12\
-    \n\n\x06SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\
-    \x10\x03\x12\x0e\n\nUpdateUser\x10\x04\x12\x12\n\x0eGetUserProfile\x10\
-    \x05\x12\r\n\tCheckUser\x10\x06\x12\x15\n\x11UpdateNetworkType\x10\nJ\
-    \xf2\x02\n\x06\x12\x04\0\0\x0b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\
-    \x02\x05\0\x12\x04\x02\0\x0b\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x0e\
-    \n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x11\n\x0c\n\x05\x05\0\x02\0\x01\
-    \x12\x03\x03\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x0f\x10\n\
-    \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\n\x0c\n\x05\x05\0\x02\x01\
-    \x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\r\x0e\n\
-    \x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\n\x0c\n\x05\x05\0\x02\x02\
-    \x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\r\x0e\n\
-    \x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\n\x0c\n\x05\x05\0\x02\x03\
-    \x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x0e\
-    \x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x13\n\x0c\n\x05\x05\0\x02\
-    \x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\
-    \x11\x12\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x17\n\x0c\n\x05\x05\0\
-    \x02\x05\x01\x12\x03\x08\x04\x12\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\
-    \x08\x15\x16\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x12\n\x0c\n\x05\x05\
-    \0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\
-    \x10\x11\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x1b\n\x0c\n\x05\x05\0\
-    \x02\x07\x01\x12\x03\n\x04\x15\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\
-    \x18\x1ab\x06proto3\
+    \n\x0bevent.proto*q\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\x12\n\n\x06\
+    SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\x10\x03\
+    \x12\x0e\n\nUpdateUser\x10\x04\x12\x12\n\x0eGetUserProfile\x10\x05\x12\r\
+    \n\tCheckUser\x10\x06J\xc9\x02\n\x06\x12\x04\0\0\n\x01\n\x08\n\x01\x0c\
+    \x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\n\x01\n\n\n\x03\x05\0\x01\
+    \x12\x03\x02\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x11\n\x0c\n\
+    \x05\x05\0\x02\0\x01\x12\x03\x03\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x02\x12\
+    \x03\x03\x0f\x10\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\n\x0c\n\
+    \x05\x05\0\x02\x01\x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\
+    \x12\x03\x04\r\x0e\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\n\x0c\n\
+    \x05\x05\0\x02\x02\x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\x02\x02\
+    \x12\x03\x05\r\x0e\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\n\x0c\n\
+    \x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\x03\x02\
+    \x12\x03\x06\x0e\x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x13\n\x0c\
+    \n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\x05\x05\0\x02\x04\
+    \x02\x12\x03\x07\x11\x12\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x17\n\
+    \x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x12\n\x0c\n\x05\x05\0\x02\
+    \x05\x02\x12\x03\x08\x15\x16\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x12\
+    \n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\
+    \x02\x12\x03\t\x10\x11b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -8,5 +8,4 @@ enum UserEvent {
     UpdateUser = 4;
     GetUserProfile = 5;
     CheckUser = 6;
-    UpdateNetworkType = 10;
 }

+ 0 - 11
frontend/rust-lib/flowy-user/src/services/server/mod.rs

@@ -1,6 +1,5 @@
 mod server_api;
 mod server_api_mock;
-mod ws_local;
 
 pub use server_api::*;
 pub use server_api_mock::*;
@@ -10,7 +9,6 @@ pub(crate) type Server = Arc<dyn UserServerAPI + Send + Sync>;
 use crate::{
     entities::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile},
     errors::UserError,
-    services::user::ws_manager::FlowyWebSocket,
 };
 use backend_service::configuration::ClientServerConfiguration;
 use lib_infra::future::FutureResult;
@@ -31,12 +29,3 @@ pub(crate) fn construct_user_server(config: &ClientServerConfiguration) -> Arc<d
         Arc::new(UserServerMock {})
     }
 }
-
-#[cfg(feature = "ws_mock")]
-mod ws_mock;
-
-#[cfg(not(feature = "ws_mock"))]
-pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> { Arc::new(Arc::new(ws_local::LocalWebSocket::default())) }
-
-#[cfg(feature = "ws_mock")]
-pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> { Arc::new(Arc::new(ws_mock::MockWebSocket::default())) }

+ 0 - 1
frontend/rust-lib/flowy-user/src/services/user/mod.rs

@@ -3,4 +3,3 @@ pub use user_session::*;
 pub mod database;
 mod notifier;
 mod user_session;
-pub mod ws_manager;

+ 2 - 13
frontend/rust-lib/flowy-user/src/services/user/notifier.rs

@@ -4,17 +4,12 @@ use tokio::sync::{broadcast, mpsc};
 
 pub struct UserNotifier {
     user_status_notifier: broadcast::Sender<UserStatus>,
-    network_status_notifier: broadcast::Sender<NetworkType>,
 }
 
 impl std::default::Default for UserNotifier {
     fn default() -> Self {
         let (user_status_notifier, _) = broadcast::channel(10);
-        let (network_status_notifier, _) = broadcast::channel(10);
-        UserNotifier {
-            user_status_notifier,
-            network_status_notifier,
-        }
+        UserNotifier { user_status_notifier }
     }
 }
 
@@ -40,11 +35,5 @@ impl UserNotifier {
         });
     }
 
-    pub fn update_network_type(&self, ty: &NetworkType) { let _ = self.network_status_notifier.send(ty.clone()); }
-
-    pub fn user_status_subscribe(&self) -> broadcast::Receiver<UserStatus> { self.user_status_notifier.subscribe() }
-
-    pub fn network_type_subscribe(&self) -> broadcast::Receiver<NetworkType> {
-        self.network_status_notifier.subscribe()
-    }
+    pub fn subscribe_user_status(&self) -> broadcast::Receiver<UserStatus> { self.user_status_notifier.subscribe() }
 }

+ 2 - 37
frontend/rust-lib/flowy-user/src/services/user/user_session.rs

@@ -15,7 +15,6 @@ use flowy_database::{
 };
 use flowy_user_infra::entities::{SignInResponse, SignUpResponse};
 use lib_sqlite::ConnectionPool;
-use lib_ws::{WsConnectState, WsMessageHandler};
 
 use crate::{
     entities::{SignInParams, SignUpParams, UpdateUserParams, UserProfile},
@@ -23,11 +22,7 @@ use crate::{
     notify::*,
     services::{
         server::{construct_user_server, Server},
-        user::{
-            database::UserDB,
-            notifier::UserNotifier,
-            ws_manager::{FlowyWsSender, WsManager},
-        },
+        user::{database::UserDB, notifier::UserNotifier},
     },
     sql_tables::{UserTable, UserTableChangeset},
 };
@@ -55,7 +50,6 @@ pub struct UserSession {
     #[allow(dead_code)]
     server: Server,
     session: RwLock<Option<Session>>,
-    ws_manager: Arc<WsManager>,
     pub notifier: UserNotifier,
 }
 
@@ -63,14 +57,12 @@ impl UserSession {
     pub fn new(config: UserSessionConfig) -> Self {
         let db = UserDB::new(&config.root_dir);
         let server = construct_user_server(&config.server_config);
-        let ws_manager = Arc::new(WsManager::new());
         let notifier = UserNotifier::new();
         Self {
             database: db,
             config,
             server,
             session: RwLock::new(None),
-            ws_manager,
             notifier,
         }
     }
@@ -153,12 +145,7 @@ impl UserSession {
         Ok(())
     }
 
-    pub async fn init_user(&self) -> Result<(), UserError> {
-        let (_, token) = self.get_session()?.into_part();
-        let _ = self.start_ws_connection(&token).await?;
-
-        Ok(())
-    }
+    pub async fn init_user(&self) -> Result<(), UserError> { Ok(()) }
 
     pub async fn check_user(&self) -> Result<UserProfile, UserError> {
         let (user_id, token) = self.get_session()?.into_part();
@@ -191,21 +178,6 @@ impl UserSession {
     pub fn user_name(&self) -> Result<String, UserError> { Ok(self.get_session()?.name) }
 
     pub fn token(&self) -> Result<String, UserError> { Ok(self.get_session()?.token) }
-
-    pub fn add_ws_handler(&self, handler: Arc<dyn WsMessageHandler>) { let _ = self.ws_manager.add_handler(handler); }
-
-    pub fn set_network_state(&self, new_state: NetworkState) {
-        log::debug!("Network new state: {:?}", new_state);
-        self.ws_manager.update_network_type(&new_state.ty);
-        self.notifier.update_network_type(&new_state.ty);
-    }
-
-    pub fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> {
-        let sender = self.ws_manager.ws_sender()?;
-        Ok(sender)
-    }
-
-    pub fn ws_state_notifier(&self) -> broadcast::Receiver<WsConnectState> { self.ws_manager.state_subscribe() }
 }
 
 impl UserSession {
@@ -302,13 +274,6 @@ impl UserSession {
             Err(_) => false,
         }
     }
-
-    #[tracing::instrument(level = "debug", skip(self, token))]
-    pub async fn start_ws_connection(&self, token: &str) -> Result<(), UserError> {
-        let addr = format!("{}/{}", self.server.ws_addr(), token);
-        let _ = self.ws_manager.start(addr).await?;
-        Ok(())
-    }
 }
 
 pub async fn update_user(

+ 2 - 0
shared-lib/flowy-collaboration/src/lib.rs

@@ -3,3 +3,5 @@ pub mod entities;
 pub mod errors;
 pub mod protobuf;
 pub mod util;
+
+pub use lib_ot::{revision::Revision, rich_text::RichTextDelta};

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

@@ -20,6 +20,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "DocError"
         | "FFIRequest"
         | "FFIResponse"
+        | "FlowyError"
         | "SubscribeObject"
         | "NetworkState"
         | "UserError"
@@ -84,6 +85,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "ErrorCode"
         | "DocObservable"
         | "FFIStatusCode"
+        | "NetworkEvent"
         | "NetworkType"
         | "UserEvent"
         | "UserNotification"
@@ -93,6 +95,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "WsDataType"
         | "WsModule"
         | "RevType"
+        | "RevState"
         => TypeCategory::Enum,
 
         "Option" => TypeCategory::Opt,

+ 0 - 3
shared-lib/lib-ot/src/protobuf/model/mod.rs

@@ -1,8 +1,5 @@
 #![cfg_attr(rustfmt, rustfmt::skip)]
 // Auto-generated, do not edit
 
-mod cache;
-pub use cache::*;
-
 mod model;
 pub use model::*;

+ 59 - 3
shared-lib/lib-ot/src/protobuf/model/model.rs

@@ -840,6 +840,56 @@ impl ::protobuf::reflect::ProtobufValue for RevType {
     }
 }
 
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum RevState {
+    StateLocal = 0,
+    Acked = 1,
+}
+
+impl ::protobuf::ProtobufEnum for RevState {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<RevState> {
+        match value {
+            0 => ::std::option::Option::Some(RevState::StateLocal),
+            1 => ::std::option::Option::Some(RevState::Acked),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [RevState] = &[
+            RevState::StateLocal,
+            RevState::Acked,
+        ];
+        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::<RevState>("RevState", file_descriptor_proto())
+        })
+    }
+}
+
+impl ::std::marker::Copy for RevState {
+}
+
+impl ::std::default::Default for RevState {
+    fn default() -> Self {
+        RevState::StateLocal
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for RevState {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x0bmodel.proto\"\xbc\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\x18\
     \x01\x20\x01(\x03R\tbaseRevId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\x03R\
@@ -850,8 +900,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\rRevisionRange\x12\
     \x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\n\x05start\x18\x02\
     \x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\x01(\x03R\x03end*\
-    \x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\x10\x01J\xa1\
-    \x06\n\x06\x12\x04\0\0\x16\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
+    \x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\x10\x01*%\n\
+    \x08RevState\x12\x0e\n\nStateLocal\x10\0\x12\t\n\x05Acked\x10\x01J\x8b\
+    \x07\n\x06\x12\x04\0\0\x1a\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
     \x04\0\x12\x04\x02\0\n\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\
     \n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\
     \x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\
@@ -890,7 +941,12 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \0\x02\0\x01\x12\x03\x14\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\
     \x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x15\x04\x0f\n\x0c\n\x05\x05\0\
     \x02\x01\x01\x12\x03\x15\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x15\
-    \r\x0eb\x06proto3\
+    \r\x0e\n\n\n\x02\x05\x01\x12\x04\x17\0\x1a\x01\n\n\n\x03\x05\x01\x01\x12\
+    \x03\x17\x05\r\n\x0b\n\x04\x05\x01\x02\0\x12\x03\x18\x04\x13\n\x0c\n\x05\
+    \x05\x01\x02\0\x01\x12\x03\x18\x04\x0e\n\x0c\n\x05\x05\x01\x02\0\x02\x12\
+    \x03\x18\x11\x12\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x19\x04\x0e\n\x0c\n\
+    \x05\x05\x01\x02\x01\x01\x12\x03\x19\x04\t\n\x0c\n\x05\x05\x01\x02\x01\
+    \x02\x12\x03\x19\x0c\rb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 0 - 6
shared-lib/lib-ot/src/protobuf/proto/cache.proto

@@ -1,6 +0,0 @@
-syntax = "proto3";
-
-enum RevState {
-    Local = 0;
-    Acked = 1;
-}

+ 4 - 0
shared-lib/lib-ot/src/protobuf/proto/model.proto

@@ -21,3 +21,7 @@ enum RevType {
     Local = 0;
     Remote = 1;
 }
+enum RevState {
+    StateLocal = 0;
+    Acked = 1;
+}

+ 2 - 8
shared-lib/lib-ot/src/revision/model.rs

@@ -32,12 +32,6 @@ impl Revision {
     pub fn pair_rev_id(&self) -> (i64, i64) { (self.base_rev_id, self.rev_id) }
 
     pub fn is_initial(&self) -> bool { self.rev_id == 0 }
-
-    // pub fn from_pb(pb: &mut crate::protobuf::Revision) -> Self {
-    // pb.try_into().unwrap() }
-
-    // pub fn from_pb(mut pb: crate::protobuf::Revision) -> Self {
-    // Revision::try_from(&mut pb).unwrap() }
 }
 
 impl std::fmt::Debug for Revision {
@@ -160,6 +154,6 @@ pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum RevState {
-    Local = 0,
-    Acked = 1,
+    StateLocal = 0,
+    Acked      = 1,
 }