Bladeren bron

impl ObservableParser with dart

appflowy 3 jaren geleden
bovenliggende
commit
0a82601eac
39 gewijzigde bestanden met toevoegingen van 1169 en 865 verwijderingen
  1. 9 3
      app_flowy/lib/welcome/infrastructure/deps_resolver.dart
  2. 53 0
      app_flowy/lib/workspace/application/home/home_auth_bloc.dart
  3. 643 0
      app_flowy/lib/workspace/application/home/home_auth_bloc.freezed.dart
  4. 0 28
      app_flowy/lib/workspace/application/home/home_watcher_bloc.dart
  5. 0 562
      app_flowy/lib/workspace/application/home/home_watcher_bloc.freezed.dart
  6. 2 2
      app_flowy/lib/workspace/application/menu/menu_bloc.dart
  7. 24 12
      app_flowy/lib/workspace/application/menu/menu_user_bloc.dart
  8. 4 4
      app_flowy/lib/workspace/application/menu/menu_watch.dart
  9. 11 5
      app_flowy/lib/workspace/application/workspace/welcome_bloc.dart
  10. 4 3
      app_flowy/lib/workspace/infrastructure/deps_resolver.dart
  11. 3 3
      app_flowy/lib/workspace/infrastructure/i_user_impl.dart
  12. 1 1
      app_flowy/lib/workspace/infrastructure/repos/helper.dart
  13. 23 11
      app_flowy/lib/workspace/presentation/home/home_screen.dart
  14. 8 8
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart
  15. 2 2
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart
  16. 14 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_profile.pb.dart
  17. 2 1
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_profile.pbjson.dart
  18. 29 1
      backend/src/entities/token.rs
  19. 3 1
      backend/src/user_service/auth.rs
  20. 14 14
      backend/src/user_service/logged_user.rs
  21. 12 8
      backend/src/user_service/router.rs
  22. 21 4
      rust-lib/flowy-net/src/request/request.rs
  23. 17 0
      rust-lib/flowy-observable/src/entities/subject.rs
  24. 2 0
      rust-lib/flowy-observable/src/lib.rs
  25. 1 0
      rust-lib/flowy-sdk/src/lib.rs
  26. 1 1
      rust-lib/flowy-user/src/entities/auth.rs
  27. 4 0
      rust-lib/flowy-user/src/entities/user_profile.rs
  28. 91 91
      rust-lib/flowy-user/src/protobuf/model/auth.rs
  29. 109 64
      rust-lib/flowy-user/src/protobuf/model/user_profile.rs
  30. 1 1
      rust-lib/flowy-user/src/protobuf/proto/auth.proto
  31. 1 0
      rust-lib/flowy-user/src/protobuf/proto/user_profile.proto
  32. 10 5
      rust-lib/flowy-user/src/services/server/server_api.rs
  33. 1 1
      rust-lib/flowy-user/src/services/server/server_api_mock.rs
  34. 5 6
      rust-lib/flowy-user/src/services/user/user_session.rs
  35. 2 2
      rust-lib/flowy-user/src/sql_tables/user.rs
  36. 9 3
      rust-lib/flowy-workspace/src/services/server/server_api.rs
  37. 13 15
      rust-lib/flowy-workspace/src/services/workspace_controller.rs
  38. 7 1
      rust-lib/flowy-workspace/src/sql_tables/view/view_sql.rs
  39. 13 2
      rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs

+ 9 - 3
app_flowy/lib/welcome/infrastructure/deps_resolver.dart

@@ -2,7 +2,9 @@ import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dar
 import 'package:app_flowy/welcome/application/splash_bloc.dart';
 import 'package:app_flowy/welcome/infrastructure/i_splash_impl.dart';
 import 'package:app_flowy/workspace/application/home/home_bloc.dart';
-import 'package:app_flowy/workspace/application/home/home_watcher_bloc.dart';
+import 'package:app_flowy/workspace/application/home/home_auth_bloc.dart';
+import 'package:app_flowy/workspace/domain/i_user.dart';
+import 'package:app_flowy/workspace/infrastructure/i_user_impl.dart';
 import 'package:get_it/get_it.dart';
 
 class WelcomeDepsResolver {
@@ -10,9 +12,13 @@ class WelcomeDepsResolver {
     getIt.registerFactory<ISplashUser>(() => SplashUserImpl());
     getIt.registerFactory<ISplashRoute>(() => SplashRoute());
     getIt.registerFactory<HomeBloc>(() => HomeBloc());
-    getIt.registerFactory<HomeWatcherBloc>(() => HomeWatcherBloc());
     getIt.registerFactory<EditPannelBloc>(() => EditPannelBloc());
-
     getIt.registerFactory<SplashBloc>(() => SplashBloc(getIt<ISplashUser>()));
+
+    getIt.registerFactoryParam<HomeAuthBloc, UserProfile, void>(
+      (user, _) => HomeAuthBloc(
+        getIt<IUserWatch>(param1: user),
+      ),
+    );
   }
 }

+ 53 - 0
app_flowy/lib/workspace/application/home/home_auth_bloc.dart

@@ -0,0 +1,53 @@
+import 'package:app_flowy/workspace/domain/i_user.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:dartz/dartz.dart';
+part 'home_auth_bloc.freezed.dart';
+
+class HomeAuthBloc extends Bloc<HomeAuthEvent, HomeAuthState> {
+  final IUserWatch watch;
+  HomeAuthBloc(this.watch) : super(const HomeAuthState.loading());
+
+  @override
+  Stream<HomeAuthState> mapEventToState(
+    HomeAuthEvent event,
+  ) async* {
+    yield* event.map(
+      started: (_) async* {
+        watch.setAuthCallback(_authStateChanged);
+        watch.startWatching();
+      },
+      stop: (_) async* {},
+      unauthorized: (e) async* {
+        yield HomeAuthState.unauthorized(e.msg);
+      },
+    );
+  }
+
+  @override
+  Future<void> close() async {
+    await watch.stopWatching();
+    super.close();
+  }
+
+  void _authStateChanged(Either<Unit, UserError> errorOrNothing) {
+    errorOrNothing.fold((_) {}, (error) {
+      if (error.code == ErrorCode.UserUnauthorized) {
+        add(HomeAuthEvent.unauthorized(error.msg));
+      }
+    });
+  }
+}
+
+@freezed
+class HomeAuthEvent with _$HomeAuthEvent {
+  const factory HomeAuthEvent.started() = _Started;
+  const factory HomeAuthEvent.stop() = _Stop;
+  const factory HomeAuthEvent.unauthorized(String msg) = _Unauthorized;
+}
+
+@freezed
+class HomeAuthState with _$HomeAuthState {
+  const factory HomeAuthState.loading() = Loading;
+  const factory HomeAuthState.unauthorized(String msg) = Unauthorized;
+}

+ 643 - 0
app_flowy/lib/workspace/application/home/home_auth_bloc.freezed.dart

