瀏覽代碼

config workspace server

appflowy 3 年之前
父節點
當前提交
498a594ad0
共有 24 個文件被更改,包括 468 次插入420 次删除
  1. 0 1
      app_flowy/lib/workspace/application/doc/doc_bloc.dart
  2. 0 2
      app_flowy/lib/workspace/presentation/app/app_header.dart
  3. 1 0
      app_flowy/lib/workspace/presentation/doc/editor_page.dart
  4. 1 3
      app_flowy/packages/flowy_infra_ui/lib/widget/error_page.dart
  5. 201 201
      app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
  6. 5 5
      backend/tests/api/helper.rs
  7. 8 0
      rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs
  8. 15 0
      rust-lib/flowy-user/src/services/server/mod.rs
  9. 11 27
      rust-lib/flowy-user/src/services/server/server_api.rs
  10. 9 4
      rust-lib/flowy-user/src/services/server/server_api_mock.rs
  11. 1 4
      rust-lib/flowy-user/src/services/user/user_session.rs
  12. 4 1
      rust-lib/flowy-workspace/Cargo.toml
  13. 5 16
      rust-lib/flowy-workspace/src/handlers/app_handler.rs
  14. 5 19
      rust-lib/flowy-workspace/src/handlers/view_handler.rs
  15. 4 6
      rust-lib/flowy-workspace/src/handlers/workspace_handler.rs
  16. 9 2
      rust-lib/flowy-workspace/src/module.rs
  17. 16 32
      rust-lib/flowy-workspace/src/services/app_controller.rs
  18. 1 0
      rust-lib/flowy-workspace/src/services/mod.rs
  19. 52 0
      rust-lib/flowy-workspace/src/services/server/mod.rs
  20. 38 0
      rust-lib/flowy-workspace/src/services/server/server_api.rs
  21. 40 0
      rust-lib/flowy-workspace/src/services/server/server_api_mock.rs
  22. 17 39
      rust-lib/flowy-workspace/src/services/view_controller.rs
  23. 24 57
      rust-lib/flowy-workspace/src/services/workspace_controller.rs
  24. 1 1
      rust-lib/rustfmt.toml

+ 0 - 1
app_flowy/lib/workspace/application/doc/doc_bloc.dart

@@ -1,7 +1,6 @@
 import 'package:app_flowy/workspace/domain/i_doc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:dartz/dartz.dart';
 
 part 'doc_bloc.freezed.dart';
 

+ 0 - 2
app_flowy/lib/workspace/presentation/app/app_header.dart

@@ -1,7 +1,5 @@
 import 'package:app_flowy/workspace/application/app/app_bloc.dart';
 import 'package:expandable/expandable.dart';
-import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_infra_ui/style_widget/text_button.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';

+ 1 - 0
app_flowy/lib/workspace/presentation/doc/editor_page.dart

@@ -7,6 +7,7 @@ import 'package:flowy_editor/flowy_editor.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
+// ignore: must_be_immutable
 class EditorPage extends StatelessWidget {
   final FocusNode _focusNode = FocusNode();
   late EditorController controller;

+ 1 - 3
app_flowy/packages/flowy_infra_ui/lib/widget/error_page.dart

@@ -6,8 +6,6 @@ class FlowyErrorPage extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Container(
-      child: Text(error),
-    );
+    return Text(error);
   }
 }

+ 201 - 201
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -1,369 +1,369 @@
-
-
 /// Auto gen code from rust ast, do not edit
 part of 'dispatch.dart';
+
 class WorkspaceEventCreateWorkspace {
-     CreateWorkspaceRequest request;
-     WorkspaceEventCreateWorkspace(this.request);
+  CreateWorkspaceRequest request;
+  WorkspaceEventCreateWorkspace(this.request);
 
-    Future<Either<Workspace, WorkspaceError>> send() {
+  Future<Either<Workspace, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.CreateWorkspace.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.CreateWorkspace.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(Workspace.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(Workspace.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventReadCurWorkspace {
-    WorkspaceEventReadCurWorkspace();
+  WorkspaceEventReadCurWorkspace();
 
-    Future<Either<Workspace, WorkspaceError>> send() {
-     final request = FFIRequest.create()
-        ..event = WorkspaceEvent.ReadCurWorkspace.toString();
+  Future<Either<Workspace, WorkspaceError>> send() {
+    final request = FFIRequest.create()
+      ..event = WorkspaceEvent.ReadCurWorkspace.toString();
 
-     return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
-        (okBytes) => left(Workspace.fromBuffer(okBytes)),
-        (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-      ));
-    }
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+              (okBytes) => left(Workspace.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventReadWorkspaces {
-     QueryWorkspaceRequest request;
-     WorkspaceEventReadWorkspaces(this.request);
+  QueryWorkspaceRequest request;
+  WorkspaceEventReadWorkspaces(this.request);
 
-    Future<Either<RepeatedWorkspace, WorkspaceError>> send() {
+  Future<Either<RepeatedWorkspace, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.ReadWorkspaces.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.ReadWorkspaces.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(RepeatedWorkspace.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(RepeatedWorkspace.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventDeleteWorkspace {
-     DeleteWorkspaceRequest request;
-     WorkspaceEventDeleteWorkspace(this.request);
+  DeleteWorkspaceRequest request;
+  WorkspaceEventDeleteWorkspace(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+  Future<Either<Unit, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.DeleteWorkspace.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.DeleteWorkspace.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventOpenWorkspace {
-     QueryWorkspaceRequest request;
-     WorkspaceEventOpenWorkspace(this.request);
+  QueryWorkspaceRequest request;
+  WorkspaceEventOpenWorkspace(this.request);
 
-    Future<Either<Workspace, WorkspaceError>> send() {
+  Future<Either<Workspace, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.OpenWorkspace.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.OpenWorkspace.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(Workspace.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(Workspace.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventCreateApp {
-     CreateAppRequest request;
-     WorkspaceEventCreateApp(this.request);
+  CreateAppRequest request;
+  WorkspaceEventCreateApp(this.request);
 
-    Future<Either<App, WorkspaceError>> send() {
+  Future<Either<App, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.CreateApp.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.CreateApp.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(App.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(App.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventDeleteApp {
-     DeleteAppRequest request;
-     WorkspaceEventDeleteApp(this.request);
+  DeleteAppRequest request;
+  WorkspaceEventDeleteApp(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+  Future<Either<Unit, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.DeleteApp.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.DeleteApp.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventReadApp {
-     QueryAppRequest request;
-     WorkspaceEventReadApp(this.request);
+  QueryAppRequest request;
+  WorkspaceEventReadApp(this.request);
 
-    Future<Either<App, WorkspaceError>> send() {
+  Future<Either<App, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.ReadApp.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.ReadApp.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(App.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(App.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventUpdateApp {
-     UpdateAppRequest request;
-     WorkspaceEventUpdateApp(this.request);
+  UpdateAppRequest request;
+  WorkspaceEventUpdateApp(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+  Future<Either<Unit, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.UpdateApp.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.UpdateApp.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventCreateView {
-     CreateViewRequest request;
-     WorkspaceEventCreateView(this.request);
+  CreateViewRequest request;
+  WorkspaceEventCreateView(this.request);
 
-    Future<Either<View, WorkspaceError>> send() {
+  Future<Either<View, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.CreateView.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.CreateView.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(View.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(View.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventReadView {
-     QueryViewRequest request;
-     WorkspaceEventReadView(this.request);
+  QueryViewRequest request;
+  WorkspaceEventReadView(this.request);
 
-    Future<Either<View, WorkspaceError>> send() {
+  Future<Either<View, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.ReadView.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.ReadView.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(View.fromBuffer(okBytes)),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(View.fromBuffer(okBytes)),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventUpdateView {
-     UpdateViewRequest request;
-     WorkspaceEventUpdateView(this.request);
+  UpdateViewRequest request;
+  WorkspaceEventUpdateView(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+  Future<Either<Unit, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.UpdateView.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.UpdateView.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class WorkspaceEventDeleteView {
-     DeleteViewRequest request;
-     WorkspaceEventDeleteView(this.request);
+  DeleteViewRequest request;
+  WorkspaceEventDeleteView(this.request);
 
-    Future<Either<Unit, WorkspaceError>> send() {
+  Future<Either<Unit, WorkspaceError>> send() {
     final request = FFIRequest.create()
-          ..event = WorkspaceEvent.DeleteView.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = WorkspaceEvent.DeleteView.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class EditorEventCreateDoc {
-     CreateDocRequest request;
-     EditorEventCreateDoc(this.request);
+  CreateDocRequest request;
+  EditorEventCreateDoc(this.request);
 
-    Future<Either<DocInfo, DocError>> send() {
+  Future<Either<DocInfo, DocError>> send() {
     final request = FFIRequest.create()
-          ..event = EditorEvent.CreateDoc.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = EditorEvent.CreateDoc.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(DocInfo.fromBuffer(okBytes)),
-           (errBytes) => right(DocError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(DocInfo.fromBuffer(okBytes)),
+              (errBytes) => right(DocError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class EditorEventUpdateDoc {
-     UpdateDocRequest request;
-     EditorEventUpdateDoc(this.request);
+  UpdateDocRequest request;
+  EditorEventUpdateDoc(this.request);
 
-    Future<Either<Unit, DocError>> send() {
+  Future<Either<Unit, DocError>> send() {
     final request = FFIRequest.create()
-          ..event = EditorEvent.UpdateDoc.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = EditorEvent.UpdateDoc.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(DocError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(DocError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class EditorEventReadDocInfo {
-     QueryDocRequest request;
-     EditorEventReadDocInfo(this.request);
+  QueryDocRequest request;
+  EditorEventReadDocInfo(this.request);
 
-    Future<Either<DocInfo, DocError>> send() {
+  Future<Either<DocInfo, DocError>> send() {
     final request = FFIRequest.create()
-          ..event = EditorEvent.ReadDocInfo.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = EditorEvent.ReadDocInfo.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(DocInfo.fromBuffer(okBytes)),
-           (errBytes) => right(DocError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(DocInfo.fromBuffer(okBytes)),
+              (errBytes) => right(DocError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class EditorEventReadDocData {
-     QueryDocDataRequest request;
-     EditorEventReadDocData(this.request);
+  QueryDocDataRequest request;
+  EditorEventReadDocData(this.request);
 
-    Future<Either<DocData, DocError>> send() {
+  Future<Either<DocData, DocError>> send() {
     final request = FFIRequest.create()
-          ..event = EditorEvent.ReadDocData.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = EditorEvent.ReadDocData.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(DocData.fromBuffer(okBytes)),
-           (errBytes) => right(DocError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(DocData.fromBuffer(okBytes)),
+              (errBytes) => right(DocError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class UserEventGetStatus {
-    UserEventGetStatus();
+  UserEventGetStatus();
 
-    Future<Either<UserDetail, UserError>> send() {
-     final request = FFIRequest.create()
-        ..event = UserEvent.GetStatus.toString();
+  Future<Either<UserDetail, UserError>> send() {
+    final request = FFIRequest.create()
+      ..event = UserEvent.GetUserProfile.toString();
 
-     return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
-        (okBytes) => left(UserDetail.fromBuffer(okBytes)),
-        (errBytes) => right(UserError.fromBuffer(errBytes)),
-      ));
-    }
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+              (okBytes) => left(UserDetail.fromBuffer(okBytes)),
+              (errBytes) => right(UserError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class UserEventSignIn {
-     SignInRequest request;
-     UserEventSignIn(this.request);
+  SignInRequest request;
+  UserEventSignIn(this.request);
 
-    Future<Either<UserDetail, UserError>> send() {
+  Future<Either<UserDetail, UserError>> send() {
     final request = FFIRequest.create()
-          ..event = UserEvent.SignIn.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = UserEvent.SignIn.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(UserDetail.fromBuffer(okBytes)),
-           (errBytes) => right(UserError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(UserDetail.fromBuffer(okBytes)),
+              (errBytes) => right(UserError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class UserEventSignUp {
-     SignUpRequest request;
-     UserEventSignUp(this.request);
+  SignUpRequest request;
+  UserEventSignUp(this.request);
 
-    Future<Either<UserDetail, UserError>> send() {
+  Future<Either<UserDetail, UserError>> send() {
     final request = FFIRequest.create()
-          ..event = UserEvent.SignUp.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = UserEvent.SignUp.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(UserDetail.fromBuffer(okBytes)),
-           (errBytes) => right(UserError.fromBuffer(errBytes)),
-        ));
-    }
+              (okBytes) => left(UserDetail.fromBuffer(okBytes)),
+              (errBytes) => right(UserError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class UserEventSignOut {
-    UserEventSignOut();
+  UserEventSignOut();
 
-    Future<Either<Unit, UserError>> send() {
-     final request = FFIRequest.create()
-        ..event = UserEvent.SignOut.toString();
+  Future<Either<Unit, UserError>> send() {
+    final request = FFIRequest.create()..event = UserEvent.SignOut.toString();
 
-     return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
-        (bytes) => left(unit),
-        (errBytes) => right(UserError.fromBuffer(errBytes)),
-      ));
-    }
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+              (bytes) => left(unit),
+              (errBytes) => right(UserError.fromBuffer(errBytes)),
+            ));
+  }
 }
 
 class UserEventUpdateUser {
-     UpdateUserRequest request;
-     UserEventUpdateUser(this.request);
+  UpdateUserRequest request;
+  UserEventUpdateUser(this.request);
 
-    Future<Either<Unit, UserError>> send() {
+  Future<Either<Unit, UserError>> send() {
     final request = FFIRequest.create()
-          ..event = UserEvent.UpdateUser.toString()
-          ..payload = requestToBytes(this.request);
+      ..event = UserEvent.UpdateUser.toString()
+      ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (bytes) => left(unit),
-           (errBytes) => right(UserError.fromBuffer(errBytes)),
-        ));
-    }
+              (bytes) => left(unit),
+              (errBytes) => right(UserError.fromBuffer(errBytes)),
+            ));
+  }
 }
-

+ 5 - 5
backend/tests/api/helper.rs

@@ -17,23 +17,23 @@ pub struct TestApp {
 impl TestApp {
     pub async fn register_user(&self, params: SignUpParams) -> SignUpResponse {
         let url = format!("{}/api/register", self.address);
-        let resp = user_sign_up(params, &url).await.unwrap();
+        let resp = user_sign_up_request(params, &url).await.unwrap();
         resp
     }
 
     pub async fn sign_in(&self, params: SignInParams) -> Result<SignInResponse, UserError> {
         let url = format!("{}/api/auth", self.address);
-        user_sign_in(params, &url).await
+        user_sign_in_request(params, &url).await
     }
 
     pub async fn sign_out(&self, token: &str) {
         let url = format!("{}/api/auth", self.address);
-        let _ = user_sign_out(token, &url).await.unwrap();
+        let _ = user_sign_out_request(token, &url).await.unwrap();
     }
 
     pub async fn get_user_detail(&self, token: &str) -> UserDetail {
         let url = format!("{}/api/user", self.address);
-        let user_detail = get_user_detail(token, &url).await.unwrap();
+        let user_detail = get_user_detail_request(token, &url).await.unwrap();
         user_detail
     }
 
@@ -43,7 +43,7 @@ impl TestApp {
         params: UpdateUserParams,
     ) -> Result<(), UserError> {
         let url = format!("{}/api/user", self.address);
-        update_user_detail(token, params, &url).await
+        update_user_detail_request(token, params, &url).await
     }
 
     pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> Workspace {

+ 8 - 0
rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs

@@ -19,6 +19,14 @@ impl WorkspaceUser for WorkspaceUserImpl {
                 .build()
         })
     }
+
+    fn token(&self) -> Result<String, WorkspaceError> {
+        self.user_session.token().map_err(|e| {
+            ErrorBuilder::new(ErrorCode::UserInternalError)
+                .error(e)
+                .build()
+        })
+    }
 }
 
 pub struct WorkspaceDatabaseImpl {

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

@@ -4,6 +4,21 @@ pub use server_api::*;
 pub use server_api_mock::*;
 
 use std::sync::Arc;
+pub(crate) type Server = Arc<dyn UserServerAPI + Send + Sync>;
+use crate::{
+    entities::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserDetail},
+    errors::UserError,
+};
+use flowy_infra::future::ResultFuture;
+
+pub trait UserServerAPI {
+    fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError>;
+    fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError>;
+    fn sign_out(&self, token: &str) -> ResultFuture<(), UserError>;
+    fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError>;
+    fn get_user_detail(&self, token: &str) -> ResultFuture<UserDetail, UserError>;
+}
+
 pub(crate) fn construct_user_server() -> Arc<dyn UserServerAPI + Send + Sync> {
     if cfg!(feature = "http_server") {
         Arc::new(UserServer {})

+ 11 - 27
rust-lib/flowy-user/src/services/server/server_api.rs

@@ -3,21 +3,11 @@ use crate::{
     errors::UserError,
 };
 
-use crate::entities::UpdateUserParams;
+use crate::{entities::UpdateUserParams, services::server::UserServerAPI};
 use flowy_infra::future::ResultFuture;
 use flowy_net::{config::*, request::HttpRequestBuilder};
 use std::sync::Arc;
 
-pub type Server = Arc<dyn UserServerAPI + Send + Sync>;
-
-pub trait UserServerAPI {
-    fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError>;
-    fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError>;
-    fn sign_out(&self, token: &str) -> ResultFuture<(), UserError>;
-    fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError>;
-    fn get_user_detail(&self, token: &str) -> ResultFuture<UserDetail, UserError>;
-}
-
 pub struct UserServer {}
 impl UserServer {
     pub fn new() -> Self { Self {} }
@@ -25,35 +15,33 @@ impl UserServer {
 
 impl UserServerAPI for UserServer {
     fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
-        ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await })
+        ResultFuture::new(async move { user_sign_up_request(params, SIGN_UP_URL.as_ref()).await })
     }
 
     fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
-        ResultFuture::new(async move { user_sign_in(params, SIGN_IN_URL.as_ref()).await })
+        ResultFuture::new(async move { user_sign_in_request(params, SIGN_IN_URL.as_ref()).await })
     }
 
     fn sign_out(&self, token: &str) -> ResultFuture<(), UserError> {
         let token = token.to_owned();
         ResultFuture::new(async move {
-            let _ = user_sign_out(&token, SIGN_OUT_URL.as_ref()).await;
+            let _ = user_sign_out_request(&token, SIGN_OUT_URL.as_ref()).await;
             Ok(())
         })
     }
 
     fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError> {
         let token = token.to_owned();
-        ResultFuture::new(async move {
-            update_user_detail(&token, params, USER_PROFILE_URL.as_ref()).await
-        })
+        ResultFuture::new(async move { update_user_detail_request(&token, params, USER_PROFILE_URL.as_ref()).await })
     }
 
     fn get_user_detail(&self, token: &str) -> ResultFuture<UserDetail, UserError> {
         let token = token.to_owned();
-        ResultFuture::new(async move { get_user_detail(&token, USER_PROFILE_URL.as_ref()).await })
+        ResultFuture::new(async move { get_user_detail_request(&token, USER_PROFILE_URL.as_ref()).await })
     }
 }
 
-pub async fn user_sign_up(params: SignUpParams, url: &str) -> Result<SignUpResponse, UserError> {
+pub async fn user_sign_up_request(params: SignUpParams, url: &str) -> Result<SignUpResponse, UserError> {
     let response = HttpRequestBuilder::post(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -63,7 +51,7 @@ pub async fn user_sign_up(params: SignUpParams, url: &str) -> Result<SignUpRespo
     Ok(response)
 }
 
-pub async fn user_sign_in(params: SignInParams, url: &str) -> Result<SignInResponse, UserError> {
+pub async fn user_sign_in_request(params: SignInParams, url: &str) -> Result<SignInResponse, UserError> {
     let response = HttpRequestBuilder::post(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -73,7 +61,7 @@ pub async fn user_sign_in(params: SignInParams, url: &str) -> Result<SignInRespo
     Ok(response)
 }
 
-pub async fn user_sign_out(token: &str, url: &str) -> Result<(), UserError> {
+pub async fn user_sign_out_request(token: &str, url: &str) -> Result<(), UserError> {
     let _ = HttpRequestBuilder::delete(&url.to_owned())
         .header(HEADER_TOKEN, token)
         .send()
@@ -81,7 +69,7 @@ pub async fn user_sign_out(token: &str, url: &str) -> Result<(), UserError> {
     Ok(())
 }
 
-pub async fn get_user_detail(token: &str, url: &str) -> Result<UserDetail, UserError> {
+pub async fn get_user_detail_request(token: &str, url: &str) -> Result<UserDetail, UserError> {
     let user_detail = HttpRequestBuilder::get(&url.to_owned())
         .header(HEADER_TOKEN, token)
         .send()
@@ -91,11 +79,7 @@ pub async fn get_user_detail(token: &str, url: &str) -> Result<UserDetail, UserE
     Ok(user_detail)
 }
 
-pub async fn update_user_detail(
-    token: &str,
-    params: UpdateUserParams,
-    url: &str,
-) -> Result<(), UserError> {
+pub async fn update_user_detail_request(token: &str, params: UpdateUserParams, url: &str) -> Result<(), UserError> {
     let _ = HttpRequestBuilder::patch(&url.to_owned())
         .header(HEADER_TOKEN, token)
         .protobuf(params)?

+ 9 - 4
rust-lib/flowy-user/src/services/server/server_api_mock.rs

@@ -1,11 +1,16 @@
 use crate::{
-    entities::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UserDetail},
+    entities::{
+        SignInParams,
+        SignInResponse,
+        SignUpParams,
+        SignUpResponse,
+        UpdateUserParams,
+        UserDetail,
+    },
     errors::{ErrorBuilder, ErrorCode, UserError},
-    services::user::UserServerAPI,
 };
 
-use crate::entities::UpdateUserParams;
-
+use crate::services::server::UserServerAPI;
 use flowy_infra::{future::ResultFuture, uuid};
 
 pub struct UserServerMock {}

+ 1 - 4
rust-lib/flowy-user/src/services/user/user_session.rs

@@ -155,10 +155,7 @@ impl UserSession {
 
     pub fn user_id(&self) -> Result<String, UserError> { Ok(self.get_session()?.user_id) }
 
-    // pub fn user_token(&self) -> Result<String, UserError> {
-    //     let user_detail = self.user_detail()?;
-    //     Ok(user_detail.token)
-    // }
+    pub fn token(&self) -> Result<String, UserError> { Ok(self.get_session()?.token) }
 }
 
 impl UserSession {

+ 4 - 1
rust-lib/flowy-workspace/Cargo.toml

@@ -32,4 +32,7 @@ tracing = { version = "0.1", features = ["log"] }
 bytes = { version = "1.0" }
 [dev-dependencies]
 flowy-test = { path = "../flowy-test" }
-serial_test = "0.5.1"
+serial_test = "0.5.1"
+
+[features]
+http_server = []

+ 5 - 16
rust-lib/flowy-workspace/src/handlers/app_handler.rs

@@ -20,45 +20,34 @@ use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(name = "create_app", skip(data, controller))]
-pub async fn create_app(
-    data: Data<CreateAppRequest>,
-    controller: Unit<Arc<AppController>>,
-) -> DataResult<App, WorkspaceError> {
+pub(crate) async fn create_app(data: Data<CreateAppRequest>, controller: Unit<Arc<AppController>>) -> DataResult<App, WorkspaceError> {
     let params: CreateAppParams = data.into_inner().try_into()?;
     let detail = controller.create_app(params)?;
     data_result(detail)
 }
 
 #[tracing::instrument(name = "delete_app", skip(data, controller))]
-pub async fn delete_app(
-    data: Data<DeleteAppRequest>,
-    controller: Unit<Arc<AppController>>,
-) -> Result<(), WorkspaceError> {
+pub(crate) async fn delete_app(data: Data<DeleteAppRequest>, controller: Unit<Arc<AppController>>) -> Result<(), WorkspaceError> {
     let params: DeleteAppParams = data.into_inner().try_into()?;
     let _ = controller.delete_app(&params.app_id).await?;
     Ok(())
 }
 
 #[tracing::instrument(name = "update_app", skip(data, controller))]
-pub async fn update_app(
-    data: Data<UpdateAppRequest>,
-    controller: Unit<Arc<AppController>>,
-) -> Result<(), WorkspaceError> {
+pub(crate) async fn update_app(data: Data<UpdateAppRequest>, controller: Unit<Arc<AppController>>) -> Result<(), WorkspaceError> {
     let params: UpdateAppParams = data.into_inner().try_into()?;
     let _ = controller.update_app(params).await?;
     Ok(())
 }
 
 #[tracing::instrument(name = "read_app", skip(data, app_controller, view_controller))]
-pub async fn read_app(
+pub(crate) async fn read_app(
     data: Data<QueryAppRequest>,
     app_controller: Unit<Arc<AppController>>,
     view_controller: Unit<Arc<ViewController>>,
 ) -> DataResult<App, WorkspaceError> {
     let params: QueryAppParams = data.into_inner().try_into()?;
-    let mut app = app_controller
-        .read_app(&params.app_id, params.is_trash)
-        .await?;
+    let mut app = app_controller.read_app(&params.app_id, params.is_trash).await?;
 
     // The View's belonging is the view indexed by the belong_to_id for now
     if params.read_belongings {

+ 5 - 19
rust-lib/flowy-workspace/src/handlers/view_handler.rs

@@ -18,24 +18,16 @@ use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(name = "create_view", skip(data, controller))]
-pub async fn create_view(
-    data: Data<CreateViewRequest>,
-    controller: Unit<Arc<ViewController>>,
-) -> DataResult<View, WorkspaceError> {
+pub(crate) async fn create_view(data: Data<CreateViewRequest>, controller: Unit<Arc<ViewController>>) -> DataResult<View, WorkspaceError> {
     let params: CreateViewParams = data.into_inner().try_into()?;
     let view = controller.create_view(params).await?;
     data_result(view)
 }
 
 #[tracing::instrument(name = "read_view", skip(data, controller))]
-pub async fn read_view(
-    data: Data<QueryViewRequest>,
-    controller: Unit<Arc<ViewController>>,
-) -> DataResult<View, WorkspaceError> {
+pub(crate) async fn read_view(data: Data<QueryViewRequest>, controller: Unit<Arc<ViewController>>) -> DataResult<View, WorkspaceError> {
     let params: QueryViewParams = data.into_inner().try_into()?;
-    let mut view = controller
-        .read_view(&params.view_id, params.is_trash)
-        .await?;
+    let mut view = controller.read_view(&params.view_id, params.is_trash).await?;
 
     if params.read_belongings {
         let views = controller.read_views_belong_to(&params.view_id).await?;
@@ -46,10 +38,7 @@ pub async fn read_view(
 }
 
 #[tracing::instrument(name = "update_view", skip(data, controller))]
-pub async fn update_view(
-    data: Data<UpdateViewRequest>,
-    controller: Unit<Arc<ViewController>>,
-) -> Result<(), WorkspaceError> {
+pub(crate) async fn update_view(data: Data<UpdateViewRequest>, controller: Unit<Arc<ViewController>>) -> Result<(), WorkspaceError> {
     let params: UpdateViewParams = data.into_inner().try_into()?;
     let _ = controller.update_view(params).await?;
 
@@ -57,10 +46,7 @@ pub async fn update_view(
 }
 
 #[tracing::instrument(name = "delete_view", skip(data, controller))]
-pub async fn delete_view(
-    data: Data<DeleteViewRequest>,
-    controller: Unit<Arc<ViewController>>,
-) -> Result<(), WorkspaceError> {
+pub(crate) async fn delete_view(data: Data<DeleteViewRequest>, controller: Unit<Arc<ViewController>>) -> Result<(), WorkspaceError> {
     let params: DeleteViewParams = data.into_inner().try_into()?;
     let _ = controller.delete_view(&params.view_id).await?;
     Ok(())

+ 4 - 6
rust-lib/flowy-workspace/src/handlers/workspace_handler.rs

@@ -7,7 +7,7 @@ use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(name = "create_workspace", skip(data, controller))]
-pub async fn create_workspace(
+pub(crate) async fn create_workspace(
     data: Data<CreateWorkspaceRequest>,
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<Workspace, WorkspaceError> {
@@ -18,15 +18,13 @@ pub async fn create_workspace(
 }
 
 #[tracing::instrument(name = "read_cur_workspace", skip(controller))]
-pub async fn read_cur_workspace(
-    controller: Unit<Arc<WorkspaceController>>,
-) -> DataResult<Workspace, WorkspaceError> {
+pub(crate) async fn read_cur_workspace(controller: Unit<Arc<WorkspaceController>>) -> DataResult<Workspace, WorkspaceError> {
     let workspace = controller.read_cur_workspace().await?;
     data_result(workspace)
 }
 
 #[tracing::instrument(name = "read_workspace", skip(data, controller))]
-pub async fn read_workspaces(
+pub(crate) async fn read_workspaces(
     data: Data<QueryWorkspaceRequest>,
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<RepeatedWorkspace, WorkspaceError> {
@@ -36,7 +34,7 @@ pub async fn read_workspaces(
 }
 
 #[tracing::instrument(name = "open_workspace", skip(data, controller))]
-pub async fn open_workspace(
+pub(crate) async fn open_workspace(
     data: Data<QueryWorkspaceRequest>,
     controller: Unit<Arc<WorkspaceController>>,
 ) -> DataResult<Workspace, WorkspaceError> {

+ 9 - 2
rust-lib/flowy-workspace/src/module.rs

@@ -7,13 +7,17 @@ use crate::{
 };
 use flowy_database::DBConnection;
 
-use crate::{handlers::*, services::ViewController};
+use crate::{
+    handlers::*,
+    services::{server::construct_workspace_server, ViewController},
+};
 use std::sync::Arc;
 
 pub trait WorkspaceDeps: WorkspaceUser + WorkspaceDatabase {}
 
 pub trait WorkspaceUser: Send + Sync {
     fn user_id(&self) -> Result<String, WorkspaceError>;
+    fn token(&self) -> Result<String, WorkspaceError>;
     // fn set_cur_workspace_id(&self, id: &str) -> DispatchFuture<Result<(),
     // WorkspaceError>>; fn get_cur_workspace(&self) ->
     // DispatchFuture<Result<CurrentWorkspace, WorkspaceError>>;
@@ -24,18 +28,21 @@ pub trait WorkspaceDatabase: Send + Sync {
 }
 
 pub fn create(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>) -> Module {
-    let view_controller = Arc::new(ViewController::new(database.clone()));
+    let server = construct_workspace_server();
+    let view_controller = Arc::new(ViewController::new(database.clone(), server.clone()));
 
     let app_controller = Arc::new(AppController::new(
         user.clone(),
         database.clone(),
         view_controller.clone(),
+        server.clone(),
     ));
 
     let workspace_controller = Arc::new(WorkspaceController::new(
         user.clone(),
         database.clone(),
         app_controller.clone(),
+        server.clone(),
     ));
 
     let mut module = Module::new()

+ 16 - 32
rust-lib/flowy-workspace/src/services/app_controller.rs

@@ -3,35 +3,38 @@ use crate::{
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
     observable::*,
-    services::ViewController,
+    services::{server::Server, ViewController},
     sql_tables::app::{AppTable, AppTableChangeset, AppTableSql},
 };
 use flowy_dispatch::prelude::DispatchFuture;
 use flowy_net::request::HttpRequestBuilder;
 use std::sync::Arc;
 
-pub struct AppController {
+pub(crate) struct AppController {
     user: Arc<dyn WorkspaceUser>,
     sql: Arc<AppTableSql>,
     #[allow(dead_code)]
     view_controller: Arc<ViewController>,
+    server: Server,
 }
 
 impl AppController {
-    pub fn new(
+    pub(crate) fn new(
         user: Arc<dyn WorkspaceUser>,
         database: Arc<dyn WorkspaceDatabase>,
         view_controller: Arc<ViewController>,
+        server: Server,
     ) -> Self {
         let sql = Arc::new(AppTableSql { database });
         Self {
             user,
             sql,
             view_controller,
+            server,
         }
     }
 
-    pub fn create_app(&self, mut params: CreateAppParams) -> Result<App, WorkspaceError> {
+    pub(crate) fn create_app(&self, mut params: CreateAppParams) -> Result<App, WorkspaceError> {
         let user_id = self.user.user_id()?;
         params.user_id = user_id;
 
@@ -45,18 +48,18 @@ impl AppController {
         Ok(app)
     }
 
-    pub async fn read_app(&self, app_id: &str, is_trash: bool) -> Result<App, WorkspaceError> {
+    pub(crate) async fn read_app(&self, app_id: &str, is_trash: bool) -> Result<App, WorkspaceError> {
         let app_table = self.async_read_app(&app_id, is_trash).await?;
         Ok(app_table.into())
     }
 
-    pub async fn delete_app(&self, app_id: &str) -> Result<(), WorkspaceError> {
+    pub(crate) async fn delete_app(&self, app_id: &str) -> Result<(), WorkspaceError> {
         let app = self.sql.delete_app(app_id)?;
         send_observable(&app.workspace_id, WorkspaceObservable::WorkspaceDeleteApp);
         Ok(())
     }
 
-    pub async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> {
+    pub(crate) async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> {
         let changeset = AppTableChangeset::new(params);
         let app_id = changeset.id.clone();
         let _ = self.sql.update_app(changeset)?;
@@ -64,11 +67,7 @@ impl AppController {
         Ok(())
     }
 
-    fn async_read_app(
-        &self,
-        app_id: &str,
-        is_trash: bool,
-    ) -> DispatchFuture<Result<AppTable, WorkspaceError>> {
+    fn async_read_app(&self, app_id: &str, is_trash: bool) -> DispatchFuture<Result<AppTable, WorkspaceError>> {
         let sql = self.sql.clone();
         let app_id = app_id.to_owned();
         DispatchFuture {
@@ -91,20 +90,11 @@ pub async fn create_app_request(params: CreateAppParams, url: &str) -> Result<Ap
     Ok(app)
 }
 
-pub async fn read_app_request(
-    params: QueryAppParams,
-    url: &str,
-) -> Result<Option<App>, WorkspaceError> {
-    let result = HttpRequestBuilder::get(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await;
+pub async fn read_app_request(params: QueryAppParams, url: &str) -> Result<Option<App>, WorkspaceError> {
+    let result = HttpRequestBuilder::get(&url.to_owned()).protobuf(params)?.send().await;
 
     match result {
-        Ok(builder) => {
-            let app = builder.response::<App>().await?;
-            Ok(Some(app))
-        },
+        Ok(builder) => Ok(Some(builder.response::<App>().await?)),
         Err(e) => {
             if e.is_not_found() {
                 Ok(None)
@@ -116,17 +106,11 @@ pub async fn read_app_request(
 }
 
 pub async fn update_app_request(params: UpdateAppParams, url: &str) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::patch(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await?;
+    let _ = HttpRequestBuilder::patch(&url.to_owned()).protobuf(params)?.send().await?;
     Ok(())
 }
 
 pub async fn delete_app_request(params: DeleteAppParams, url: &str) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::delete(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await?;
+    let _ = HttpRequestBuilder::delete(&url.to_owned()).protobuf(params)?.send().await?;
     Ok(())
 }

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

@@ -5,5 +5,6 @@ pub use workspace_controller::*;
 mod app_controller;
 mod database;
 mod helper;
+pub(crate) mod server;
 mod view_controller;
 mod workspace_controller;

+ 52 - 0
rust-lib/flowy-workspace/src/services/server/mod.rs

@@ -0,0 +1,52 @@
+mod server_api;
+mod server_api_mock;
+pub use server_api::*;
+// TODO: exclude mock files in production
+pub use server_api_mock::*;
+
+use crate::{
+    entities::{
+        app::{CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+        view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams},
+        workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams},
+    },
+    errors::WorkspaceError,
+};
+use flowy_infra::future::ResultFuture;
+use std::sync::Arc;
+
+pub(crate) type Server = Arc<dyn WorkspaceServerAPI + Send + Sync>;
+
+pub trait WorkspaceServerAPI {
+    // Workspace
+    fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<(), WorkspaceError>;
+
+    fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture<RepeatedWorkspace, WorkspaceError>;
+
+    fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError>;
+
+    fn delete_workspace(&self, token: &str, params: DeleteWorkspaceParams) -> ResultFuture<(), WorkspaceError>;
+
+    // View
+    fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture<(), WorkspaceError>;
+
+    fn read_view(&self, token: &str, params: QueryViewParams) -> ResultFuture<(), WorkspaceError>;
+
+    fn delete_view(&self, token: &str, params: DeleteViewParams) -> ResultFuture<(), WorkspaceError>;
+
+    fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError>;
+
+    // App
+    fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<(), WorkspaceError>;
+    fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture<(), WorkspaceError>;
+    fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>;
+    fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError>;
+}
+
+pub(crate) fn construct_workspace_server() -> Arc<dyn WorkspaceServerAPI + Send + Sync> {
+    if cfg!(feature = "http_server") {
+        Arc::new(WorkspaceServer {})
+    } else {
+        Arc::new(WorkspaceServerMock {})
+    }
+}

+ 38 - 0
rust-lib/flowy-workspace/src/services/server/server_api.rs

@@ -0,0 +1,38 @@
+use crate::{
+    entities::{
+        app::{CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+        view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams},
+        workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams},
+    },
+    errors::WorkspaceError,
+    services::server::WorkspaceServerAPI,
+};
+use flowy_infra::future::ResultFuture;
+
+pub struct WorkspaceServer {}
+
+impl WorkspaceServerAPI for WorkspaceServer {
+    fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture<RepeatedWorkspace, WorkspaceError> { unimplemented!() }
+
+    fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_workspace(&self, token: &str, params: DeleteWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_view(&self, token: &str, params: QueryViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_view(&self, token: &str, params: DeleteViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+}

+ 40 - 0
rust-lib/flowy-workspace/src/services/server/server_api_mock.rs

@@ -0,0 +1,40 @@
+use crate::{
+    entities::{
+        app::{CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+        view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams},
+        workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams},
+    },
+    errors::WorkspaceError,
+    services::server::WorkspaceServerAPI,
+};
+use flowy_infra::future::ResultFuture;
+
+pub struct WorkspaceServerMock {}
+
+impl WorkspaceServerAPI for WorkspaceServerMock {
+    fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
+        unimplemented!()
+    }
+
+    fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_workspace(&self, token: &str, params: DeleteWorkspaceParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_view(&self, token: &str, params: QueryViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_view(&self, token: &str, params: DeleteViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+
+    fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError> { unimplemented!() }
+}

+ 17 - 39
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -3,22 +3,24 @@ use crate::{
     errors::WorkspaceError,
     module::WorkspaceDatabase,
     observable::{send_observable, WorkspaceObservable},
+    services::server::Server,
     sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
 };
 use flowy_net::request::HttpRequestBuilder;
 use std::sync::Arc;
 
-pub struct ViewController {
+pub(crate) struct ViewController {
     sql: Arc<ViewTableSql>,
+    server: Server,
 }
 
 impl ViewController {
-    pub fn new(database: Arc<dyn WorkspaceDatabase>) -> Self {
+    pub(crate) fn new(database: Arc<dyn WorkspaceDatabase>, server: Server) -> Self {
         let sql = Arc::new(ViewTableSql { database });
-        Self { sql }
+        Self { sql, server }
     }
 
-    pub async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
+    pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
         let view_table = ViewTable::new(params);
         let view: View = view_table.clone().into();
         let _ = self.sql.create_view(view_table)?;
@@ -27,22 +29,19 @@ impl ViewController {
         Ok(view)
     }
 
-    pub async fn read_view(&self, view_id: &str, is_trash: bool) -> Result<View, WorkspaceError> {
+    pub(crate) async fn read_view(&self, view_id: &str, is_trash: bool) -> Result<View, WorkspaceError> {
         let view_table = self.sql.read_view(view_id, is_trash)?;
         let view: View = view_table.into();
         Ok(view)
     }
 
-    pub async fn delete_view(&self, view_id: &str) -> Result<(), WorkspaceError> {
+    pub(crate) async fn delete_view(&self, view_id: &str) -> Result<(), WorkspaceError> {
         let view = self.sql.delete_view(view_id)?;
         send_observable(&view.belong_to_id, WorkspaceObservable::AppDeleteView);
         Ok(())
     }
 
-    pub async fn read_views_belong_to(
-        &self,
-        belong_to_id: &str,
-    ) -> Result<Vec<View>, WorkspaceError> {
+    pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<Vec<View>, WorkspaceError> {
         let views = self
             .sql
             .read_views_belong_to(belong_to_id)?
@@ -53,7 +52,7 @@ impl ViewController {
         Ok(views)
     }
 
-    pub async fn update_view(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
+    pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
         let changeset = ViewTableChangeset::new(params);
         let view_id = changeset.id.clone();
         let _ = self.sql.update_view(changeset)?;
@@ -63,10 +62,7 @@ impl ViewController {
     }
 }
 
-pub async fn create_view_request(
-    params: CreateViewParams,
-    url: &str,
-) -> Result<View, WorkspaceError> {
+pub async fn create_view_request(params: CreateViewParams, url: &str) -> Result<View, WorkspaceError> {
     let view = HttpRequestBuilder::post(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -76,14 +72,8 @@ pub async fn create_view_request(
     Ok(view)
 }
 
-pub async fn read_view_request(
-    params: QueryViewParams,
-    url: &str,
-) -> Result<Option<View>, WorkspaceError> {
-    let result = HttpRequestBuilder::get(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await;
+pub async fn read_view_request(params: QueryViewParams, url: &str) -> Result<Option<View>, WorkspaceError> {
+    let result = HttpRequestBuilder::get(&url.to_owned()).protobuf(params)?.send().await;
 
     match result {
         Ok(builder) => {
@@ -100,24 +90,12 @@ pub async fn read_view_request(
     }
 }
 
-pub async fn update_view_request(
-    params: UpdateViewParams,
-    url: &str,
-) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::patch(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await?;
+pub async fn update_view_request(params: UpdateViewParams, url: &str) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::patch(&url.to_owned()).protobuf(params)?.send().await?;
     Ok(())
 }
 
-pub async fn delete_view_request(
-    params: DeleteViewParams,
-    url: &str,
-) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::delete(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await?;
+pub async fn delete_view_request(params: DeleteViewParams, url: &str) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::delete(&url.to_owned()).protobuf(params)?.send().await?;
     Ok(())
 }

+ 24 - 57
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -3,7 +3,7 @@ use crate::{
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
     observable::{send_observable, WorkspaceObservable},
-    services::AppController,
+    services::{server::Server, AppController},
     sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset},
 };
 use flowy_dispatch::prelude::DispatchFuture;
@@ -11,30 +11,30 @@ use flowy_infra::kv::KVStore;
 use flowy_net::request::HttpRequestBuilder;
 use std::sync::Arc;
 
-pub struct WorkspaceController {
+pub(crate) struct WorkspaceController {
     pub user: Arc<dyn WorkspaceUser>,
     pub sql: Arc<WorkspaceSql>,
     pub app_controller: Arc<AppController>,
+    server: Server,
 }
 
 impl WorkspaceController {
-    pub fn new(
+    pub(crate) fn new(
         user: Arc<dyn WorkspaceUser>,
         database: Arc<dyn WorkspaceDatabase>,
         app_controller: Arc<AppController>,
+        server: Server,
     ) -> Self {
         let sql = Arc::new(WorkspaceSql { database });
         Self {
             user,
             sql,
             app_controller,
+            server,
         }
     }
 
-    pub async fn create_workspace(
-        &self,
-        params: CreateWorkspaceParams,
-    ) -> Result<Workspace, WorkspaceError> {
+    pub(crate) async fn create_workspace(&self, params: CreateWorkspaceParams) -> Result<Workspace, WorkspaceError> {
         let user_id = params.user_id.clone();
         // TODO: server
 
@@ -45,7 +45,7 @@ impl WorkspaceController {
         Ok(workspace)
     }
 
-    pub fn update_workspace(&self, params: UpdateWorkspaceParams) -> Result<(), WorkspaceError> {
+    pub(crate) fn update_workspace(&self, params: UpdateWorkspaceParams) -> Result<(), WorkspaceError> {
         let changeset = WorkspaceTableChangeset::new(params);
         let workspace_id = changeset.id.clone();
         let _ = self.sql.update_workspace(changeset)?;
@@ -54,18 +54,16 @@ impl WorkspaceController {
         Ok(())
     }
 
-    pub fn delete_workspace(&self, workspace_id: &str) -> Result<(), WorkspaceError> {
+    pub(crate) fn delete_workspace(&self, workspace_id: &str) -> Result<(), WorkspaceError> {
         let user_id = self.user.user_id()?;
         let _ = self.sql.delete_workspace(workspace_id)?;
         send_observable(&user_id, WorkspaceObservable::UserDeleteWorkspace);
         Ok(())
     }
 
-    pub async fn open_workspace(&self, workspace_id: &str) -> Result<Workspace, WorkspaceError> {
+    pub(crate) async fn open_workspace(&self, workspace_id: &str) -> Result<Workspace, WorkspaceError> {
         let user_id = self.user.user_id()?;
-        let result = self
-            .read_workspace_table(Some(workspace_id.to_owned()), user_id)
-            .await?;
+        let result = self.read_workspace_table(Some(workspace_id.to_owned()), user_id).await?;
 
         match result.first() {
             None => Err(ErrorBuilder::new(ErrorCode::RecordNotFound).build()),
@@ -77,10 +75,7 @@ impl WorkspaceController {
         }
     }
 
-    pub async fn read_workspaces(
-        &self,
-        workspace_id: Option<String>,
-    ) -> Result<RepeatedWorkspace, WorkspaceError> {
+    pub(crate) async fn read_workspaces(&self, workspace_id: Option<String>) -> Result<RepeatedWorkspace, WorkspaceError> {
         let user_id = self.user.user_id()?;
         let workspace_tables = self.read_workspace_table(workspace_id, user_id).await?;
         let mut workspaces = vec![];
@@ -94,7 +89,7 @@ impl WorkspaceController {
         Ok(RepeatedWorkspace { items: workspaces })
     }
 
-    pub async fn read_cur_workspace(&self) -> Result<Workspace, WorkspaceError> {
+    pub(crate) async fn read_cur_workspace(&self) -> Result<Workspace, WorkspaceError> {
         let workspace_id = get_current_workspace()?;
         let mut repeated_workspace = self.read_workspaces(Some(workspace_id.clone())).await?;
 
@@ -103,21 +98,17 @@ impl WorkspaceController {
         }
 
         debug_assert_eq!(repeated_workspace.len(), 1);
-        let workspace = repeated_workspace
-            .drain(..1)
-            .collect::<Vec<Workspace>>()
-            .pop()
-            .unwrap();
+        let workspace = repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop().unwrap();
         Ok(workspace)
     }
 
-    pub async fn read_cur_apps(&self) -> Result<Vec<App>, WorkspaceError> {
+    pub(crate) async fn read_cur_apps(&self) -> Result<Vec<App>, WorkspaceError> {
         let workspace_id = get_current_workspace()?;
         let apps = self.read_apps(&workspace_id).await?;
         Ok(apps)
     }
 
-    pub async fn read_apps(&self, workspace_id: &str) -> Result<Vec<App>, WorkspaceError> {
+    pub(crate) async fn read_apps(&self, workspace_id: &str) -> Result<Vec<App>, WorkspaceError> {
         let apps = self
             .sql
             .read_apps_belong_to_workspace(workspace_id)?
@@ -147,9 +138,7 @@ impl WorkspaceController {
 
 const CURRENT_WORKSPACE_ID: &str = "current_workspace_id";
 
-fn set_current_workspace(workspace: &str) {
-    KVStore::set_str(CURRENT_WORKSPACE_ID, workspace.to_owned());
-}
+fn set_current_workspace(workspace: &str) { KVStore::set_str(CURRENT_WORKSPACE_ID, workspace.to_owned()); }
 
 fn get_current_workspace() -> Result<String, WorkspaceError> {
     match KVStore::get_str(CURRENT_WORKSPACE_ID) {
@@ -158,10 +147,7 @@ fn get_current_workspace() -> Result<String, WorkspaceError> {
     }
 }
 
-pub async fn create_workspace_request(
-    params: CreateWorkspaceParams,
-    url: &str,
-) -> Result<Workspace, WorkspaceError> {
+pub async fn create_workspace_request(params: CreateWorkspaceParams, url: &str) -> Result<Workspace, WorkspaceError> {
     let workspace = HttpRequestBuilder::post(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -171,10 +157,7 @@ pub async fn create_workspace_request(
     Ok(workspace)
 }
 
-pub async fn read_workspaces_request(
-    params: QueryWorkspaceParams,
-    url: &str,
-) -> Result<RepeatedWorkspace, WorkspaceError> {
+pub async fn read_workspaces_request(params: QueryWorkspaceParams, url: &str) -> Result<RepeatedWorkspace, WorkspaceError> {
     let result = HttpRequestBuilder::get(&url.to_owned())
         .protobuf(params)?
         .send()
@@ -188,33 +171,17 @@ pub async fn read_workspaces_request(
     }
 }
 
-pub async fn update_workspace_request(
-    params: UpdateWorkspaceParams,
-    url: &str,
-) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::patch(&url.to_owned())
-        .protobuf(params)?
-        .send()
-        .await?;
+pub async fn update_workspace_request(params: UpdateWorkspaceParams, url: &str) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::patch(&url.to_owned()).protobuf(params)?.send().await?;
     Ok(())
 }
 
-pub async fn delete_workspace_request(
-    params: DeleteWorkspaceParams,
-    url: &str,
-) -> Result<(), WorkspaceError> {
-    let _ = HttpRequestBuilder::delete(url)
-        .protobuf(params)?
-        .send()
-        .await?;
+pub async fn delete_workspace_request(params: DeleteWorkspaceParams, url: &str) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::delete(url).protobuf(params)?.send().await?;
     Ok(())
 }
 
 pub async fn read_workspace_list_request(url: &str) -> Result<RepeatedWorkspace, WorkspaceError> {
-    let workspaces = HttpRequestBuilder::get(url)
-        .send()
-        .await?
-        .response::<RepeatedWorkspace>()
-        .await?;
+    let workspaces = HttpRequestBuilder::get(url).send().await?.response::<RepeatedWorkspace>().await?;
     Ok(workspaces)
 }

+ 1 - 1
rust-lib/rustfmt.toml

@@ -1,5 +1,5 @@
 # https://rust-lang.github.io/rustfmt/?version=master&search=
-max_width = 100
+max_width = 140
 tab_spaces = 4
 fn_single_line = true
 match_block_trailing_comma = true