@@ -0,0 +1,643 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
+
+part of 'home_auth_bloc.dart';
+
+// **************************************************************************
+// FreezedGenerator
+// **************************************************************************
+
+T _$identity<T>(T value) => value;
+
+final _privateConstructorUsedError = UnsupportedError(
+    'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
+
+/// @nodoc
+class _$HomeAuthEventTearOff {
+  const _$HomeAuthEventTearOff();
+
+  _Started started() {
+    return const _Started();
+  }
+
+  _Stop stop() {
+    return const _Stop();
+  }
+
+  _Unauthorized unauthorized(String msg) {
+    return _Unauthorized(
+      msg,
+    );
+  }
+}
+
+/// @nodoc
+const $HomeAuthEvent = _$HomeAuthEventTearOff();
+
+/// @nodoc
+mixin _$HomeAuthEvent {
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() started,
+    required TResult Function() stop,
+    required TResult Function(String msg) unauthorized,
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? started,
+    TResult Function()? stop,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Started value) started,
+    required TResult Function(_Stop value) stop,
+    required TResult Function(_Unauthorized value) unauthorized,
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Started value)? started,
+    TResult Function(_Stop value)? stop,
+    TResult Function(_Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) =>
+      throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $HomeAuthEventCopyWith<$Res> {
+  factory $HomeAuthEventCopyWith(
+          HomeAuthEvent value, $Res Function(HomeAuthEvent) then) =
+      _$HomeAuthEventCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class _$HomeAuthEventCopyWithImpl<$Res>
+    implements $HomeAuthEventCopyWith<$Res> {
+  _$HomeAuthEventCopyWithImpl(this._value, this._then);
+
+  final HomeAuthEvent _value;
+  // ignore: unused_field
+  final $Res Function(HomeAuthEvent) _then;
+}
+
+/// @nodoc
+abstract class _$StartedCopyWith<$Res> {
+  factory _$StartedCopyWith(_Started value, $Res Function(_Started) then) =
+      __$StartedCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$StartedCopyWithImpl<$Res> extends _$HomeAuthEventCopyWithImpl<$Res>
+    implements _$StartedCopyWith<$Res> {
+  __$StartedCopyWithImpl(_Started _value, $Res Function(_Started) _then)
+      : super(_value, (v) => _then(v as _Started));
+
+  @override
+  _Started get _value => super._value as _Started;
+}
+
+/// @nodoc
+
+class _$_Started implements _Started {
+  const _$_Started();
+
+  @override
+  String toString() {
+    return 'HomeAuthEvent.started()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is _Started);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() started,
+    required TResult Function() stop,
+    required TResult Function(String msg) unauthorized,
+  }) {
+    return started();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? started,
+    TResult Function()? stop,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (started != null) {
+      return started();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Started value) started,
+    required TResult Function(_Stop value) stop,
+    required TResult Function(_Unauthorized value) unauthorized,
+  }) {
+    return started(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Started value)? started,
+    TResult Function(_Stop value)? stop,
+    TResult Function(_Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (started != null) {
+      return started(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class _Started implements HomeAuthEvent {
+  const factory _Started() = _$_Started;
+}
+
+/// @nodoc
+abstract class _$StopCopyWith<$Res> {
+  factory _$StopCopyWith(_Stop value, $Res Function(_Stop) then) =
+      __$StopCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class __$StopCopyWithImpl<$Res> extends _$HomeAuthEventCopyWithImpl<$Res>
+    implements _$StopCopyWith<$Res> {
+  __$StopCopyWithImpl(_Stop _value, $Res Function(_Stop) _then)
+      : super(_value, (v) => _then(v as _Stop));
+
+  @override
+  _Stop get _value => super._value as _Stop;
+}
+
+/// @nodoc
+
+class _$_Stop implements _Stop {
+  const _$_Stop();
+
+  @override
+  String toString() {
+    return 'HomeAuthEvent.stop()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is _Stop);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() started,
+    required TResult Function() stop,
+    required TResult Function(String msg) unauthorized,
+  }) {
+    return stop();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? started,
+    TResult Function()? stop,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (stop != null) {
+      return stop();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Started value) started,
+    required TResult Function(_Stop value) stop,
+    required TResult Function(_Unauthorized value) unauthorized,
+  }) {
+    return stop(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Started value)? started,
+    TResult Function(_Stop value)? stop,
+    TResult Function(_Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (stop != null) {
+      return stop(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class _Stop implements HomeAuthEvent {
+  const factory _Stop() = _$_Stop;
+}
+
+/// @nodoc
+abstract class _$UnauthorizedCopyWith<$Res> {
+  factory _$UnauthorizedCopyWith(
+          _Unauthorized value, $Res Function(_Unauthorized) then) =
+      __$UnauthorizedCopyWithImpl<$Res>;
+  $Res call({String msg});
+}
+
+/// @nodoc
+class __$UnauthorizedCopyWithImpl<$Res>
+    extends _$HomeAuthEventCopyWithImpl<$Res>
+    implements _$UnauthorizedCopyWith<$Res> {
+  __$UnauthorizedCopyWithImpl(
+      _Unauthorized _value, $Res Function(_Unauthorized) _then)
+      : super(_value, (v) => _then(v as _Unauthorized));
+
+  @override
+  _Unauthorized get _value => super._value as _Unauthorized;
+
+  @override
+  $Res call({
+    Object? msg = freezed,
+  }) {
+    return _then(_Unauthorized(
+      msg == freezed
+          ? _value.msg
+          : msg // ignore: cast_nullable_to_non_nullable
+              as String,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$_Unauthorized implements _Unauthorized {
+  const _$_Unauthorized(this.msg);
+
+  @override
+  final String msg;
+
+  @override
+  String toString() {
+    return 'HomeAuthEvent.unauthorized(msg: $msg)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is _Unauthorized &&
+            (identical(other.msg, msg) ||
+                const DeepCollectionEquality().equals(other.msg, msg)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(msg);
+
+  @JsonKey(ignore: true)
+  @override
+  _$UnauthorizedCopyWith<_Unauthorized> get copyWith =>
+      __$UnauthorizedCopyWithImpl<_Unauthorized>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() started,
+    required TResult Function() stop,
+    required TResult Function(String msg) unauthorized,
+  }) {
+    return unauthorized(msg);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? started,
+    TResult Function()? stop,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (unauthorized != null) {
+      return unauthorized(msg);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(_Started value) started,
+    required TResult Function(_Stop value) stop,
+    required TResult Function(_Unauthorized value) unauthorized,
+  }) {
+    return unauthorized(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(_Started value)? started,
+    TResult Function(_Stop value)? stop,
+    TResult Function(_Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (unauthorized != null) {
+      return unauthorized(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class _Unauthorized implements HomeAuthEvent {
+  const factory _Unauthorized(String msg) = _$_Unauthorized;
+
+  String get msg => throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  _$UnauthorizedCopyWith<_Unauthorized> get copyWith =>
+      throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+class _$HomeAuthStateTearOff {
+  const _$HomeAuthStateTearOff();
+
+  Loading loading() {
+    return const Loading();
+  }
+
+  Unauthorized unauthorized(String msg) {
+    return Unauthorized(
+      msg,
+    );
+  }
+}
+
+/// @nodoc
+const $HomeAuthState = _$HomeAuthStateTearOff();
+
+/// @nodoc
+mixin _$HomeAuthState {
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() loading,
+    required TResult Function(String msg) unauthorized,
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? loading,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Loading value) loading,
+    required TResult Function(Unauthorized value) unauthorized,
+  }) =>
+      throw _privateConstructorUsedError;
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Loading value)? loading,
+    TResult Function(Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) =>
+      throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $HomeAuthStateCopyWith<$Res> {
+  factory $HomeAuthStateCopyWith(
+          HomeAuthState value, $Res Function(HomeAuthState) then) =
+      _$HomeAuthStateCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class _$HomeAuthStateCopyWithImpl<$Res>
+    implements $HomeAuthStateCopyWith<$Res> {
+  _$HomeAuthStateCopyWithImpl(this._value, this._then);
+
+  final HomeAuthState _value;
+  // ignore: unused_field
+  final $Res Function(HomeAuthState) _then;
+}
+
+/// @nodoc
+abstract class $LoadingCopyWith<$Res> {
+  factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) =
+      _$LoadingCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class _$LoadingCopyWithImpl<$Res> extends _$HomeAuthStateCopyWithImpl<$Res>
+    implements $LoadingCopyWith<$Res> {
+  _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then)
+      : super(_value, (v) => _then(v as Loading));
+
+  @override
+  Loading get _value => super._value as Loading;
+}
+
+/// @nodoc
+
+class _$Loading implements Loading {
+  const _$Loading();
+
+  @override
+  String toString() {
+    return 'HomeAuthState.loading()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is Loading);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() loading,
+    required TResult Function(String msg) unauthorized,
+  }) {
+    return loading();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? loading,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (loading != null) {
+      return loading();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Loading value) loading,
+    required TResult Function(Unauthorized value) unauthorized,
+  }) {
+    return loading(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Loading value)? loading,
+    TResult Function(Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (loading != null) {
+      return loading(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Loading implements HomeAuthState {
+  const factory Loading() = _$Loading;
+}
+
+/// @nodoc
+abstract class $UnauthorizedCopyWith<$Res> {
+  factory $UnauthorizedCopyWith(
+          Unauthorized value, $Res Function(Unauthorized) then) =
+      _$UnauthorizedCopyWithImpl<$Res>;
+  $Res call({String msg});
+}
+
+/// @nodoc
+class _$UnauthorizedCopyWithImpl<$Res> extends _$HomeAuthStateCopyWithImpl<$Res>
+    implements $UnauthorizedCopyWith<$Res> {
+  _$UnauthorizedCopyWithImpl(
+      Unauthorized _value, $Res Function(Unauthorized) _then)
+      : super(_value, (v) => _then(v as Unauthorized));
+
+  @override
+  Unauthorized get _value => super._value as Unauthorized;
+
+  @override
+  $Res call({
+    Object? msg = freezed,
+  }) {
+    return _then(Unauthorized(
+      msg == freezed
+          ? _value.msg
+          : msg // ignore: cast_nullable_to_non_nullable
+              as String,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$Unauthorized implements Unauthorized {
+  const _$Unauthorized(this.msg);
+
+  @override
+  final String msg;
+
+  @override
+  String toString() {
+    return 'HomeAuthState.unauthorized(msg: $msg)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is Unauthorized &&
+            (identical(other.msg, msg) ||
+                const DeepCollectionEquality().equals(other.msg, msg)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(msg);
+
+  @JsonKey(ignore: true)
+  @override
+  $UnauthorizedCopyWith<Unauthorized> get copyWith =>
+      _$UnauthorizedCopyWithImpl<Unauthorized>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() loading,
+    required TResult Function(String msg) unauthorized,
+  }) {
+    return unauthorized(msg);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? loading,
+    TResult Function(String msg)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (unauthorized != null) {
+      return unauthorized(msg);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Loading value) loading,
+    required TResult Function(Unauthorized value) unauthorized,
+  }) {
+    return unauthorized(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Loading value)? loading,
+    TResult Function(Unauthorized value)? unauthorized,
+    required TResult orElse(),
+  }) {
+    if (unauthorized != null) {
+      return unauthorized(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Unauthorized implements HomeAuthState {
+  const factory Unauthorized(String msg) = _$Unauthorized;
+
+  String get msg => throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  $UnauthorizedCopyWith<Unauthorized> get copyWith =>
+      throw _privateConstructorUsedError;
+}

+ 0 - 28
app_flowy/lib/workspace/application/home/home_watcher_bloc.dart

@@ -1,28 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:freezed_annotation/freezed_annotation.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-
-part 'home_watcher_bloc.freezed.dart';
-
-class HomeWatcherBloc extends Bloc<HomeWatcherEvent, HomeWatcherState> {
-  HomeWatcherBloc() : super(const HomeWatcherState.initial());
-
-  @override
-  Stream<HomeWatcherState> mapEventToState(
-    HomeWatcherEvent event,
-  ) async* {
-    yield state;
-  }
-}
-
-@freezed
-abstract class HomeWatcherEvent with _$HomeWatcherEvent {
-  const factory HomeWatcherEvent.started(String workspaceId) = _Started;
-  const factory HomeWatcherEvent.stop(String workspaceId) = _Stop;
-}
-
-@freezed
-abstract class HomeWatcherState with _$HomeWatcherState {
-  const factory HomeWatcherState.initial() = _Initial;
-  const factory HomeWatcherState.loading() = _Loading;
-}

+ 0 - 562
app_flowy/lib/workspace/application/home/home_watcher_bloc.freezed.dart

@@ -1,562 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
-
-part of 'home_watcher_bloc.dart';
-
-// **************************************************************************
-// FreezedGenerator
-// **************************************************************************
-
-T _$identity<T>(T value) => value;
-
-final _privateConstructorUsedError = UnsupportedError(
-    'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
-
-/// @nodoc
-class _$HomeWatcherEventTearOff {
-  const _$HomeWatcherEventTearOff();
-
-  _Started started(String workspaceId) {
-    return _Started(
-      workspaceId,
-    );
-  }
-
-  _Stop stop(String workspaceId) {
-    return _Stop(
-      workspaceId,
-    );
-  }
-}
-
-/// @nodoc
-const $HomeWatcherEvent = _$HomeWatcherEventTearOff();
-
-/// @nodoc
-mixin _$HomeWatcherEvent {
-  String get workspaceId => throw _privateConstructorUsedError;
-
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function(String workspaceId) started,
-    required TResult Function(String workspaceId) stop,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function(String workspaceId)? started,
-    TResult Function(String workspaceId)? stop,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Started value) started,
-    required TResult Function(_Stop value) stop,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Started value)? started,
-    TResult Function(_Stop value)? stop,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-
-  @JsonKey(ignore: true)
-  $HomeWatcherEventCopyWith<HomeWatcherEvent> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class $HomeWatcherEventCopyWith<$Res> {
-  factory $HomeWatcherEventCopyWith(
-          HomeWatcherEvent value, $Res Function(HomeWatcherEvent) then) =
-      _$HomeWatcherEventCopyWithImpl<$Res>;
-  $Res call({String workspaceId});
-}
-
-/// @nodoc
-class _$HomeWatcherEventCopyWithImpl<$Res>
-    implements $HomeWatcherEventCopyWith<$Res> {
-  _$HomeWatcherEventCopyWithImpl(this._value, this._then);
-
-  final HomeWatcherEvent _value;
-  // ignore: unused_field
-  final $Res Function(HomeWatcherEvent) _then;
-
-  @override
-  $Res call({
-    Object? workspaceId = freezed,
-  }) {
-    return _then(_value.copyWith(
-      workspaceId: workspaceId == freezed
-          ? _value.workspaceId
-          : workspaceId // ignore: cast_nullable_to_non_nullable
-              as String,
-    ));
-  }
-}
-
-/// @nodoc
-abstract class _$StartedCopyWith<$Res>
-    implements $HomeWatcherEventCopyWith<$Res> {
-  factory _$StartedCopyWith(_Started value, $Res Function(_Started) then) =
-      __$StartedCopyWithImpl<$Res>;
-  @override
-  $Res call({String workspaceId});
-}
-
-/// @nodoc
-class __$StartedCopyWithImpl<$Res> extends _$HomeWatcherEventCopyWithImpl<$Res>
-    implements _$StartedCopyWith<$Res> {
-  __$StartedCopyWithImpl(_Started _value, $Res Function(_Started) _then)
-      : super(_value, (v) => _then(v as _Started));
-
-  @override
-  _Started get _value => super._value as _Started;
-
-  @override
-  $Res call({
-    Object? workspaceId = freezed,
-  }) {
-    return _then(_Started(
-      workspaceId == freezed
-          ? _value.workspaceId
-          : workspaceId // ignore: cast_nullable_to_non_nullable
-              as String,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_Started implements _Started {
-  const _$_Started(this.workspaceId);
-
-  @override
-  final String workspaceId;
-
-  @override
-  String toString() {
-    return 'HomeWatcherEvent.started(workspaceId: $workspaceId)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _Started &&
-            (identical(other.workspaceId, workspaceId) ||
-                const DeepCollectionEquality()
-                    .equals(other.workspaceId, workspaceId)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(workspaceId);
-
-  @JsonKey(ignore: true)
-  @override
-  _$StartedCopyWith<_Started> get copyWith =>
-      __$StartedCopyWithImpl<_Started>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function(String workspaceId) started,
-    required TResult Function(String workspaceId) stop,
-  }) {
-    return started(workspaceId);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function(String workspaceId)? started,
-    TResult Function(String workspaceId)? stop,
-    required TResult orElse(),
-  }) {
-    if (started != null) {
-      return started(workspaceId);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Started value) started,
-    required TResult Function(_Stop value) stop,
-  }) {
-    return started(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Started value)? started,
-    TResult Function(_Stop value)? stop,
-    required TResult orElse(),
-  }) {
-    if (started != null) {
-      return started(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Started implements HomeWatcherEvent {
-  const factory _Started(String workspaceId) = _$_Started;
-
-  @override
-  String get workspaceId => throw _privateConstructorUsedError;
-  @override
-  @JsonKey(ignore: true)
-  _$StartedCopyWith<_Started> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class _$StopCopyWith<$Res> implements $HomeWatcherEventCopyWith<$Res> {
-  factory _$StopCopyWith(_Stop value, $Res Function(_Stop) then) =
-      __$StopCopyWithImpl<$Res>;
-  @override
-  $Res call({String workspaceId});
-}
-
-/// @nodoc
-class __$StopCopyWithImpl<$Res> extends _$HomeWatcherEventCopyWithImpl<$Res>
-    implements _$StopCopyWith<$Res> {
-  __$StopCopyWithImpl(_Stop _value, $Res Function(_Stop) _then)
-      : super(_value, (v) => _then(v as _Stop));
-
-  @override
-  _Stop get _value => super._value as _Stop;
-
-  @override
-  $Res call({
-    Object? workspaceId = freezed,
-  }) {
-    return _then(_Stop(
-      workspaceId == freezed
-          ? _value.workspaceId
-          : workspaceId // ignore: cast_nullable_to_non_nullable
-              as String,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_Stop implements _Stop {
-  const _$_Stop(this.workspaceId);
-
-  @override
-  final String workspaceId;
-
-  @override
-  String toString() {
-    return 'HomeWatcherEvent.stop(workspaceId: $workspaceId)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _Stop &&
-            (identical(other.workspaceId, workspaceId) ||
-                const DeepCollectionEquality()
-                    .equals(other.workspaceId, workspaceId)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(workspaceId);
-
-  @JsonKey(ignore: true)
-  @override
-  _$StopCopyWith<_Stop> get copyWith =>
-      __$StopCopyWithImpl<_Stop>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function(String workspaceId) started,
-    required TResult Function(String workspaceId) stop,
-  }) {
-    return stop(workspaceId);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function(String workspaceId)? started,
-    TResult Function(String workspaceId)? stop,
-    required TResult orElse(),
-  }) {
-    if (stop != null) {
-      return stop(workspaceId);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Started value) started,
-    required TResult Function(_Stop value) stop,
-  }) {
-    return stop(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Started value)? started,
-    TResult Function(_Stop value)? stop,
-    required TResult orElse(),
-  }) {
-    if (stop != null) {
-      return stop(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Stop implements HomeWatcherEvent {
-  const factory _Stop(String workspaceId) = _$_Stop;
-
-  @override
-  String get workspaceId => throw _privateConstructorUsedError;
-  @override
-  @JsonKey(ignore: true)
-  _$StopCopyWith<_Stop> get copyWith => throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-class _$HomeWatcherStateTearOff {
-  const _$HomeWatcherStateTearOff();
-
-  _Initial initial() {
-    return const _Initial();
-  }
-
-  _Loading loading() {
-    return const _Loading();
-  }
-}
-
-/// @nodoc
-const $HomeWatcherState = _$HomeWatcherStateTearOff();
-
-/// @nodoc
-mixin _$HomeWatcherState {
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() loading,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? loading,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Loading value) loading,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Loading value)? loading,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class $HomeWatcherStateCopyWith<$Res> {
-  factory $HomeWatcherStateCopyWith(
-          HomeWatcherState value, $Res Function(HomeWatcherState) then) =
-      _$HomeWatcherStateCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class _$HomeWatcherStateCopyWithImpl<$Res>
-    implements $HomeWatcherStateCopyWith<$Res> {
-  _$HomeWatcherStateCopyWithImpl(this._value, this._then);
-
-  final HomeWatcherState _value;
-  // ignore: unused_field
-  final $Res Function(HomeWatcherState) _then;
-}
-
-/// @nodoc
-abstract class _$InitialCopyWith<$Res> {
-  factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
-      __$InitialCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class __$InitialCopyWithImpl<$Res> extends _$HomeWatcherStateCopyWithImpl<$Res>
-    implements _$InitialCopyWith<$Res> {
-  __$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
-      : super(_value, (v) => _then(v as _Initial));
-
-  @override
-  _Initial get _value => super._value as _Initial;
-}
-
-/// @nodoc
-
-class _$_Initial implements _Initial {
-  const _$_Initial();
-
-  @override
-  String toString() {
-    return 'HomeWatcherState.initial()';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) || (other is _Initial);
-  }
-
-  @override
-  int get hashCode => runtimeType.hashCode;
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() loading,
-  }) {
-    return initial();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? loading,
-    required TResult orElse(),
-  }) {
-    if (initial != null) {
-      return initial();
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Loading value) loading,
-  }) {
-    return initial(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Loading value)? loading,
-    required TResult orElse(),
-  }) {
-    if (initial != null) {
-      return initial(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Initial implements HomeWatcherState {
-  const factory _Initial() = _$_Initial;
-}
-
-/// @nodoc
-abstract class _$LoadingCopyWith<$Res> {
-  factory _$LoadingCopyWith(_Loading value, $Res Function(_Loading) then) =
-      __$LoadingCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class __$LoadingCopyWithImpl<$Res> extends _$HomeWatcherStateCopyWithImpl<$Res>
-    implements _$LoadingCopyWith<$Res> {
-  __$LoadingCopyWithImpl(_Loading _value, $Res Function(_Loading) _then)
-      : super(_value, (v) => _then(v as _Loading));
-
-  @override
-  _Loading get _value => super._value as _Loading;
-}
-
-/// @nodoc
-
-class _$_Loading implements _Loading {
-  const _$_Loading();
-
-  @override
-  String toString() {
-    return 'HomeWatcherState.loading()';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) || (other is _Loading);
-  }
-
-  @override
-  int get hashCode => runtimeType.hashCode;
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() loading,
-  }) {
-    return loading();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? loading,
-    required TResult orElse(),
-  }) {
-    if (loading != null) {
-      return loading();
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Loading value) loading,
-  }) {
-    return loading(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Loading value)? loading,
-    required TResult orElse(),
-  }) {
-    if (loading != null) {
-      return loading(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Loading implements HomeWatcherState {
-  const factory _Loading() = _$_Loading;
-}

+ 2 - 2
app_flowy/lib/workspace/application/menu/menu_bloc.dart

@@ -66,7 +66,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
 }
 
 @freezed
-abstract class MenuEvent with _$MenuEvent {
+class MenuEvent with _$MenuEvent {
   const factory MenuEvent.initial() = _Initial;
   const factory MenuEvent.collapse() = Collapse;
   const factory MenuEvent.openPage(HomeStackView stackView) = OpenPage;
@@ -74,7 +74,7 @@ abstract class MenuEvent with _$MenuEvent {
 }
 
 @freezed
-abstract class MenuState implements _$MenuState {
+class MenuState with _$MenuState {
   const factory MenuState({
     required bool isCollapse,
     required Option<List<App>> apps,

+ 24 - 12
app_flowy/lib/workspace/application/menu/menu_user_bloc.dart

@@ -1,5 +1,6 @@
 import 'package:app_flowy/workspace/domain/i_user.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
@@ -9,24 +10,18 @@ part 'menu_user_bloc.freezed.dart';
 
 class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
   final IUser iUserImpl;
+  final IUserWatch watch;
 
-  MenuUserBloc(this.iUserImpl) : super(MenuUserState.initial(iUserImpl.user));
+  MenuUserBloc(this.iUserImpl, this.watch)
+      : super(MenuUserState.initial(iUserImpl.user));
 
   @override
   Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* {
     yield* event.map(
       initial: (_) async* {
-        // // fetch workspaces
-        // iUserImpl.fetchWorkspaces().then((result) {
-        //   result.fold(
-        //     (workspaces) async* {
-        //       yield state.copyWith(workspaces: some(workspaces));
-        //     },
-        //     (error) async* {
-        //       yield state.copyWith(successOrFailure: right(error.msg));
-        //     },
-        //   );
-        // });
+        watch.setProfileCallback(_profileUpdated);
+        watch.setWorkspacesCallback(_workspacesUpdated);
+        watch.startWatching();
       },
       fetchWorkspaces: (_FetchWorkspaces value) async* {},
     );
@@ -34,8 +29,25 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
 
   @override
   Future<void> close() async {
+    await watch.stopWatching();
     super.close();
   }
+
+  void _profileUpdated(Either<UserProfile, UserError> userOrFailed) {}
+  void _workspacesUpdated(
+      Either<List<Workspace>, WorkspaceError> workspacesOrFailed) {
+    // fetch workspaces
+    // iUserImpl.fetchWorkspaces().then((result) {
+    //   result.fold(
+    //     (workspaces) async* {
+    //       yield state.copyWith(workspaces: some(workspaces));
+    //     },
+    //     (error) async* {
+    //       yield state.copyWith(successOrFailure: right(error.msg));
+    //     },
+    //   );
+    // });
+  }
 }
 
 @freezed

+ 4 - 4
app_flowy/lib/workspace/application/menu/menu_watch.dart

@@ -10,14 +10,14 @@ import 'package:dartz/dartz.dart';
 part 'menu_watch.freezed.dart';
 
 class MenuWatchBloc extends Bloc<MenuWatchEvent, MenuWatchState> {
-  final IWorkspaceWatch watcher;
-  MenuWatchBloc(this.watcher) : super(const MenuWatchState.initial());
+  final IWorkspaceWatch watch;
+  MenuWatchBloc(this.watch) : super(const MenuWatchState.initial());
 
   @override
   Stream<MenuWatchState> mapEventToState(MenuWatchEvent event) async* {
     yield* event.map(
       started: (_) async* {
-        watcher.startWatching(
+        watch.startWatching(
           addAppCallback: (appsOrFail) => _handleAppsOrFail(appsOrFail),
         );
       },
@@ -32,7 +32,7 @@ class MenuWatchBloc extends Bloc<MenuWatchEvent, MenuWatchState> {
 
   @override
   Future<void> close() async {
-    await watcher.stopWatching();
+    await watch.stopWatching();
     return super.close();
   }
 

+ 11 - 5
app_flowy/lib/workspace/application/workspace/welcome_bloc.dart

@@ -10,9 +10,9 @@ import 'package:dartz/dartz.dart';
 part 'welcome_bloc.freezed.dart';
 
 class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
-  UserRepo repo;
-  IUserWatch watcher;
-  WelcomeBloc({required this.repo, required this.watcher})
+  final UserRepo repo;
+  final IUserWatch watch;
+  WelcomeBloc({required this.repo, required this.watch})
       : super(WelcomeState.initial());
 
   @override
@@ -20,8 +20,8 @@ class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
     WelcomeEvent event,
   ) async* {
     yield* event.map(initial: (e) async* {
-      watcher.setWorkspacesCallback(_workspacesUpdated);
-      watcher.startWatching();
+      watch.setWorkspacesCallback(_workspacesUpdated);
+      watch.startWatching();
       //
       yield* _fetchWorkspaces();
     }, openWorkspace: (e) async* {
@@ -37,6 +37,12 @@ class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
     });
   }
 
+  @override
+  Future<void> close() async {
+    await watch.stopWatching();
+    super.close();
+  }
+
   Stream<WelcomeState> _fetchWorkspaces() async* {
     final workspacesOrFailed = await repo.getWorkspaces();
     yield workspacesOrFailed.fold(

+ 4 - 3
app_flowy/lib/workspace/infrastructure/deps_resolver.dart

@@ -69,8 +69,9 @@ class HomeDepsResolver {
         (user, workspaceId) => MenuWatchBloc(
             getIt<IWorkspaceWatch>(param1: user, param2: workspaceId)));
 
-    getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>(
-        (user, _) => MenuUserBloc(getIt<IUser>(param1: user)));
+    getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>((user, _) =>
+        MenuUserBloc(
+            getIt<IUser>(param1: user), getIt<IUserWatch>(param1: user)));
 
     //
     getIt.registerFactoryParam<AppBloc, String, void>(
@@ -97,7 +98,7 @@ class HomeDepsResolver {
     getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
       (user, _) => WelcomeBloc(
         repo: UserRepo(user: user),
-        watcher: getIt<IUserWatch>(param1: user),
+        watch: getIt<IUserWatch>(param1: user),
       ),
     );
 

+ 3 - 3
app_flowy/lib/workspace/infrastructure/i_user_impl.dart

@@ -62,10 +62,10 @@ class IUserWatchImpl extends IUserWatch {
   @override
   void startWatching() {
     _workspaceParser = WorkspaceObservableParser(
-        id: _user.id, callback: _workspaceObservableCallback);
+        id: _user.token, callback: _workspaceObservableCallback);
 
-    _userParser =
-        UserObservableParser(id: _user.id, callback: _userObservableCallback);
+    _userParser = UserObservableParser(
+        id: _user.token, callback: _userObservableCallback);
 
     _subscription = RustStreamReceiver.listen((observable) {
       _workspaceParser.parse(observable);

+ 1 - 1
app_flowy/lib/workspace/infrastructure/repos/helper.dart

@@ -86,7 +86,7 @@ class ObservableParser<T, E> {
     }
 
     if (subject.hasPayload()) {
-      final bytes = Uint8List.fromList(subject.error);
+      final bytes = Uint8List.fromList(subject.payload);
       callback(ty, left(bytes));
     } else if (subject.hasError()) {
       final bytes = Uint8List.fromList(subject.error);

+ 23 - 11
app_flowy/lib/workspace/presentation/home/home_screen.dart

@@ -1,5 +1,5 @@
 import 'package:app_flowy/workspace/application/home/home_bloc.dart';
-import 'package:app_flowy/workspace/application/home/home_watcher_bloc.dart';
+import 'package:app_flowy/workspace/application/home/home_auth_bloc.dart';
 import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
 import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
 import 'package:app_flowy/startup/startup.dart';
@@ -22,22 +22,34 @@ class HomeScreen extends StatelessWidget {
   Widget build(BuildContext context) {
     return MultiBlocProvider(
       providers: [
-        BlocProvider<HomeWatcherBloc>(
-            create: (context) => getIt<HomeWatcherBloc>()),
+        BlocProvider<HomeAuthBloc>(
+          create: (context) => getIt<HomeAuthBloc>(param1: user)
+            ..add(const HomeAuthEvent.started()),
+        ),
         BlocProvider<HomeBloc>(create: (context) => getIt<HomeBloc>()),
       ],
       child: Scaffold(
         key: HomeScreen.scaffoldKey,
-        body: BlocBuilder<HomeBloc, HomeState>(
-          buildWhen: (previous, current) => previous != current,
-          builder: (context, state) {
-            return FlowyContainer(
-              Theme.of(context).colorScheme.surface,
-              // Colors.white,
-              child: _buildBody(
-                  state, context.read<HomeBloc>().state.forceCollapse),
+        body: BlocListener<HomeAuthBloc, HomeAuthState>(
+          listener: (context, state) {
+            state.map(
+              loading: (_) {},
+              unauthorized: (unauthorized) {
+                //
+              },
             );
           },
+          child: BlocBuilder<HomeBloc, HomeState>(
+            buildWhen: (previous, current) => previous != current,
+            builder: (context, state) {
+              return FlowyContainer(
+                Theme.of(context).colorScheme.surface,
+                // Colors.white,
+                child: _buildBody(
+                    state, context.read<HomeBloc>().state.forceCollapse),
+              );
+            },
+          ),
         ),
       ),
     );

+ 8 - 8
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pb.dart

@@ -133,7 +133,7 @@ class SignInParams extends $pb.GeneratedMessage {
 
 class SignInResponse extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SignInResponse', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'uid')
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'email')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'token')
@@ -142,14 +142,14 @@ class SignInResponse extends $pb.GeneratedMessage {
 
   SignInResponse._() : super();
   factory SignInResponse({
-    $core.String? uid,
+    $core.String? userId,
     $core.String? name,
     $core.String? email,
     $core.String? token,
   }) {
     final _result = create();
-    if (uid != null) {
-      _result.uid = uid;
+    if (userId != null) {
+      _result.userId = userId;
     }
     if (name != null) {
       _result.name = name;
@@ -184,13 +184,13 @@ class SignInResponse extends $pb.GeneratedMessage {
   static SignInResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get uid => $_getSZ(0);
+  $core.String get userId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set uid($core.String v) { $_setString(0, v); }
+  set userId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasUid() => $_has(0);
+  $core.bool hasUserId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearUid() => clearField(1);
+  void clearUserId() => clearField(1);
 
   @$pb.TagNumber(2)
   $core.String get name => $_getSZ(1);

+ 2 - 2
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/auth.pbjson.dart

@@ -34,7 +34,7 @@ final $typed_data.Uint8List signInParamsDescriptor = $convert.base64Decode('CgxT
 const SignInResponse$json = const {
   '1': 'SignInResponse',
   '2': const [
-    const {'1': 'uid', '3': 1, '4': 1, '5': 9, '10': 'uid'},
+    const {'1': 'user_id', '3': 1, '4': 1, '5': 9, '10': 'userId'},
     const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'email', '3': 3, '4': 1, '5': 9, '10': 'email'},
     const {'1': 'token', '3': 4, '4': 1, '5': 9, '10': 'token'},
@@ -42,7 +42,7 @@ const SignInResponse$json = const {
 };
 
 /// Descriptor for `SignInResponse`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List signInResponseDescriptor = $convert.base64Decode('Cg5TaWduSW5SZXNwb25zZRIQCgN1aWQYASABKAlSA3VpZBISCgRuYW1lGAIgASgJUgRuYW1lEhQKBWVtYWlsGAMgASgJUgVlbWFpbBIUCgV0b2tlbhgEIAEoCVIFdG9rZW4=');
+final $typed_data.Uint8List signInResponseDescriptor = $convert.base64Decode('Cg5TaWduSW5SZXNwb25zZRIXCgd1c2VyX2lkGAEgASgJUgZ1c2VySWQSEgoEbmFtZRgCIAEoCVIEbmFtZRIUCgVlbWFpbBgDIAEoCVIFZW1haWwSFAoFdG9rZW4YBCABKAlSBXRva2Vu');
 @$core.Deprecated('Use signUpRequestDescriptor instead')
 const SignUpRequest$json = const {
   '1': 'SignUpRequest',

+ 14 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/user_profile.pb.dart

@@ -63,6 +63,7 @@ class UserProfile extends $pb.GeneratedMessage {
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'email')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
+    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'token')
     ..hasRequiredFields = false
   ;
 
@@ -71,6 +72,7 @@ class UserProfile extends $pb.GeneratedMessage {
     $core.String? id,
     $core.String? email,
     $core.String? name,
+    $core.String? token,
   }) {
     final _result = create();
     if (id != null) {
@@ -82,6 +84,9 @@ class UserProfile extends $pb.GeneratedMessage {
     if (name != null) {
       _result.name = name;
     }
+    if (token != null) {
+      _result.token = token;
+    }
     return _result;
   }
   factory UserProfile.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -131,6 +136,15 @@ class UserProfile extends $pb.GeneratedMessage {
   $core.bool hasName() => $_has(2);
   @$pb.TagNumber(3)
   void clearName() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get token => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set token($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasToken() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearToken() => clearField(4);
 }
 
 enum UpdateUserRequest_OneOfName {

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

@@ -37,11 +37,12 @@ const UserProfile$json = const {
     const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
     const {'1': 'email', '3': 2, '4': 1, '5': 9, '10': 'email'},
     const {'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'token', '3': 4, '4': 1, '5': 9, '10': 'token'},
   ],
 };
 
 /// Descriptor for `UserProfile`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List userProfileDescriptor = $convert.base64Decode('CgtVc2VyUHJvZmlsZRIOCgJpZBgBIAEoCVICaWQSFAoFZW1haWwYAiABKAlSBWVtYWlsEhIKBG5hbWUYAyABKAlSBG5hbWU=');
+final $typed_data.Uint8List userProfileDescriptor = $convert.base64Decode('CgtVc2VyUHJvZmlsZRIOCgJpZBgBIAEoCVICaWQSFAoFZW1haWwYAiABKAlSBWVtYWlsEhIKBG5hbWUYAyABKAlSBG5hbWUSFAoFdG9rZW4YBCABKAlSBXRva2Vu');
 @$core.Deprecated('Use updateUserRequestDescriptor instead')
 const UpdateUserRequest$json = const {
   '1': 'UpdateUserRequest',

+ 29 - 1
backend/src/entities/token.rs

@@ -40,7 +40,7 @@ impl Claim {
 // }
 
 #[derive(From, Into, Clone)]
-pub struct Token(String);
+pub struct Token(pub String);
 impl Token {
     pub fn create_token(user_id: &str) -> Result<Self, ServerError> {
         let claims = Claim::with_user_id(&user_id);
@@ -62,4 +62,32 @@ impl Token {
         .map(|data| Ok(data.claims))
         .map_err(|err| ServerError::unauthorized().context(err))?
     }
+
+    pub fn parser_from_request(request: &HttpRequest) -> Result<Self, ServerError> {
+        match request.headers().get(HEADER_TOKEN) {
+            Some(header) => match header.to_str() {
+                Ok(val) => Ok(Token(val.to_owned())),
+                Err(_) => Err(ServerError::unauthorized()),
+            },
+            None => Err(ServerError::unauthorized()),
+        }
+    }
+}
+
+use actix_web::{dev::Payload, FromRequest, HttpRequest};
+use flowy_net::config::HEADER_TOKEN;
+use futures::future::{ready, Ready};
+use std::convert::TryInto;
+
+impl FromRequest for Token {
+    type Config = ();
+    type Error = ServerError;
+    type Future = Ready<Result<Self, Self::Error>>;
+
+    fn from_request(request: &HttpRequest, _payload: &mut Payload) -> Self::Future {
+        match Token::parser_from_request(request) {
+            Ok(token) => ready(Ok(token)),
+            Err(err) => ready(Err(err)),
+        }
+    }
 }

+ 3 - 1
backend/src/user_service/auth.rs

@@ -48,7 +48,7 @@ pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInRespon
 
     let _ = AUTHORIZED_USERS.store_auth(logged_user, true)?;
     let mut response_data = SignInResponse::default();
-    response_data.set_uid(user.id.to_string());
+    response_data.set_user_id(user.id.to_string());
     response_data.set_name(user.name);
     response_data.set_email(user.email);
     response_data.set_token(token.clone().into());
@@ -101,6 +101,7 @@ pub async fn register_user(
 
 pub(crate) async fn get_user_profile(
     pool: &PgPool,
+    token: Token,
     logged_user: LoggedUser,
 ) -> Result<FlowyResponse, ServerError> {
     let mut transaction = pool
@@ -128,6 +129,7 @@ pub(crate) async fn get_user_profile(
     user_profile.set_id(user_table.id.to_string());
     user_profile.set_email(user_table.email);
     user_profile.set_name(user_table.name);
+    user_profile.set_token(token.0);
     FlowyResponse::success().pb(user_profile)
 }
 

+ 14 - 14
backend/src/user_service/logged_user.rs

@@ -24,17 +24,6 @@ impl std::convert::From<Claim> for LoggedUser {
     }
 }
 
-impl std::convert::TryFrom<&HeaderValue> for LoggedUser {
-    type Error = ServerError;
-
-    fn try_from(header: &HeaderValue) -> Result<Self, Self::Error> {
-        match header.to_str() {
-            Ok(val) => LoggedUser::from_token(val.to_owned()),
-            Err(_) => Err(ServerError::unauthorized()),
-        }
-    }
-}
-
 impl LoggedUser {
     pub fn new(user_id: &str) -> Self {
         Self {
@@ -67,9 +56,20 @@ impl FromRequest for LoggedUser {
     type Future = Ready<Result<Self, Self::Error>>;
 
     fn from_request(request: &HttpRequest, _payload: &mut Payload) -> Self::Future {
-        match request.headers().get(HEADER_TOKEN) {
-            Some(header) => ready(header.try_into()),
-            None => ready(Err(ServerError::unauthorized())),
+        match Token::parser_from_request(request) {
+            Ok(token) => ready(LoggedUser::from_token(token.0)),
+            Err(err) => ready(Err(err)),
+        }
+    }
+}
+
+impl std::convert::TryFrom<&HeaderValue> for LoggedUser {
+    type Error = ServerError;
+
+    fn try_from(header: &HeaderValue) -> Result<Self, Self::Error> {
+        match header.to_str() {
+            Ok(val) => LoggedUser::from_token(val.to_owned()),
+            Err(_) => Err(ServerError::unauthorized()),
         }
     }
 }

+ 12 - 8
backend/src/user_service/router.rs

@@ -5,13 +5,16 @@ use actix_web::{
     HttpResponse,
 };
 
-use crate::user_service::{
-    get_user_profile,
-    register_user,
-    set_user_profile,
-    sign_in,
-    sign_out,
-    LoggedUser,
+use crate::{
+    entities::token::Token,
+    user_service::{
+        get_user_profile,
+        register_user,
+        set_user_profile,
+        sign_in,
+        sign_out,
+        LoggedUser,
+    },
 };
 use actix_identity::Identity;
 use flowy_net::{errors::ServerError, response::FlowyResponse};
@@ -41,10 +44,11 @@ pub async fn sign_out_handler(
 }
 
 pub async fn get_user_profile_handler(
+    token: Token,
     logged_user: LoggedUser,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
-    let response = get_user_profile(pool.get_ref(), logged_user).await?;
+    let response = get_user_profile(pool.get_ref(), token, logged_user).await?;
     Ok(response.into())
 }
 

+ 21 - 4
rust-lib/flowy-net/src/request/request.rs

@@ -1,11 +1,17 @@
 use crate::{
+    config::HEADER_TOKEN,
     errors::{ErrorCode, ServerError},
     response::FlowyResponse,
 };
 use bytes::Bytes;
-use hyper::http;
+use hyper::{http, http::HeaderValue};
 use protobuf::ProtobufError;
-use reqwest::{header::HeaderMap, Client, Method, Response};
+use reqwest::{
+    header::{HeaderMap, ToStrError},
+    Client,
+    Method,
+    Response,
+};
 use std::{
     convert::{TryFrom, TryInto},
     sync::Arc,
@@ -14,7 +20,7 @@ use std::{
 use tokio::sync::oneshot;
 
 pub trait ResponseMiddleware {
-    fn receive_response(&self, response: &FlowyResponse);
+    fn receive_response(&self, token: &Option<String>, response: &FlowyResponse);
 }
 
 pub struct HttpRequestBuilder {
@@ -114,8 +120,9 @@ impl HttpRequestBuilder {
 
         let response = rx.await??;
         let flowy_response = flowy_response_from(response).await?;
+        let token = self.token();
         self.middleware.iter().for_each(|middleware| {
-            middleware.receive_response(&flowy_response);
+            middleware.receive_response(&token, &flowy_response);
         });
         match flowy_response.error {
             None => {
@@ -138,6 +145,16 @@ impl HttpRequestBuilder {
             Some(data) => Ok(T2::try_from(data)?),
         }
     }
+
+    fn token(&self) -> Option<String> {
+        match self.headers.get(HEADER_TOKEN) {
+            None => None,
+            Some(header) => match header.to_str() {
+                Ok(val) => Some(val.to_owned()),
+                Err(_) => None,
+            },
+        }
+    }
 }
 
 async fn flowy_response_from(original: Response) -> Result<FlowyResponse, ServerError> {

+ 17 - 0
rust-lib/flowy-observable/src/entities/subject.rs

@@ -1,4 +1,5 @@
 use flowy_derive::ProtoBuf;
+use std::{fmt, fmt::Formatter};
 
 #[derive(Debug, Clone, ProtoBuf)]
 pub struct ObservableSubject {
@@ -18,6 +19,22 @@ pub struct ObservableSubject {
     pub error: Option<Vec<u8>>,
 }
 
+impl std::fmt::Display for ObservableSubject {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        let _ = f.write_str(&self.source)?;
+        let _ = f.write_str(&format!("-{}", self.ty))?;
+        if let Some(payload) = &self.payload {
+            let _ = f.write_str(&format!("-{} payload", payload.len()))?;
+        }
+
+        if let Some(payload) = &self.error {
+            let _ = f.write_str(&format!("-{} error", payload.len()))?;
+        }
+
+        Ok(())
+    }
+}
+
 impl std::default::Default for ObservableSubject {
     fn default() -> Self {
         Self {

+ 2 - 0
rust-lib/flowy-observable/src/lib.rs

@@ -71,6 +71,8 @@ impl ObservableBuilder {
             payload,
             error,
         };
+
+        log::debug!("Post {}", subject);
         match RustStreamSender::post(subject) {
             Ok(_) => {},
             Err(error) => log::error!("Send observable subject failed: {}", error),

+ 1 - 0
rust-lib/flowy-sdk/src/lib.rs

@@ -38,6 +38,7 @@ fn crate_log_filter(level: Option<String>) -> String {
     filters.push(format!("flowy_sdk={}", level));
     filters.push(format!("flowy_workspace={}", level));
     filters.push(format!("flowy_user={}", level));
+    filters.push(format!("flowy_observable={}", level));
     filters.push(format!("info"));
     filters.join(",")
 }

+ 1 - 1
rust-lib/flowy-user/src/entities/auth.rs

@@ -23,7 +23,7 @@ pub struct SignInParams {
 #[derive(Debug, Default, ProtoBuf)]
 pub struct SignInResponse {
     #[pb(index = 1)]
-    pub uid: String,
+    pub user_id: String,
 
     #[pb(index = 2)]
     pub name: String,

+ 4 - 0
rust-lib/flowy-user/src/entities/user_profile.rs

@@ -27,6 +27,9 @@ pub struct UserProfile {
 
     #[pb(index = 3)]
     pub name: String,
+
+    #[pb(index = 4)]
+    pub token: String,
 }
 
 use crate::{
@@ -42,6 +45,7 @@ impl std::convert::From<UserTable> for UserProfile {
             id: user.id,
             email: user.email,
             name: user.name,
+            token: user.token,
         }
     }
 }

+ 91 - 91
rust-lib/flowy-user/src/protobuf/model/auth.rs

@@ -428,7 +428,7 @@ impl ::protobuf::reflect::ProtobufValue for SignInParams {
 #[derive(PartialEq,Clone,Default)]
 pub struct SignInResponse {
     // message fields
-    pub uid: ::std::string::String,
+    pub user_id: ::std::string::String,
     pub name: ::std::string::String,
     pub email: ::std::string::String,
     pub token: ::std::string::String,
@@ -448,30 +448,30 @@ impl SignInResponse {
         ::std::default::Default::default()
     }
 
-    // string uid = 1;
+    // string user_id = 1;
 
 
-    pub fn get_uid(&self) -> &str {
-        &self.uid
+    pub fn get_user_id(&self) -> &str {
+        &self.user_id
     }
-    pub fn clear_uid(&mut self) {
-        self.uid.clear();
+    pub fn clear_user_id(&mut self) {
+        self.user_id.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_uid(&mut self, v: ::std::string::String) {
-        self.uid = v;
+    pub fn set_user_id(&mut self, v: ::std::string::String) {
+        self.user_id = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_uid(&mut self) -> &mut ::std::string::String {
-        &mut self.uid
+    pub fn mut_user_id(&mut self) -> &mut ::std::string::String {
+        &mut self.user_id
     }
 
     // Take field
-    pub fn take_uid(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.uid, ::std::string::String::new())
+    pub fn take_user_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.user_id, ::std::string::String::new())
     }
 
     // string name = 2;
@@ -563,7 +563,7 @@ impl ::protobuf::Message for SignInResponse {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.uid)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.user_id)?;
                 },
                 2 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?;
@@ -586,8 +586,8 @@ impl ::protobuf::Message for SignInResponse {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.uid.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.uid);
+        if !self.user_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.user_id);
         }
         if !self.name.is_empty() {
             my_size += ::protobuf::rt::string_size(2, &self.name);
@@ -604,8 +604,8 @@ impl ::protobuf::Message for SignInResponse {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.uid.is_empty() {
-            os.write_string(1, &self.uid)?;
+        if !self.user_id.is_empty() {
+            os.write_string(1, &self.user_id)?;
         }
         if !self.name.is_empty() {
             os.write_string(2, &self.name)?;
@@ -655,9 +655,9 @@ impl ::protobuf::Message for SignInResponse {
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "uid",
-                |m: &SignInResponse| { &m.uid },
-                |m: &mut SignInResponse| { &mut m.uid },
+                "user_id",
+                |m: &SignInResponse| { &m.user_id },
+                |m: &mut SignInResponse| { &mut m.user_id },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "name",
@@ -690,7 +690,7 @@ impl ::protobuf::Message for SignInResponse {
 
 impl ::protobuf::Clear for SignInResponse {
     fn clear(&mut self) {
-        self.uid.clear();
+        self.user_id.clear();
         self.name.clear();
         self.email.clear();
         self.token.clear();
@@ -1485,76 +1485,76 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \n\nauth.proto\"A\n\rSignInRequest\x12\x14\n\x05email\x18\x01\x20\x01(\t\
     R\x05email\x12\x1a\n\x08password\x18\x02\x20\x01(\tR\x08password\"@\n\
     \x0cSignInParams\x12\x14\n\x05email\x18\x01\x20\x01(\tR\x05email\x12\x1a\
-    \n\x08password\x18\x02\x20\x01(\tR\x08password\"b\n\x0eSignInResponse\
-    \x12\x10\n\x03uid\x18\x01\x20\x01(\tR\x03uid\x12\x12\n\x04name\x18\x02\
-    \x20\x01(\tR\x04name\x12\x14\n\x05email\x18\x03\x20\x01(\tR\x05email\x12\
-    \x14\n\x05token\x18\x04\x20\x01(\tR\x05token\"U\n\rSignUpRequest\x12\x14\
-    \n\x05email\x18\x01\x20\x01(\tR\x05email\x12\x12\n\x04name\x18\x02\x20\
-    \x01(\tR\x04name\x12\x1a\n\x08password\x18\x03\x20\x01(\tR\x08password\"\
-    T\n\x0cSignUpParams\x12\x14\n\x05email\x18\x01\x20\x01(\tR\x05email\x12\
-    \x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x1a\n\x08password\x18\x03\
-    \x20\x01(\tR\x08password\"i\n\x0eSignUpResponse\x12\x17\n\x07user_id\x18\
-    \x01\x20\x01(\tR\x06userId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\
-    \x12\x14\n\x05email\x18\x03\x20\x01(\tR\x05email\x12\x14\n\x05token\x18\
-    \x04\x20\x01(\tR\x05tokenJ\x80\t\n\x06\x12\x04\0\0\x1f\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\x15\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\
-    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
-    \x12\x03\x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\
-    \x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x18\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\x13\
-    \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\
-    \x04\x06\0\t\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x14\n\x0b\n\x04\
-    \x04\x01\x02\0\x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\
-    \x07\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\
-    \x04\x01\x02\0\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x01\x12\
-    \x03\x08\x04\x18\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\n\n\x0c\
-    \n\x05\x04\x01\x02\x01\x01\x12\x03\x08\x0b\x13\n\x0c\n\x05\x04\x01\x02\
-    \x01\x03\x12\x03\x08\x16\x17\n\n\n\x02\x04\x02\x12\x04\n\0\x0f\x01\n\n\n\
-    \x03\x04\x02\x01\x12\x03\n\x08\x16\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\
-    \x04\x13\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\
-    \x02\x02\0\x01\x12\x03\x0b\x0b\x0e\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\
-    \x0b\x11\x12\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\
-    \x04\x02\x02\x01\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\
-    \x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0c\x12\x13\
-    \n\x0b\n\x04\x04\x02\x02\x02\x12\x03\r\x04\x15\n\x0c\n\x05\x04\x02\x02\
-    \x02\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\r\x0b\
-    \x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\r\x13\x14\n\x0b\n\x04\x04\
-    \x02\x02\x03\x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\
-    \x0e\x04\n\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x0e\x0b\x10\n\x0c\n\
-    \x05\x04\x02\x02\x03\x03\x12\x03\x0e\x13\x14\n\n\n\x02\x04\x03\x12\x04\
-    \x10\0\x14\x01\n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\x15\n\x0b\n\x04\x04\
-    \x03\x02\0\x12\x03\x11\x04\x15\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x11\
-    \x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\x0b\x10\n\x0c\n\x05\x04\
-    \x03\x02\0\x03\x12\x03\x11\x13\x14\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\
-    \x12\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x12\x04\n\n\x0c\n\
-    \x05\x04\x03\x02\x01\x01\x12\x03\x12\x0b\x0f\n\x0c\n\x05\x04\x03\x02\x01\
-    \x03\x12\x03\x12\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x13\x04\x18\
-    \n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x03\
-    \x02\x02\x01\x12\x03\x13\x0b\x13\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\
-    \x13\x16\x17\n\n\n\x02\x04\x04\x12\x04\x15\0\x19\x01\n\n\n\x03\x04\x04\
-    \x01\x12\x03\x15\x08\x14\n\x0b\n\x04\x04\x04\x02\0\x12\x03\x16\x04\x15\n\
-    \x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x16\x04\n\n\x0c\n\x05\x04\x04\x02\0\
-    \x01\x12\x03\x16\x0b\x10\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x16\x13\
-    \x14\n\x0b\n\x04\x04\x04\x02\x01\x12\x03\x17\x04\x14\n\x0c\n\x05\x04\x04\
-    \x02\x01\x05\x12\x03\x17\x04\n\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\
-    \x17\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x03\x12\x03\x17\x12\x13\n\x0b\n\
-    \x04\x04\x04\x02\x02\x12\x03\x18\x04\x18\n\x0c\n\x05\x04\x04\x02\x02\x05\
-    \x12\x03\x18\x04\n\n\x0c\n\x05\x04\x04\x02\x02\x01\x12\x03\x18\x0b\x13\n\
-    \x0c\n\x05\x04\x04\x02\x02\x03\x12\x03\x18\x16\x17\n\n\n\x02\x04\x05\x12\
-    \x04\x1a\0\x1f\x01\n\n\n\x03\x04\x05\x01\x12\x03\x1a\x08\x16\n\x0b\n\x04\
-    \x04\x05\x02\0\x12\x03\x1b\x04\x17\n\x0c\n\x05\x04\x05\x02\0\x05\x12\x03\
-    \x1b\x04\n\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03\x1b\x0b\x12\n\x0c\n\x05\
-    \x04\x05\x02\0\x03\x12\x03\x1b\x15\x16\n\x0b\n\x04\x04\x05\x02\x01\x12\
-    \x03\x1c\x04\x14\n\x0c\n\x05\x04\x05\x02\x01\x05\x12\x03\x1c\x04\n\n\x0c\
-    \n\x05\x04\x05\x02\x01\x01\x12\x03\x1c\x0b\x0f\n\x0c\n\x05\x04\x05\x02\
-    \x01\x03\x12\x03\x1c\x12\x13\n\x0b\n\x04\x04\x05\x02\x02\x12\x03\x1d\x04\
-    \x15\n\x0c\n\x05\x04\x05\x02\x02\x05\x12\x03\x1d\x04\n\n\x0c\n\x05\x04\
-    \x05\x02\x02\x01\x12\x03\x1d\x0b\x10\n\x0c\n\x05\x04\x05\x02\x02\x03\x12\
-    \x03\x1d\x13\x14\n\x0b\n\x04\x04\x05\x02\x03\x12\x03\x1e\x04\x15\n\x0c\n\
-    \x05\x04\x05\x02\x03\x05\x12\x03\x1e\x04\n\n\x0c\n\x05\x04\x05\x02\x03\
-    \x01\x12\x03\x1e\x0b\x10\n\x0c\n\x05\x04\x05\x02\x03\x03\x12\x03\x1e\x13\
-    \x14b\x06proto3\
+    \n\x08password\x18\x02\x20\x01(\tR\x08password\"i\n\x0eSignInResponse\
+    \x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x12\n\x04name\
+    \x18\x02\x20\x01(\tR\x04name\x12\x14\n\x05email\x18\x03\x20\x01(\tR\x05e\
+    mail\x12\x14\n\x05token\x18\x04\x20\x01(\tR\x05token\"U\n\rSignUpRequest\
+    \x12\x14\n\x05email\x18\x01\x20\x01(\tR\x05email\x12\x12\n\x04name\x18\
+    \x02\x20\x01(\tR\x04name\x12\x1a\n\x08password\x18\x03\x20\x01(\tR\x08pa\
+    ssword\"T\n\x0cSignUpParams\x12\x14\n\x05email\x18\x01\x20\x01(\tR\x05em\
+    ail\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x1a\n\x08password\
+    \x18\x03\x20\x01(\tR\x08password\"i\n\x0eSignUpResponse\x12\x17\n\x07use\
+    r_id\x18\x01\x20\x01(\tR\x06userId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\
+    \x04name\x12\x14\n\x05email\x18\x03\x20\x01(\tR\x05email\x12\x14\n\x05to\
+    ken\x18\x04\x20\x01(\tR\x05tokenJ\x80\t\n\x06\x12\x04\0\0\x1f\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\x15\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
+    \x04\x15\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\
+    \x02\0\x01\x12\x03\x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
+    \x13\x14\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x18\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\x13\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x16\x17\n\n\n\x02\x04\
+    \x01\x12\x04\x06\0\t\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x14\n\x0b\
+    \n\x04\x04\x01\x02\0\x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\0\x05\
+    \x12\x03\x07\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x10\n\
+    \x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\
+    \x01\x12\x03\x08\x04\x18\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x08\x0b\x13\n\x0c\n\x05\x04\
+    \x01\x02\x01\x03\x12\x03\x08\x16\x17\n\n\n\x02\x04\x02\x12\x04\n\0\x0f\
+    \x01\n\n\n\x03\x04\x02\x01\x12\x03\n\x08\x16\n\x0b\n\x04\x04\x02\x02\0\
+    \x12\x03\x0b\x04\x17\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\
+    \x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0b\x0b\x12\n\x0c\n\x05\x04\x02\x02\
+    \0\x03\x12\x03\x0b\x15\x16\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0c\x04\
+    \x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\
+    \x02\x02\x01\x01\x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\
+    \x03\x0c\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\r\x04\x15\n\x0c\n\
+    \x05\x04\x02\x02\x02\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\
+    \x12\x03\r\x0b\x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\r\x13\x14\n\
+    \x0b\n\x04\x04\x02\x02\x03\x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\x02\x02\
+    \x03\x05\x12\x03\x0e\x04\n\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x0e\
+    \x0b\x10\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x0e\x13\x14\n\n\n\x02\
+    \x04\x03\x12\x04\x10\0\x14\x01\n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\x15\
+    \n\x0b\n\x04\x04\x03\x02\0\x12\x03\x11\x04\x15\n\x0c\n\x05\x04\x03\x02\0\
+    \x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\x0b\x10\
+    \n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x11\x13\x14\n\x0b\n\x04\x04\x03\
+    \x02\x01\x12\x03\x12\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x12\
+    \x04\n\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x12\x0b\x0f\n\x0c\n\x05\
+    \x04\x03\x02\x01\x03\x12\x03\x12\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\
+    \x03\x13\x04\x18\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x13\x04\n\n\x0c\
+    \n\x05\x04\x03\x02\x02\x01\x12\x03\x13\x0b\x13\n\x0c\n\x05\x04\x03\x02\
+    \x02\x03\x12\x03\x13\x16\x17\n\n\n\x02\x04\x04\x12\x04\x15\0\x19\x01\n\n\
+    \n\x03\x04\x04\x01\x12\x03\x15\x08\x14\n\x0b\n\x04\x04\x04\x02\0\x12\x03\
+    \x16\x04\x15\n\x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x16\x04\n\n\x0c\n\x05\
+    \x04\x04\x02\0\x01\x12\x03\x16\x0b\x10\n\x0c\n\x05\x04\x04\x02\0\x03\x12\
+    \x03\x16\x13\x14\n\x0b\n\x04\x04\x04\x02\x01\x12\x03\x17\x04\x14\n\x0c\n\
+    \x05\x04\x04\x02\x01\x05\x12\x03\x17\x04\n\n\x0c\n\x05\x04\x04\x02\x01\
+    \x01\x12\x03\x17\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x03\x12\x03\x17\x12\
+    \x13\n\x0b\n\x04\x04\x04\x02\x02\x12\x03\x18\x04\x18\n\x0c\n\x05\x04\x04\
+    \x02\x02\x05\x12\x03\x18\x04\n\n\x0c\n\x05\x04\x04\x02\x02\x01\x12\x03\
+    \x18\x0b\x13\n\x0c\n\x05\x04\x04\x02\x02\x03\x12\x03\x18\x16\x17\n\n\n\
+    \x02\x04\x05\x12\x04\x1a\0\x1f\x01\n\n\n\x03\x04\x05\x01\x12\x03\x1a\x08\
+    \x16\n\x0b\n\x04\x04\x05\x02\0\x12\x03\x1b\x04\x17\n\x0c\n\x05\x04\x05\
+    \x02\0\x05\x12\x03\x1b\x04\n\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03\x1b\
+    \x0b\x12\n\x0c\n\x05\x04\x05\x02\0\x03\x12\x03\x1b\x15\x16\n\x0b\n\x04\
+    \x04\x05\x02\x01\x12\x03\x1c\x04\x14\n\x0c\n\x05\x04\x05\x02\x01\x05\x12\
+    \x03\x1c\x04\n\n\x0c\n\x05\x04\x05\x02\x01\x01\x12\x03\x1c\x0b\x0f\n\x0c\
+    \n\x05\x04\x05\x02\x01\x03\x12\x03\x1c\x12\x13\n\x0b\n\x04\x04\x05\x02\
+    \x02\x12\x03\x1d\x04\x15\n\x0c\n\x05\x04\x05\x02\x02\x05\x12\x03\x1d\x04\
+    \n\n\x0c\n\x05\x04\x05\x02\x02\x01\x12\x03\x1d\x0b\x10\n\x0c\n\x05\x04\
+    \x05\x02\x02\x03\x12\x03\x1d\x13\x14\n\x0b\n\x04\x04\x05\x02\x03\x12\x03\
+    \x1e\x04\x15\n\x0c\n\x05\x04\x05\x02\x03\x05\x12\x03\x1e\x04\n\n\x0c\n\
+    \x05\x04\x05\x02\x03\x01\x12\x03\x1e\x0b\x10\n\x0c\n\x05\x04\x05\x02\x03\
+    \x03\x12\x03\x1e\x13\x14b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 109 - 64
rust-lib/flowy-user/src/protobuf/model/user_profile.rs

@@ -188,6 +188,7 @@ pub struct UserProfile {
     pub id: ::std::string::String,
     pub email: ::std::string::String,
     pub name: ::std::string::String,
+    pub token: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -281,6 +282,32 @@ impl UserProfile {
     pub fn take_name(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.name, ::std::string::String::new())
     }
+
+    // string token = 4;
+
+
+    pub fn get_token(&self) -> &str {
+        &self.token
+    }
+    pub fn clear_token(&mut self) {
+        self.token.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_token(&mut self, v: ::std::string::String) {
+        self.token = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_token(&mut self) -> &mut ::std::string::String {
+        &mut self.token
+    }
+
+    // Take field
+    pub fn take_token(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.token, ::std::string::String::new())
+    }
 }
 
 impl ::protobuf::Message for UserProfile {
@@ -301,6 +328,9 @@ impl ::protobuf::Message for UserProfile {
                 3 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?;
                 },
+                4 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.token)?;
+                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -322,6 +352,9 @@ impl ::protobuf::Message for UserProfile {
         if !self.name.is_empty() {
             my_size += ::protobuf::rt::string_size(3, &self.name);
         }
+        if !self.token.is_empty() {
+            my_size += ::protobuf::rt::string_size(4, &self.token);
+        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -337,6 +370,9 @@ impl ::protobuf::Message for UserProfile {
         if !self.name.is_empty() {
             os.write_string(3, &self.name)?;
         }
+        if !self.token.is_empty() {
+            os.write_string(4, &self.token)?;
+        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -390,6 +426,11 @@ impl ::protobuf::Message for UserProfile {
                 |m: &UserProfile| { &m.name },
                 |m: &mut UserProfile| { &mut m.name },
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "token",
+                |m: &UserProfile| { &m.token },
+                |m: &mut UserProfile| { &mut m.token },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<UserProfile>(
                 "UserProfile",
                 fields,
@@ -409,6 +450,7 @@ impl ::protobuf::Clear for UserProfile {
         self.id.clear();
         self.email.clear();
         self.name.clear();
+        self.token.clear();
         self.unknown_fields.clear();
     }
 }
@@ -1286,72 +1328,75 @@ impl ::protobuf::reflect::ProtobufValue for UserStatus {
 
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x12user_profile.proto\"!\n\tUserToken\x12\x14\n\x05token\x18\x01\x20\
-    \x01(\tR\x05token\"G\n\x0bUserProfile\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
+    \x01(\tR\x05token\"]\n\x0bUserProfile\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
     R\x02id\x12\x14\n\x05email\x18\x02\x20\x01(\tR\x05email\x12\x12\n\x04nam\
-    e\x18\x03\x20\x01(\tR\x04name\"\xa1\x01\n\x11UpdateUserRequest\x12\x0e\n\
-    \x02id\x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0\
-    R\x04name\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\
+    e\x18\x03\x20\x01(\tR\x04name\x12\x14\n\x05token\x18\x04\x20\x01(\tR\x05\
+    token\"\xa1\x01\n\x11UpdateUserRequest\x12\x0e\n\x02id\x18\x01\x20\x01(\
+    \tR\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04name\x12\x16\n\x05\
+    email\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\x08password\x18\x04\
+    \x20\x01(\tH\x02R\x08passwordB\r\n\x0bone_of_nameB\x0e\n\x0cone_of_email\
+    B\x11\n\x0fone_of_password\"\xa0\x01\n\x10UpdateUserParams\x12\x0e\n\x02\
+    id\x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\
+    \x04name\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\x05email\x12\x1c\n\
     \x08password\x18\x04\x20\x01(\tH\x02R\x08passwordB\r\n\x0bone_of_nameB\
-    \x0e\n\x0cone_of_emailB\x11\n\x0fone_of_password\"\xa0\x01\n\x10UpdateUs\
-    erParams\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x14\n\x04name\x18\
-    \x02\x20\x01(\tH\0R\x04name\x12\x16\n\x05email\x18\x03\x20\x01(\tH\x01R\
-    \x05email\x12\x1c\n\x08password\x18\x04\x20\x01(\tH\x02R\x08passwordB\r\
-    \n\x0bone_of_nameB\x0e\n\x0cone_of_emailB\x11\n\x0fone_of_password*1\n\n\
-    UserStatus\x12\x0b\n\x07Unknown\x10\0\x12\t\n\x05Login\x10\x01\x12\x0b\n\
-    \x07Expired\x10\x02J\xbb\x08\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\x04\x01\n\n\n\x03\x04\0\
-    \x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\
-    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
-    \x12\x03\x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\n\
-    \n\x02\x04\x01\x12\x04\x05\0\t\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\
-    \x13\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x12\n\x0c\n\x05\x04\x01\
-    \x02\0\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\
-    \x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x06\x10\x11\n\x0b\n\x04\x04\
-    \x01\x02\x01\x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\
-    \x07\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x07\x0b\x10\n\x0c\n\
-    \x05\x04\x01\x02\x01\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x02\
-    \x12\x03\x08\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x08\x04\n\n\
-    \x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x08\x0b\x0f\n\x0c\n\x05\x04\x01\
-    \x02\x02\x03\x12\x03\x08\x12\x13\n\n\n\x02\x04\x02\x12\x04\n\0\x0f\x01\n\
-    \n\n\x03\x04\x02\x01\x12\x03\n\x08\x19\n\x0b\n\x04\x04\x02\x02\0\x12\x03\
-    \x0b\x04\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\
-    \x04\x02\x02\0\x01\x12\x03\x0b\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\
-    \x03\x0b\x10\x11\n\x0b\n\x04\x04\x02\x08\0\x12\x03\x0c\x04*\n\x0c\n\x05\
-    \x04\x02\x08\0\x01\x12\x03\x0c\n\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\
-    \x0c\x18(\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0c\x18\x1e\n\x0c\n\
-    \x05\x04\x02\x02\x01\x01\x12\x03\x0c\x1f#\n\x0c\n\x05\x04\x02\x02\x01\
-    \x03\x12\x03\x0c&'\n\x0b\n\x04\x04\x02\x08\x01\x12\x03\r\x04,\n\x0c\n\
-    \x05\x04\x02\x08\x01\x01\x12\x03\r\n\x16\n\x0b\n\x04\x04\x02\x02\x02\x12\
-    \x03\r\x19*\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\r\x19\x1f\n\x0c\n\
-    \x05\x04\x02\x02\x02\x01\x12\x03\r\x20%\n\x0c\n\x05\x04\x02\x02\x02\x03\
-    \x12\x03\r()\n\x0b\n\x04\x04\x02\x08\x02\x12\x03\x0e\x042\n\x0c\n\x05\
-    \x04\x02\x08\x02\x01\x12\x03\x0e\n\x19\n\x0b\n\x04\x04\x02\x02\x03\x12\
-    \x03\x0e\x1c0\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\x0e\x1c\"\n\x0c\n\
-    \x05\x04\x02\x02\x03\x01\x12\x03\x0e#+\n\x0c\n\x05\x04\x02\x02\x03\x03\
-    \x12\x03\x0e./\n\n\n\x02\x04\x03\x12\x04\x10\0\x15\x01\n\n\n\x03\x04\x03\
-    \x01\x12\x03\x10\x08\x18\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x11\x04\x12\n\
-    \x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x03\x02\0\
-    \x01\x12\x03\x11\x0b\r\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x11\x10\x11\
-    \n\x0b\n\x04\x04\x03\x08\0\x12\x03\x12\x04*\n\x0c\n\x05\x04\x03\x08\0\
-    \x01\x12\x03\x12\n\x15\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x12\x18(\n\
-    \x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x12\x18\x1e\n\x0c\n\x05\x04\x03\
-    \x02\x01\x01\x12\x03\x12\x1f#\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\
-    \x12&'\n\x0b\n\x04\x04\x03\x08\x01\x12\x03\x13\x04,\n\x0c\n\x05\x04\x03\
-    \x08\x01\x01\x12\x03\x13\n\x16\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x13\
-    \x19*\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x13\x19\x1f\n\x0c\n\x05\
-    \x04\x03\x02\x02\x01\x12\x03\x13\x20%\n\x0c\n\x05\x04\x03\x02\x02\x03\
-    \x12\x03\x13()\n\x0b\n\x04\x04\x03\x08\x02\x12\x03\x14\x042\n\x0c\n\x05\
-    \x04\x03\x08\x02\x01\x12\x03\x14\n\x19\n\x0b\n\x04\x04\x03\x02\x03\x12\
-    \x03\x14\x1c0\n\x0c\n\x05\x04\x03\x02\x03\x05\x12\x03\x14\x1c\"\n\x0c\n\
-    \x05\x04\x03\x02\x03\x01\x12\x03\x14#+\n\x0c\n\x05\x04\x03\x02\x03\x03\
-    \x12\x03\x14./\n\n\n\x02\x05\0\x12\x04\x16\0\x1a\x01\n\n\n\x03\x05\0\x01\
-    \x12\x03\x16\x05\x0f\n\x0b\n\x04\x05\0\x02\0\x12\x03\x17\x04\x10\n\x0c\n\
-    \x05\x05\0\x02\0\x01\x12\x03\x17\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\
-    \x03\x17\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x18\x04\x0e\n\x0c\n\
-    \x05\x05\0\x02\x01\x01\x12\x03\x18\x04\t\n\x0c\n\x05\x05\0\x02\x01\x02\
-    \x12\x03\x18\x0c\r\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x19\x04\x10\n\x0c\n\
-    \x05\x05\0\x02\x02\x01\x12\x03\x19\x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\
-    \x12\x03\x19\x0e\x0fb\x06proto3\
+    \x0e\n\x0cone_of_emailB\x11\n\x0fone_of_password*1\n\nUserStatus\x12\x0b\
+    \n\x07Unknown\x10\0\x12\t\n\x05Login\x10\x01\x12\x0b\n\x07Expired\x10\
+    \x02J\xf2\x08\n\x06\x12\x04\0\0\x1b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\
+    \n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\
+    \x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\x04\0\
+    \x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\
+    \x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\n\n\x02\x04\x01\
+    \x12\x04\x05\0\n\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x13\n\x0b\n\
+    \x04\x04\x01\x02\0\x12\x03\x06\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\
+    \x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x0b\r\n\x0c\n\
+    \x05\x04\x01\x02\0\x03\x12\x03\x06\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\
+    \x12\x03\x07\x04\x15\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x07\x04\n\n\
+    \x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x07\x0b\x10\n\x0c\n\x05\x04\x01\
+    \x02\x01\x03\x12\x03\x07\x13\x14\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x08\
+    \x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x08\x04\n\n\x0c\n\x05\
+    \x04\x01\x02\x02\x01\x12\x03\x08\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\x03\
+    \x12\x03\x08\x12\x13\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\t\x04\x15\n\x0c\
+    \n\x05\x04\x01\x02\x03\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\x03\
+    \x01\x12\x03\t\x0b\x10\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\t\x13\x14\
+    \n\n\n\x02\x04\x02\x12\x04\x0b\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\
+    \x0b\x08\x19\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0c\x04\x12\n\x0c\n\x05\
+    \x04\x02\x02\0\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\
+    \x03\x0c\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0c\x10\x11\n\x0b\n\
+    \x04\x04\x02\x08\0\x12\x03\r\x04*\n\x0c\n\x05\x04\x02\x08\0\x01\x12\x03\
+    \r\n\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\r\x18(\n\x0c\n\x05\x04\x02\
+    \x02\x01\x05\x12\x03\r\x18\x1e\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\r\
+    \x1f#\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\r&'\n\x0b\n\x04\x04\x02\
+    \x08\x01\x12\x03\x0e\x04,\n\x0c\n\x05\x04\x02\x08\x01\x01\x12\x03\x0e\n\
+    \x16\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x0e\x19*\n\x0c\n\x05\x04\x02\
+    \x02\x02\x05\x12\x03\x0e\x19\x1f\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\
+    \x0e\x20%\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x0e()\n\x0b\n\x04\x04\
+    \x02\x08\x02\x12\x03\x0f\x042\n\x0c\n\x05\x04\x02\x08\x02\x01\x12\x03\
+    \x0f\n\x19\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x0f\x1c0\n\x0c\n\x05\x04\
+    \x02\x02\x03\x05\x12\x03\x0f\x1c\"\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\
+    \x03\x0f#+\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x0f./\n\n\n\x02\x04\
+    \x03\x12\x04\x11\0\x16\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\x18\n\
+    \x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x12\n\x0c\n\x05\x04\x03\x02\0\
+    \x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x0b\r\n\
+    \x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x12\x10\x11\n\x0b\n\x04\x04\x03\x08\
+    \0\x12\x03\x13\x04*\n\x0c\n\x05\x04\x03\x08\0\x01\x12\x03\x13\n\x15\n\
+    \x0b\n\x04\x04\x03\x02\x01\x12\x03\x13\x18(\n\x0c\n\x05\x04\x03\x02\x01\
+    \x05\x12\x03\x13\x18\x1e\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x13\x1f\
+    #\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x13&'\n\x0b\n\x04\x04\x03\x08\
+    \x01\x12\x03\x14\x04,\n\x0c\n\x05\x04\x03\x08\x01\x01\x12\x03\x14\n\x16\
+    \n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x14\x19*\n\x0c\n\x05\x04\x03\x02\
+    \x02\x05\x12\x03\x14\x19\x1f\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\x03\x14\
+    \x20%\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x14()\n\x0b\n\x04\x04\x03\
+    \x08\x02\x12\x03\x15\x042\n\x0c\n\x05\x04\x03\x08\x02\x01\x12\x03\x15\n\
+    \x19\n\x0b\n\x04\x04\x03\x02\x03\x12\x03\x15\x1c0\n\x0c\n\x05\x04\x03\
+    \x02\x03\x05\x12\x03\x15\x1c\"\n\x0c\n\x05\x04\x03\x02\x03\x01\x12\x03\
+    \x15#+\n\x0c\n\x05\x04\x03\x02\x03\x03\x12\x03\x15./\n\n\n\x02\x05\0\x12\
+    \x04\x17\0\x1b\x01\n\n\n\x03\x05\0\x01\x12\x03\x17\x05\x0f\n\x0b\n\x04\
+    \x05\0\x02\0\x12\x03\x18\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x18\
+    \x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x18\x0e\x0f\n\x0b\n\x04\x05\
+    \0\x02\x01\x12\x03\x19\x04\x0e\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x19\
+    \x04\t\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x19\x0c\r\n\x0b\n\x04\x05\0\
+    \x02\x02\x12\x03\x1a\x04\x10\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x1a\
+    \x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x1a\x0e\x0fb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 1
rust-lib/flowy-user/src/protobuf/proto/auth.proto

@@ -9,7 +9,7 @@ message SignInParams {
     string password = 2;
 }
 message SignInResponse {
-    string uid = 1;
+    string user_id = 1;
     string name = 2;
     string email = 3;
     string token = 4;

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

@@ -7,6 +7,7 @@ message UserProfile {
     string id = 1;
     string email = 2;
     string name = 3;
+    string token = 4;
 }
 message UpdateUserRequest {
     string id = 1;

+ 10 - 5
rust-lib/flowy-user/src/services/server/server_api.rs

@@ -48,23 +48,28 @@ use flowy_net::response::FlowyResponse;
 use lazy_static::lazy_static;
 use std::sync::Arc;
 lazy_static! {
-    static ref IDDLEWARE: Arc<Middleware> = Arc::new(Middleware {});
+    static ref MIDDLEWARE: Arc<Middleware> = Arc::new(Middleware {});
 }
 
 struct Middleware {}
 impl ResponseMiddleware for Middleware {
-    fn receive_response(&self, response: &FlowyResponse) {
+    fn receive_response(&self, token: &Option<String>, response: &FlowyResponse) {
         if let Some(error) = &response.error {
             if error.is_unauthorized() {
                 log::error!("user unauthorized");
-                let error = UserError::new(ErrorCode::UserUnauthorized, "");
-                observable("", UserObservable::UserUnauthorized).error(error).build()
+                match token {
+                    None => {},
+                    Some(token) => {
+                        let error = UserError::new(ErrorCode::UserUnauthorized, "");
+                        observable(token, UserObservable::UserUnauthorized).error(error).build()
+                    },
+                }
             }
         }
     }
 }
 
-pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(IDDLEWARE.clone()) }
+pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(MIDDLEWARE.clone()) }
 
 pub async fn user_sign_up_request(params: SignUpParams, url: &str) -> Result<SignUpResponse, UserError> {
     let response = request_builder()

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

@@ -27,7 +27,7 @@ impl UserServerAPI for UserServerMock {
         let user_id = uuid();
         ResultFuture::new(async {
             Ok(SignInResponse {
-                uid: user_id.clone(),
+                user_id: user_id.clone(),
                 name: "fake name".to_owned(),
                 email: params.email,
                 token: user_id,

+ 5 - 6
rust-lib/flowy-user/src/services/user/user_session.rs

@@ -73,7 +73,7 @@ impl UserSession {
             self.user_profile().await
         } else {
             let resp = self.server.sign_in(params).await?;
-            let session = Session::new(&resp.uid, &resp.token, &resp.email);
+            let session = Session::new(&resp.user_id, &resp.token, &resp.email);
             let _ = self.set_session(Some(session))?;
             let user_table = self.save_user(resp.into()).await?;
             let user_profile = UserProfile::from(user_table);
@@ -122,7 +122,7 @@ impl UserSession {
             .filter(user_table::id.eq(&user_id))
             .first::<UserTable>(&*(self.db_conn()?))?;
 
-        let _ = self.read_user_profile_on_server(&token, &user_id).await?;
+        let _ = self.read_user_profile_on_server(&token).await?;
         Ok(UserProfile::from(user))
     }
 
@@ -137,18 +137,17 @@ impl UserSession {
 }
 
 impl UserSession {
-    async fn read_user_profile_on_server(&self, token: &str, user_id: &str) -> Result<(), UserError> {
+    async fn read_user_profile_on_server(&self, token: &str) -> Result<(), UserError> {
         let server = self.server.clone();
         let token = token.to_owned();
-        let user_id = user_id.to_owned();
         tokio::spawn(async move {
             match server.get_user(&token).await {
                 Ok(profile) => {
-                    observable(&user_id, UserObservable::UserProfileUpdated).payload(profile).build();
+                    observable(&token, UserObservable::UserProfileUpdated).payload(profile).build();
                 },
                 Err(e) => {
                     log::error!("{:?}", e);
-                    observable(&user_id, UserObservable::UserProfileUpdated).error(e).build();
+                    observable(&token, UserObservable::UserProfileUpdated).error(e).build();
                 },
             }
         });

+ 2 - 2
rust-lib/flowy-user/src/sql_tables/user.rs

@@ -29,11 +29,11 @@ impl UserTable {
 }
 
 impl std::convert::From<SignUpResponse> for UserTable {
-    fn from(resp: SignUpResponse) -> Self { UserTable::new(resp.user_id, resp.name, resp.email, "".to_owned()) }
+    fn from(resp: SignUpResponse) -> Self { UserTable::new(resp.user_id, resp.name, resp.email, resp.token) }
 }
 
 impl std::convert::From<SignInResponse> for UserTable {
-    fn from(resp: SignInResponse) -> Self { UserTable::new(resp.uid, resp.name, resp.email, resp.token) }
+    fn from(resp: SignInResponse) -> Self { UserTable::new(resp.user_id, resp.name, resp.email, resp.token) }
 }
 
 #[derive(AsChangeset, Identifiable, Default, Debug)]

+ 9 - 3
rust-lib/flowy-workspace/src/services/server/server_api.rs

@@ -95,12 +95,18 @@ use crate::{errors::ErrorCode, observable::*};
 
 struct WorkspaceMiddleware {}
 impl ResponseMiddleware for WorkspaceMiddleware {
-    fn receive_response(&self, response: &FlowyResponse) {
+    fn receive_response(&self, token: &Option<String>, response: &FlowyResponse) {
         if let Some(error) = &response.error {
             if error.is_unauthorized() {
                 log::error!("workspace user is unauthorized");
-                let error = WorkspaceError::new(ErrorCode::UserUnauthorized, "");
-                observable("", WorkspaceObservable::UserUnauthorized).error(error).build()
+
+                match token {
+                    None => {},
+                    Some(token) => {
+                        let error = WorkspaceError::new(ErrorCode::UserUnauthorized, "");
+                        observable(token, WorkspaceObservable::UserUnauthorized).error(error).build()
+                    },
+                }
             }
         }
     }

+ 13 - 15
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -1,23 +1,20 @@
 use crate::{
-    entities::{app::App, workspace::*},
+    entities::{
+        app::{App, RepeatedApp},
+        workspace::*,
+    },
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
-    observable::observable,
+    observable::{observable, WorkspaceObservable},
     services::{helper::spawn, server::Server, AppController},
-    sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
-};
-
-use flowy_infra::kv::KV;
-
-use crate::{
-    entities::app::RepeatedApp,
-    observable::WorkspaceObservable,
     sql_tables::{
         app::{AppTable, AppTableSql},
         view::{ViewTable, ViewTableSql},
+        workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
     },
 };
 use flowy_database::SqliteConnection;
+use flowy_infra::kv::KV;
 use std::sync::Arc;
 
 pub(crate) struct WorkspaceController {
@@ -54,6 +51,7 @@ impl WorkspaceController {
     pub(crate) async fn create_workspace(&self, params: CreateWorkspaceParams) -> Result<Workspace, WorkspaceError> {
         let workspace = self.create_workspace_on_server(params.clone()).await?;
         let user_id = self.user.user_id()?;
+        let token = self.user.token()?;
         let workspace_table = WorkspaceTable::new(workspace.clone(), &user_id);
         let conn = &*self.database.db_connection()?;
         //[[immediate_transaction]]
@@ -70,7 +68,7 @@ impl WorkspaceController {
         (conn).immediate_transaction::<_, WorkspaceError, _>(|| {
             self.workspace_sql.create_workspace(workspace_table, conn)?;
             let repeated_workspace = self.read_local_workspaces(None, &user_id, conn)?;
-            observable(&user_id, WorkspaceObservable::UserCreateWorkspace)
+            observable(&token, WorkspaceObservable::UserCreateWorkspace)
                 .payload(repeated_workspace)
                 .build();
 
@@ -102,12 +100,13 @@ impl WorkspaceController {
 
     pub(crate) async fn delete_workspace(&self, workspace_id: &str) -> Result<(), WorkspaceError> {
         let user_id = self.user.user_id()?;
+        let token = self.user.token()?;
         let _ = self.delete_workspace_on_server(workspace_id).await?;
         let conn = &*self.database.db_connection()?;
         (conn).immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.workspace_sql.delete_workspace(workspace_id, conn)?;
             let repeated_workspace = self.read_local_workspaces(None, &user_id, conn)?;
-            observable(&user_id, WorkspaceObservable::UserDeleteWorkspace)
+            observable(&token, WorkspaceObservable::UserDeleteWorkspace)
                 .payload(repeated_workspace)
                 .build();
 
@@ -263,8 +262,6 @@ impl WorkspaceController {
         spawn(async move {
             // Opti: retry?
             let workspaces = server.read_workspace(&token, params).await?;
-
-            // TODO: rollback if fail
             let _ = (&*conn).immediate_transaction::<_, WorkspaceError, _>(|| {
                 log::debug!("Save {} workspace", workspaces.len());
                 for workspace in &workspaces.items {
@@ -292,7 +289,8 @@ impl WorkspaceController {
                 }
                 Ok(())
             })?;
-            observable(&user_id, WorkspaceObservable::WorkspaceListUpdated)
+
+            observable(&token, WorkspaceObservable::WorkspaceListUpdated)
                 .payload(workspaces)
                 .build();
             Result::<(), WorkspaceError>::Ok(())

+ 7 - 1
rust-lib/flowy-workspace/src/sql_tables/view/view_sql.rs

@@ -12,7 +12,13 @@ pub struct ViewTableSql {}
 
 impl ViewTableSql {
     pub(crate) fn create_view(&self, view_table: ViewTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
-        let _ = diesel::insert_into(view_table::table).values(view_table).execute(conn)?;
+        match diesel_record_count!(view_table, &view_table.id, conn) {
+            0 => diesel_insert_table!(view_table, &view_table, conn),
+            _ => {
+                let changeset = ViewTableChangeset::from_table(view_table);
+                diesel_update_table!(view_table, changeset, conn)
+            },
+        }
         Ok(())
     }
 

+ 13 - 2
rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs

@@ -68,7 +68,7 @@ impl std::convert::Into<View> for ViewTable {
 
 #[derive(AsChangeset, Identifiable, Clone, Default, Debug)]
 #[table_name = "view_table"]
-pub struct ViewTableChangeset {
+pub(crate) struct ViewTableChangeset {
     pub id: String,
     pub name: Option<String>,
     pub desc: Option<String>,
@@ -78,7 +78,7 @@ pub struct ViewTableChangeset {
 }
 
 impl ViewTableChangeset {
-    pub fn new(params: UpdateViewParams) -> Self {
+    pub(crate) fn new(params: UpdateViewParams) -> Self {
         ViewTableChangeset {
             id: params.view_id,
             name: params.name,
@@ -88,6 +88,17 @@ impl ViewTableChangeset {
             is_trash: params.is_trash,
         }
     }
+
+    pub(crate) fn from_table(table: ViewTable) -> Self {
+        ViewTableChangeset {
+            id: table.id,
+            name: Some(table.name),
+            desc: Some(table.desc),
+            thumbnail: Some(table.thumbnail),
+            modified_time: table.modified_time,
+            is_trash: Some(table.is_trash),
+        }
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]