Parcourir la source

save user info to database after sign up

appflowy il y a 3 ans
Parent
commit
55454c5bec
46 fichiers modifiés avec 457 ajouts et 276 suppressions
  1. 1 0
      .idea/appflowy_client.iml
  2. 29 15
      app_flowy/packages/flowy_sdk/lib/protobuf/user.pb.dart
  3. 4 3
      app_flowy/packages/flowy_sdk/lib/protobuf/user.pbjson.dart
  4. 3 2
      rust-lib/Cargo.toml
  5. 3 7
      rust-lib/dart-ffi/src/lib.rs
  6. 0 16
      rust-lib/flowy-database/src/errors.rs
  7. 17 9
      rust-lib/flowy-database/src/lib.rs
  8. 4 4
      rust-lib/flowy-dispatch/src/data.rs
  9. 2 2
      rust-lib/flowy-dispatch/src/dispatch.rs
  10. 0 3
      rust-lib/flowy-dispatch/src/error/mod.rs
  11. 16 20
      rust-lib/flowy-dispatch/src/errors/errors.rs
  12. 3 0
      rust-lib/flowy-dispatch/src/errors/mod.rs
  13. 4 2
      rust-lib/flowy-dispatch/src/lib.rs
  14. 7 4
      rust-lib/flowy-dispatch/src/module/data.rs
  15. 9 11
      rust-lib/flowy-dispatch/src/module/module.rs
  16. 8 8
      rust-lib/flowy-dispatch/src/request/request.rs
  17. 3 3
      rust-lib/flowy-dispatch/src/response/builder.rs
  18. 2 2
      rust-lib/flowy-dispatch/src/response/responder.rs
  19. 3 3
      rust-lib/flowy-dispatch/src/response/response.rs
  20. 7 7
      rust-lib/flowy-dispatch/src/service/handler.rs
  21. 9 0
      rust-lib/flowy-infra/Cargo.toml
  22. 1 0
      rust-lib/flowy-infra/src/lib.rs
  23. 3 5
      rust-lib/flowy-sdk/src/module.rs
  24. 7 2
      rust-lib/flowy-sqlite/src/database.rs
  25. 1 6
      rust-lib/flowy-sqlite/src/pool.rs
  26. 3 0
      rust-lib/flowy-user/Cargo.toml
  27. 1 2
      rust-lib/flowy-user/src/domain/mod.rs
  28. 3 0
      rust-lib/flowy-user/src/domain/tables/mod.rs
  29. 30 0
      rust-lib/flowy-user/src/domain/tables/user_table.rs
  30. 0 2
      rust-lib/flowy-user/src/domain/user/mod.rs
  31. 0 24
      rust-lib/flowy-user/src/domain/user/user.rs
  32. 0 48
      rust-lib/flowy-user/src/domain/user_session.rs
  33. 24 13
      rust-lib/flowy-user/src/errors.rs
  34. 6 3
      rust-lib/flowy-user/src/handlers/auth.rs
  35. 5 1
      rust-lib/flowy-user/src/lib.rs
  36. 1 5
      rust-lib/flowy-user/src/module.rs
  37. 70 24
      rust-lib/flowy-user/src/protobuf/model/user.rs
  38. 4 3
      rust-lib/flowy-user/src/protobuf/proto/user.proto
  39. 21 11
      rust-lib/flowy-user/src/services/database.rs
  40. 3 0
      rust-lib/flowy-user/src/services/mod.rs
  41. 22 0
      rust-lib/flowy-user/src/services/register.rs
  42. 23 0
      rust-lib/flowy-user/src/services/user_session/builder.rs
  43. 5 0
      rust-lib/flowy-user/src/services/user_session/mod.rs
  44. 86 0
      rust-lib/flowy-user/src/services/user_session/user_session.rs
  45. 3 5
      rust-lib/flowy-user/tests/auth_test.rs
  46. 1 1
      rust-lib/flowy-user/tests/main.rs

+ 1 - 0
.idea/appflowy_client.iml

@@ -18,6 +18,7 @@
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-user/tests" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-database/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sqlite/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-infra/src" isTestSource="false" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />

+ 29 - 15
app_flowy/packages/flowy_sdk/lib/protobuf/user.pb.dart

@@ -11,19 +11,24 @@ import 'package:protobuf/protobuf.dart' as $pb;
 
 class User extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'User', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'email')
-    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'password')
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
+    ..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') ? '' : 'password')
     ..hasRequiredFields = false
   ;
 
   User._() : super();
   factory User({
+    $core.String? id,
     $core.String? name,
     $core.String? email,
     $core.String? password,
   }) {
     final _result = create();
+    if (id != null) {
+      _result.id = id;
+    }
     if (name != null) {
       _result.name = name;
     }
@@ -57,30 +62,39 @@ class User extends $pb.GeneratedMessage {
   static User? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get name => $_getSZ(0);
+  $core.String get id => $_getSZ(0);
   @$pb.TagNumber(1)
-  set name($core.String v) { $_setString(0, v); }
+  set id($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasName() => $_has(0);
+  $core.bool hasId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearName() => clearField(1);
+  void clearId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get email => $_getSZ(1);
+  $core.String get name => $_getSZ(1);
   @$pb.TagNumber(2)
-  set email($core.String v) { $_setString(1, v); }
+  set name($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasEmail() => $_has(1);
+  $core.bool hasName() => $_has(1);
   @$pb.TagNumber(2)
-  void clearEmail() => clearField(2);
+  void clearName() => clearField(2);
 
   @$pb.TagNumber(3)
-  $core.String get password => $_getSZ(2);
+  $core.String get email => $_getSZ(2);
   @$pb.TagNumber(3)
-  set password($core.String v) { $_setString(2, v); }
+  set email($core.String v) { $_setString(2, v); }
   @$pb.TagNumber(3)
-  $core.bool hasPassword() => $_has(2);
+  $core.bool hasEmail() => $_has(2);
   @$pb.TagNumber(3)
-  void clearPassword() => clearField(3);
+  void clearEmail() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get password => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set password($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasPassword() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearPassword() => clearField(4);
 }
 

+ 4 - 3
app_flowy/packages/flowy_sdk/lib/protobuf/user.pbjson.dart

@@ -9,9 +9,10 @@ import 'dart:core' as $core;
 const User$json = const {
   '1': 'User',
   '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
-    const {'1': 'email', '3': 2, '4': 1, '5': 9, '10': 'email'},
-    const {'1': 'password', '3': 3, '4': 1, '5': 9, '10': 'password'},
+    const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
+    const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'email', '3': 3, '4': 1, '5': 9, '10': 'email'},
+    const {'1': 'password', '3': 4, '4': 1, '5': 9, '10': 'password'},
   ],
 };
 

+ 3 - 2
rust-lib/Cargo.toml

@@ -8,8 +8,9 @@ members = [
   "flowy-ast",
   "flowy-derive",
   "flowy-test",
-    "flowy-sqlite",
-    "flowy-database",
+  "flowy-sqlite",
+  "flowy-database",
+  "flowy-infra",
 ]
 
 [profile.dev]

+ 3 - 7
rust-lib/dart-ffi/src/lib.rs

@@ -36,8 +36,8 @@ pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
     let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
     log::trace!(
         "[FFI]: {} Async Event: {:?} with {} port",
-        &request.id(),
-        &request.event(),
+        &request.id,
+        &request.event,
         port
     );
 
@@ -50,11 +50,7 @@ pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
 #[no_mangle]
 pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 {
     let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
-    log::trace!(
-        "[FFI]: {} Sync Event: {:?}",
-        &request.id(),
-        &request.event(),
-    );
+    log::trace!("[FFI]: {} Sync Event: {:?}", &request.id, &request.event,);
     let _response = EventDispatch::sync_send(request);
 
     // FFIResponse {  }

+ 0 - 16
rust-lib/flowy-database/src/errors.rs

@@ -1,16 +0,0 @@
-use flowy_sqlite::Error;
-use std::io;
-
-#[derive(Debug)]
-pub enum DataBaseError {
-    InitError(String),
-    IOError(String),
-}
-
-impl std::convert::From<flowy_sqlite::Error> for DataBaseError {
-    fn from(error: flowy_sqlite::Error) -> Self { DataBaseError::InitError(format!("{:?}", error)) }
-}
-
-impl std::convert::From<io::Error> for DataBaseError {
-    fn from(error: io::Error) -> Self { DataBaseError::IOError(format!("{:?}", error)) }
-}

+ 17 - 9
rust-lib/flowy-database/src/lib.rs

@@ -1,29 +1,37 @@
-mod errors;
-mod schema;
+pub mod schema;
 
 #[macro_use]
 extern crate diesel;
+pub use diesel::*;
+
 #[macro_use]
 extern crate diesel_derives;
+pub use diesel_derives::*;
+
 #[macro_use]
 extern crate diesel_migrations;
 
-pub use errors::*;
-pub use flowy_sqlite::{DBConnection, DataBase};
+pub use flowy_sqlite::{DBConnection, Database};
 
 use diesel_migrations::*;
-use flowy_sqlite::PoolConfig;
-use std::path::Path;
+use flowy_sqlite::{Error, PoolConfig};
+use std::{io, path::Path};
 
 embed_migrations!("../flowy-database/migrations/");
 pub const DB_NAME: &str = "flowy-database.db";
 
-pub fn init(storage_path: &str) -> Result<DataBase, DataBaseError> {
+pub fn init(storage_path: &str) -> Result<Database, io::Error> {
     if !Path::new(storage_path).exists() {
         std::fs::create_dir_all(storage_path)?;
     }
-
     let pool_config = PoolConfig::default();
-    let database = DataBase::new(storage_path, DB_NAME, pool_config)?;
+    let database = Database::new(storage_path, DB_NAME, pool_config).map_err(as_io_error)?;
+    let conn = database.get_connection().map_err(as_io_error)?;
+    embedded_migrations::run(&*conn);
     Ok(database)
 }
+
+fn as_io_error(e: Error) -> io::Error {
+    let msg = format!("{:?}", e);
+    io::Error::new(io::ErrorKind::NotConnected, msg)
+}

+ 4 - 4
rust-lib/flowy-dispatch/src/data.rs

@@ -1,5 +1,5 @@
 use crate::{
-    error::{InternalError, SystemError},
+    errors::{DispatchError, InternalError},
     request::{unexpected_none_payload, EventRequest, FromRequest, Payload},
     response::{EventResponse, Responder, ResponseBuilder, ToBytes},
     util::ready::{ready, Ready},
@@ -53,8 +53,8 @@ impl<T> FromRequest for Data<T>
 where
     T: FromBytes + 'static,
 {
-    type Error = SystemError;
-    type Future = Ready<Result<Self, SystemError>>;
+    type Error = DispatchError;
+    type Future = Ready<Result<Self, DispatchError>>;
 
     #[inline]
     fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
@@ -76,7 +76,7 @@ where
         match self.into_inner().into_bytes() {
             Ok(bytes) => ResponseBuilder::Ok().data(bytes.to_vec()).build(),
             Err(e) => {
-                let system_err: SystemError = InternalError::new(format!("{:?}", e)).into();
+                let system_err: DispatchError = InternalError::new(format!("{:?}", e)).into();
                 system_err.into()
             },
         }

+ 2 - 2
rust-lib/flowy-dispatch/src/dispatch.rs

@@ -1,5 +1,5 @@
 use crate::{
-    error::{Error, InternalError, SystemError},
+    errors::{DispatchError, Error, InternalError},
     module::{as_module_map, Module, ModuleMap, ModuleRequest},
     response::EventResponse,
     service::{Service, ServiceFactory},
@@ -129,7 +129,7 @@ pub(crate) struct DispatchService {
 
 impl Service<DispatchContext> for DispatchService {
     type Response = EventResponse;
-    type Error = SystemError;
+    type Error = DispatchError;
     type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
 
     #[cfg_attr(

+ 0 - 3
rust-lib/flowy-dispatch/src/error/mod.rs

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

+ 16 - 20
rust-lib/flowy-dispatch/src/error/error.rs → rust-lib/flowy-dispatch/src/errors/errors.rs

@@ -8,45 +8,43 @@ use std::{fmt, option::NoneError};
 use tokio::sync::mpsc::error::SendError;
 
 pub trait Error: fmt::Debug + fmt::Display + DynClone + Send + Sync {
-    fn status_code(&self) -> StatusCode;
-
-    fn as_response(&self) -> EventResponse { EventResponse::new(self.status_code()) }
+    fn as_response(&self) -> EventResponse { EventResponse::new(StatusCode::Err) }
 }
 
 dyn_clone::clone_trait_object!(Error);
 
-impl<T: Error + 'static> From<T> for SystemError {
-    fn from(err: T) -> SystemError {
-        SystemError {
+impl<T: Error + 'static> From<T> for DispatchError {
+    fn from(err: T) -> DispatchError {
+        DispatchError {
             inner: Box::new(err),
         }
     }
 }
 
 #[derive(Clone)]
-pub struct SystemError {
+pub struct DispatchError {
     inner: Box<dyn Error>,
 }
 
-impl SystemError {
+impl DispatchError {
     pub fn inner_error(&self) -> &dyn Error { self.inner.as_ref() }
 }
 
-impl fmt::Display for SystemError {
+impl fmt::Display for DispatchError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.inner, f) }
 }
 
-impl fmt::Debug for SystemError {
+impl fmt::Debug for DispatchError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", &self.inner) }
 }
 
-impl std::error::Error for SystemError {
+impl std::error::Error for DispatchError {
     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
 
     fn cause(&self) -> Option<&dyn std::error::Error> { None }
 }
 
-impl From<SendError<EventRequest>> for SystemError {
+impl From<SendError<EventRequest>> for DispatchError {
     fn from(err: SendError<EventRequest>) -> Self {
         InternalError {
             inner: format!("{}", err),
@@ -55,7 +53,7 @@ impl From<SendError<EventRequest>> for SystemError {
     }
 }
 
-impl From<NoneError> for SystemError {
+impl From<NoneError> for DispatchError {
     fn from(s: NoneError) -> Self {
         InternalError {
             inner: format!("Unexpected none: {:?}", s),
@@ -64,16 +62,16 @@ impl From<NoneError> for SystemError {
     }
 }
 
-impl From<String> for SystemError {
+impl From<String> for DispatchError {
     fn from(s: String) -> Self { InternalError { inner: s }.into() }
 }
 
-impl From<SystemError> for EventResponse {
-    fn from(err: SystemError) -> Self { err.inner_error().as_response() }
+impl From<DispatchError> for EventResponse {
+    fn from(err: DispatchError) -> Self { err.inner_error().as_response() }
 }
 
 #[derive(Clone)]
-pub struct InternalError<T: Clone> {
+pub(crate) struct InternalError<T: Clone> {
     inner: T,
 }
 
@@ -99,8 +97,6 @@ impl<T> Error for InternalError<T>
 where
     T: fmt::Debug + fmt::Display + 'static + Clone + Send + Sync,
 {
-    fn status_code(&self) -> StatusCode { StatusCode::Err }
-
     fn as_response(&self) -> EventResponse {
         let error = InternalError {
             inner: format!("{}", self.inner),
@@ -111,7 +107,7 @@ where
     }
 }
 
-impl Serialize for SystemError {
+impl Serialize for DispatchError {
     fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
     where
         S: Serializer,

+ 3 - 0
rust-lib/flowy-dispatch/src/errors/mod.rs

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

+ 4 - 2
rust-lib/flowy-dispatch/src/lib.rs

@@ -1,6 +1,6 @@
 #![feature(try_trait)]
 
-mod error;
+mod errors;
 mod module;
 mod request;
 mod response;
@@ -11,6 +11,8 @@ mod data;
 mod dispatch;
 mod system;
 
+pub use errors::Error;
+
 pub mod prelude {
-    pub use crate::{data::*, dispatch::*, error::*, module::*, request::*, response::*};
+    pub use crate::{data::*, dispatch::*, errors::*, module::*, request::*, response::*};
 }

+ 7 - 4
rust-lib/flowy-dispatch/src/module/data.rs

@@ -1,5 +1,5 @@
 use crate::{
-    error::{InternalError, SystemError},
+    errors::{DispatchError, InternalError},
     request::{payload::Payload, EventRequest, FromRequest},
     util::ready::{ready, Ready},
 };
@@ -43,15 +43,18 @@ impl<T> FromRequest for ModuleData<T>
 where
     T: ?Sized + Send + Sync + 'static,
 {
-    type Error = SystemError;
-    type Future = Ready<Result<Self, SystemError>>;
+    type Error = DispatchError;
+    type Future = Ready<Result<Self, DispatchError>>;
 
     #[inline]
     fn from_request(req: &EventRequest, _: &mut Payload) -> Self::Future {
         if let Some(data) = req.module_data::<ModuleData<T>>() {
             ready(Ok(data.clone()))
         } else {
-            let msg = format!("Failed to get the module data(type: {})", type_name::<T>());
+            let msg = format!(
+                "Failed to get the module data of type: {}",
+                type_name::<T>()
+            );
             log::error!("{}", msg,);
             ready(Err(InternalError::new(msg).into()))
         }

+ 9 - 11
rust-lib/flowy-dispatch/src/module/module.rs

@@ -12,7 +12,7 @@ use futures_core::ready;
 use pin_project::pin_project;
 
 use crate::{
-    error::{InternalError, SystemError},
+    errors::{DispatchError, InternalError},
     module::{container::ModuleDataMap, ModuleData},
     request::{payload::Payload, EventRequest, FromRequest},
     response::{EventResponse, Responder},
@@ -51,7 +51,8 @@ impl<T: Display + Eq + Hash + Debug + Clone> std::convert::From<T> for Event {
     fn from(t: T) -> Self { Event(format!("{}", t)) }
 }
 
-pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>;
+pub type EventServiceFactory =
+    BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>;
 
 pub struct Module {
     pub name: String,
@@ -111,8 +112,8 @@ impl Module {
 
 #[derive(Debug)]
 pub struct ModuleRequest {
-    pub(crate) id: String,
-    pub(crate) event: Event,
+    pub id: String,
+    pub event: Event,
     pub(crate) payload: Payload,
 }
 
@@ -145,7 +146,7 @@ impl std::fmt::Display for ModuleRequest {
 
 impl ServiceFactory<ModuleRequest> for Module {
     type Response = EventResponse;
-    type Error = SystemError;
+    type Error = DispatchError;
     type Service = BoxService<ModuleRequest, Self::Response, Self::Error>;
     type Context = ();
     type Future = BoxFuture<'static, Result<Self::Service, Self::Error>>;
@@ -171,7 +172,7 @@ pub struct ModuleService {
 
 impl Service<ModuleRequest> for ModuleService {
     type Response = EventResponse;
-    type Error = SystemError;
+    type Error = DispatchError;
     type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
 
     fn call(&self, request: ModuleRequest) -> Self::Future {
@@ -196,17 +197,14 @@ impl Service<ModuleRequest> for ModuleService {
     }
 }
 
-// type BoxModuleService = BoxService<ServiceRequest, ServiceResponse,
-// SystemError>;
-
 #[pin_project]
 pub struct ModuleServiceFuture {
     #[pin]
-    fut: BoxFuture<'static, Result<ServiceResponse, SystemError>>,
+    fut: BoxFuture<'static, Result<ServiceResponse, DispatchError>>,
 }
 
 impl Future for ModuleServiceFuture {
-    type Output = Result<EventResponse, SystemError>;
+    type Output = Result<EventResponse, DispatchError>;
 
     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
         loop {

+ 8 - 8
rust-lib/flowy-dispatch/src/request/request.rs

@@ -1,7 +1,7 @@
 use std::future::Future;
 
 use crate::{
-    error::{InternalError, SystemError},
+    errors::{DispatchError, InternalError},
     module::{Event, ModuleDataMap},
     request::payload::Payload,
     util::ready::{ready, Ready},
@@ -48,7 +48,7 @@ impl EventRequest {
 }
 
 pub trait FromRequest: Sized {
-    type Error: Into<SystemError>;
+    type Error: Into<DispatchError>;
     type Future: Future<Output = Result<Self, Self::Error>>;
 
     fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future;
@@ -56,15 +56,15 @@ pub trait FromRequest: Sized {
 
 #[doc(hidden)]
 impl FromRequest for () {
-    type Error = SystemError;
-    type Future = Ready<Result<(), SystemError>>;
+    type Error = DispatchError;
+    type Future = Ready<Result<(), DispatchError>>;
 
     fn from_request(_req: &EventRequest, _payload: &mut Payload) -> Self::Future { ready(Ok(())) }
 }
 
 #[doc(hidden)]
 impl FromRequest for String {
-    type Error = SystemError;
+    type Error = DispatchError;
     type Future = Ready<Result<Self, Self::Error>>;
 
     fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
@@ -75,7 +75,7 @@ impl FromRequest for String {
     }
 }
 
-pub fn unexpected_none_payload(request: &EventRequest) -> SystemError {
+pub fn unexpected_none_payload(request: &EventRequest) -> DispatchError {
     log::warn!("{:?} expected payload", &request.event);
     InternalError::new("Expected payload").into()
 }
@@ -85,7 +85,7 @@ impl<T> FromRequest for Result<T, T::Error>
 where
     T: FromRequest,
 {
-    type Error = SystemError;
+    type Error = DispatchError;
     type Future = FromRequestFuture<T::Future>;
 
     fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
@@ -105,7 +105,7 @@ impl<Fut, T, E> Future for FromRequestFuture<Fut>
 where
     Fut: Future<Output = Result<T, E>>,
 {
-    type Output = Result<Result<T, E>, SystemError>;
+    type Output = Result<Result<T, E>, DispatchError>;
 
     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
         let this = self.project();

+ 3 - 3
rust-lib/flowy-dispatch/src/response/builder.rs

@@ -1,5 +1,5 @@
 use crate::{
-    error::SystemError,
+    errors::DispatchError,
     request::Payload,
     response::{EventResponse, StatusCode},
 };
@@ -14,7 +14,7 @@ macro_rules! static_response {
 pub struct ResponseBuilder<T = Payload> {
     pub payload: T,
     pub status: StatusCode,
-    pub error: Option<SystemError>,
+    pub error: Option<DispatchError>,
 }
 
 impl ResponseBuilder {
@@ -31,7 +31,7 @@ impl ResponseBuilder {
         self
     }
 
-    pub fn error(mut self, error: SystemError) -> Self {
+    pub fn error(mut self, error: DispatchError) -> Self {
         self.error = Some(error);
         self
     }

+ 2 - 2
rust-lib/flowy-dispatch/src/response/responder.rs

@@ -1,5 +1,5 @@
 #[allow(unused_imports)]
-use crate::error::{InternalError, SystemError};
+use crate::errors::{DispatchError, InternalError};
 use crate::{
     request::EventRequest,
     response::{EventResponse, ResponseBuilder},
@@ -28,7 +28,7 @@ impl_responder!(Bytes);
 impl<T, E> Responder for Result<T, E>
 where
     T: Responder,
-    E: Into<SystemError>,
+    E: Into<DispatchError>,
 {
     fn respond_to(self, request: &EventRequest) -> EventResponse {
         match self {

+ 3 - 3
rust-lib/flowy-dispatch/src/response/response.rs

@@ -1,6 +1,6 @@
 use crate::{
     data::Data,
-    error::SystemError,
+    errors::DispatchError,
     request::{EventRequest, Payload},
     response::Responder,
 };
@@ -19,7 +19,7 @@ pub struct EventResponse {
     #[derivative(Debug = "ignore")]
     pub payload: Payload,
     pub status_code: StatusCode,
-    pub error: Option<SystemError>,
+    pub error: Option<DispatchError>,
 }
 
 impl EventResponse {
@@ -58,7 +58,7 @@ pub type ResponseResult<T, E> = std::result::Result<Data<T>, E>;
 
 pub fn response_ok<T, E>(data: T) -> Result<Data<T>, E>
 where
-    E: Into<SystemError>,
+    E: Into<DispatchError>,
 {
     Ok(Data(data))
 }

+ 7 - 7
rust-lib/flowy-dispatch/src/service/handler.rs

@@ -9,7 +9,7 @@ use futures_core::ready;
 use pin_project::pin_project;
 
 use crate::{
-    error::SystemError,
+    errors::DispatchError,
     request::{payload::Payload, EventRequest, FromRequest},
     response::{EventResponse, Responder},
     service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
@@ -73,7 +73,7 @@ where
     R::Output: Responder,
 {
     type Response = ServiceResponse;
-    type Error = SystemError;
+    type Error = DispatchError;
     type Service = Self;
     type Context = ();
     type Future = Ready<Result<Self::Service, Self::Error>>;
@@ -89,7 +89,7 @@ where
     R::Output: Responder,
 {
     type Response = ServiceResponse;
-    type Error = SystemError;
+    type Error = DispatchError;
     type Future = HandlerServiceFuture<H, T, R>;
 
     fn call(&self, req: ServiceRequest) -> Self::Future {
@@ -118,7 +118,7 @@ where
     R: Future + Sync + Send,
     R::Output: Responder,
 {
-    type Output = Result<ServiceResponse, SystemError>;
+    type Output = Result<ServiceResponse, DispatchError>;
 
     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
         loop {
@@ -132,7 +132,7 @@ where
                         },
                         Err(err) => {
                             let req = req.take().unwrap();
-                            let system_err: SystemError = err.into();
+                            let system_err: DispatchError = err.into();
                             let res: EventResponse = system_err.into();
                             return Poll::Ready(Ok(ServiceResponse::new(req, res)));
                         },
@@ -175,7 +175,7 @@ macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
         #[allow(unused_parens)]
         impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
         {
-            type Error = SystemError;
+            type Error = DispatchError;
             type Future = $tuple_type<$($T),+>;
 
             fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
@@ -196,7 +196,7 @@ macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
 
         impl<$($T: FromRequest),+> Future for $tuple_type<$($T),+>
         {
-            type Output = Result<($($T,)+), SystemError>;
+            type Output = Result<($($T,)+), DispatchError>;
 
             fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
                 let mut this = self.project();

+ 9 - 0
rust-lib/flowy-infra/Cargo.toml

@@ -0,0 +1,9 @@
+[package]
+name = "flowy-infra"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+uuid = { version = "0.8", features = ["serde", "v4"] }

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

@@ -0,0 +1 @@
+pub fn uuid() -> String { uuid::Uuid::new_v4().to_string() }

+ 3 - 5
rust-lib/flowy-sdk/src/module.rs

@@ -1,5 +1,5 @@
 use flowy_dispatch::prelude::Module;
-use flowy_user::prelude::user_session::{UserSession, UserSessionConfig};
+use flowy_user::prelude::{UserSession, UserSessionBuilder, UserSessionConfig};
 use std::sync::Arc;
 
 pub struct ModuleConfig {
@@ -7,8 +7,6 @@ pub struct ModuleConfig {
 }
 
 pub fn build_modules(config: ModuleConfig) -> Vec<Module> {
-    let user_config = UserSessionConfig::new(&config.root);
-    let user_session = Arc::new(UserSession::new(user_config));
-
-    vec![flowy_user::module::create(user_session)]
+    let user_session = UserSessionBuilder::new().root_dir(&config.root).build();
+    vec![flowy_user::module::create(Arc::new(user_session))]
 }

+ 7 - 2
rust-lib/flowy-sqlite/src/database.rs

@@ -4,16 +4,21 @@ use crate::{
 };
 use r2d2::PooledConnection;
 
-pub struct DataBase {
+pub struct Database {
     uri: String,
     pool: ConnectionPool,
 }
 
 pub type DBConnection = PooledConnection<ConnectionManager>;
 
-impl DataBase {
+impl Database {
     pub fn new(dir: &str, name: &str, pool_config: PoolConfig) -> Result<Self> {
         let uri = db_file_uri(dir, name);
+
+        if !std::path::PathBuf::from(dir).exists() {
+            log::error!("Create database failed. {} not exists", &dir);
+        }
+
         let pool = ConnectionPool::new(pool_config, &uri)?;
         Ok(Self { uri, pool })
     }

+ 1 - 6
rust-lib/flowy-sqlite/src/pool.rs

@@ -115,12 +115,7 @@ impl ManageConnection for ConnectionManager {
     type Connection = SqliteConnection;
     type Error = crate::Error;
 
-    fn connect(&self) -> Result<Self::Connection> {
-        if !std::path::PathBuf::from(&self.db_uri).exists() {
-            log::error!("db file not exists");
-        }
-        Ok(SqliteConnection::establish(&self.db_uri)?)
-    }
+    fn connect(&self) -> Result<Self::Connection> { Ok(SqliteConnection::establish(&self.db_uri)?) }
 
     fn is_valid(&self, conn: &mut Self::Connection) -> Result<()> {
         Ok(conn.execute("SELECT 1").map(|_| ())?)

+ 3 - 0
rust-lib/flowy-user/Cargo.toml

@@ -12,6 +12,7 @@ flowy-log = { path = "../flowy-log" }
 flowy-derive = { path = "../flowy-derive" }
 flowy-database = { path = "../flowy-database" }
 flowy-sqlite = { path = "../flowy-sqlite" }
+flowy-infra = { path = "../flowy-infra" }
 
 tracing = { version = "0.1", features = ["log"] }
 bytes = "1.0"
@@ -23,6 +24,8 @@ log = "0.4.14"
 protobuf = {version = "2.18.0"}
 lazy_static = "1.4.0"
 fancy-regex = "0.5.0"
+diesel = {version = "1.4.7", features = ["sqlite"]}
+diesel_derives = {version = "1.4.1", features = ["sqlite"]}
 
 [dev-dependencies]
 quickcheck = "0.9.2"

+ 1 - 2
rust-lib/flowy-user/src/domain/mod.rs

@@ -1,4 +1,3 @@
 pub use user::*;
+pub mod tables;
 pub mod user;
-pub mod user_db;
-pub mod user_session;

+ 3 - 0
rust-lib/flowy-user/src/domain/tables/mod.rs

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

+ 30 - 0
rust-lib/flowy-user/src/domain/tables/user_table.rs

@@ -0,0 +1,30 @@
+use crate::domain::{UserEmail, UserName, UserPassword};
+use flowy_database::schema::user_table;
+use flowy_derive::ProtoBuf;
+
+#[derive(ProtoBuf, Clone, Default, Queryable, Identifiable, Insertable)]
+#[table_name = "user_table"]
+pub struct User {
+    #[pb(index = 1)]
+    pub(crate) id: String,
+
+    #[pb(index = 2)]
+    name: String,
+
+    #[pb(index = 3)]
+    email: String,
+
+    #[pb(index = 4)]
+    password: String,
+}
+
+impl User {
+    pub fn new(id: String, name: String, email: String, password: String) -> Self {
+        Self {
+            id,
+            name,
+            email,
+            password,
+        }
+    }
+}

+ 0 - 2
rust-lib/flowy-user/src/domain/user/mod.rs

@@ -1,13 +1,11 @@
 mod sign_in;
 mod sign_up;
-mod user;
 mod user_email;
 mod user_name;
 mod user_password;
 
 pub use sign_in::*;
 pub use sign_up::*;
-pub use user::*;
 pub use user_email::*;
 pub use user_name::*;
 pub use user_password::*;

+ 0 - 24
rust-lib/flowy-user/src/domain/user/user.rs

@@ -1,24 +0,0 @@
-use crate::domain::{UserEmail, UserName, UserPassword};
-use flowy_derive::ProtoBuf;
-
-#[derive(ProtoBuf, Default)]
-pub struct User {
-    #[pb(index = 1)]
-    name: String,
-
-    #[pb(index = 2)]
-    email: String,
-
-    #[pb(index = 3)]
-    password: String,
-}
-
-impl User {
-    pub fn new(name: UserName, email: UserEmail, password: UserPassword) -> Self {
-        Self {
-            name: name.0,
-            email: email.0,
-            password: password.0,
-        }
-    }
-}

+ 0 - 48
rust-lib/flowy-user/src/domain/user_session.rs

@@ -1,48 +0,0 @@
-use crate::{domain::user_db::UserDB, errors::UserError};
-use flowy_sqlite::DBConnection;
-use lazy_static::lazy_static;
-use std::sync::RwLock;
-
-lazy_static! {
-    pub static ref CURRENT_USER_ID: RwLock<Option<String>> = RwLock::new(None);
-}
-fn get_current_user_id() -> Result<Option<String>, UserError> {
-    match CURRENT_USER_ID.read() {
-        Ok(read_guard) => Ok((*read_guard).clone()),
-        Err(e) => {
-            log::error!("Get current user id failed: {:?}", e);
-            Err(e.into())
-        },
-    }
-}
-
-pub struct UserSessionConfig {
-    root_dir: String,
-}
-
-impl UserSessionConfig {
-    pub fn new(root_dir: &str) -> Self {
-        Self {
-            root_dir: root_dir.to_owned(),
-        }
-    }
-}
-
-pub struct UserSession {
-    db: UserDB,
-    config: UserSessionConfig,
-}
-
-impl UserSession {
-    pub fn new(config: UserSessionConfig) -> Self {
-        let db = UserDB::new(&config.root_dir);
-        Self { db, config }
-    }
-
-    pub fn get_db_connection(&self) -> Result<DBConnection, UserError> {
-        match get_current_user_id()? {
-            None => Err(UserError::UserNotLogin),
-            Some(user_id) => self.db.get_connection(&user_id),
-        }
-    }
-}

+ 24 - 13
rust-lib/flowy-user/src/errors.rs

@@ -1,23 +1,34 @@
-use flowy_database::DataBaseError;
-use std::sync::PoisonError;
+use derive_more::Display;
+use flowy_dispatch::prelude::{DispatchError, EventResponse, ResponseBuilder, StatusCode};
+use std::{io, sync::PoisonError};
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Display)]
 pub enum UserError {
-    DBInit(String),
-    DBNotInit,
-    UserNotLogin,
-    DBConnection(String),
+    #[display(fmt = "User db error:{}", _0)]
+    Database(String),
+    #[display(fmt = "User auth error:{}", _0)]
+    Auth(String),
+    #[display(fmt = "User sync error: {}", _0)]
     PoisonError(String),
 }
 
-impl std::convert::From<DataBaseError> for UserError {
-    fn from(error: DataBaseError) -> Self { UserError::DBInit(format!("{:?}", error)) }
+impl std::convert::From<flowy_database::result::Error> for UserError {
+    fn from(error: flowy_database::result::Error) -> Self {
+        UserError::Database(format!("{:?}", error))
+    }
 }
 
-impl<T> std::convert::From<PoisonError<T>> for UserError {
-    fn from(error: PoisonError<T>) -> Self { UserError::PoisonError(format!("{:?}", error)) }
+impl std::convert::From<flowy_sqlite::Error> for UserError {
+    fn from(e: flowy_sqlite::Error) -> Self { UserError::Database(format!("{:?}", e)) }
 }
 
-impl std::convert::From<flowy_sqlite::Error> for UserError {
-    fn from(e: flowy_sqlite::Error) -> Self { UserError::DBConnection(format!("{:?}", e)) }
+impl std::convert::From<UserError> for String {
+    fn from(e: UserError) -> Self { format!("{:?}", e) }
+}
+
+impl std::convert::Into<DispatchError> for UserError {
+    fn into(self) -> DispatchError {
+        let user_error: String = self.into();
+        user_error.into()
+    }
 }

+ 6 - 3
rust-lib/flowy-user/src/handlers/auth.rs

@@ -1,4 +1,4 @@
-use crate::domain::{user::*, user_session::UserSession};
+use crate::{domain::user::*, services::user_session::UserSession};
 use flowy_dispatch::prelude::*;
 use std::{convert::TryInto, sync::Arc};
 
@@ -21,16 +21,19 @@ pub async fn user_sign_in(data: Data<SignInRequest>) -> ResponseResult<SignInRes
     name = "user_sign_up",
     skip(data, session),
     fields(
-    email = %data.email,
+        email = %data.email,
+        name = %data.name,
     )
 )]
 pub async fn user_sign_up(
     data: Data<SignUpRequest>,
     session: ModuleData<Arc<UserSession>>,
 ) -> ResponseResult<SignUpResponse, String> {
-    let _params: SignUpParams = data.into_inner().try_into()?;
+    let params: SignUpParams = data.into_inner().try_into()?;
     // TODO: user sign up
 
+    let _user = session.sign_up(params)?;
+
     let fake_resp = SignUpResponse::new(true);
     response_ok(fake_resp)
 }

+ 5 - 1
rust-lib/flowy-user/src/lib.rs

@@ -4,7 +4,11 @@ pub mod event;
 mod handlers;
 pub mod module;
 mod protobuf;
+mod services;
+
+#[macro_use]
+extern crate flowy_database;
 
 pub mod prelude {
-    pub use crate::{domain::*, handlers::auth::*};
+    pub use crate::{domain::*, handlers::auth::*, services::user_session::*};
 }

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

@@ -1,10 +1,6 @@
 use flowy_dispatch::prelude::*;
 
-use crate::{
-    domain::{user_db::*, user_session::UserSession},
-    event::UserEvent,
-    handlers::*,
-};
+use crate::{event::UserEvent, handlers::*, services::user_session::UserSession};
 use std::sync::Arc;
 
 pub fn create(user_session: Arc<UserSession>) -> Module {

+ 70 - 24
rust-lib/flowy-user/src/protobuf/model/user.rs

@@ -26,6 +26,7 @@
 #[derive(PartialEq,Clone,Default)]
 pub struct User {
     // message fields
+    pub id: ::std::string::String,
     pub name: ::std::string::String,
     pub email: ::std::string::String,
     pub password: ::std::string::String,
@@ -45,7 +46,33 @@ impl User {
         ::std::default::Default::default()
     }
 
-    // string name = 1;
+    // string id = 1;
+
+
+    pub fn get_id(&self) -> &str {
+        &self.id
+    }
+    pub fn clear_id(&mut self) {
+        self.id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_id(&mut self, v: ::std::string::String) {
+        self.id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_id(&mut self) -> &mut ::std::string::String {
+        &mut self.id
+    }
+
+    // Take field
+    pub fn take_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.id, ::std::string::String::new())
+    }
+
+    // string name = 2;
 
 
     pub fn get_name(&self) -> &str {
@@ -71,7 +98,7 @@ impl User {
         ::std::mem::replace(&mut self.name, ::std::string::String::new())
     }
 
-    // string email = 2;
+    // string email = 3;
 
 
     pub fn get_email(&self) -> &str {
@@ -97,7 +124,7 @@ impl User {
         ::std::mem::replace(&mut self.email, ::std::string::String::new())
     }
 
-    // string password = 3;
+    // string password = 4;
 
 
     pub fn get_password(&self) -> &str {
@@ -134,12 +161,15 @@ impl ::protobuf::Message for User {
             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.name)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.email)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?;
                 },
                 3 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.email)?;
+                },
+                4 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.password)?;
                 },
                 _ => {
@@ -154,14 +184,17 @@ impl ::protobuf::Message for User {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
+        if !self.id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.id);
+        }
         if !self.name.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.name);
+            my_size += ::protobuf::rt::string_size(2, &self.name);
         }
         if !self.email.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.email);
+            my_size += ::protobuf::rt::string_size(3, &self.email);
         }
         if !self.password.is_empty() {
-            my_size += ::protobuf::rt::string_size(3, &self.password);
+            my_size += ::protobuf::rt::string_size(4, &self.password);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -169,14 +202,17 @@ impl ::protobuf::Message for User {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.id.is_empty() {
+            os.write_string(1, &self.id)?;
+        }
         if !self.name.is_empty() {
-            os.write_string(1, &self.name)?;
+            os.write_string(2, &self.name)?;
         }
         if !self.email.is_empty() {
-            os.write_string(2, &self.email)?;
+            os.write_string(3, &self.email)?;
         }
         if !self.password.is_empty() {
-            os.write_string(3, &self.password)?;
+            os.write_string(4, &self.password)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -216,6 +252,11 @@ impl ::protobuf::Message for User {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "id",
+                |m: &User| { &m.id },
+                |m: &mut User| { &mut m.id },
+            ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "name",
                 |m: &User| { &m.name },
@@ -247,6 +288,7 @@ impl ::protobuf::Message for User {
 
 impl ::protobuf::Clear for User {
     fn clear(&mut self) {
+        self.id.clear();
         self.name.clear();
         self.email.clear();
         self.password.clear();
@@ -267,19 +309,23 @@ impl ::protobuf::reflect::ProtobufValue for User {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\nuser.proto\"L\n\x04User\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04nam\
-    e\x12\x14\n\x05email\x18\x02\x20\x01(\tR\x05email\x12\x1a\n\x08password\
-    \x18\x03\x20\x01(\tR\x08passwordJ\xcf\x01\n\x06\x12\x04\0\0\x06\x01\n\
-    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x06\x01\n\n\
-    \n\x03\x04\0\x01\x12\x03\x02\x08\x0c\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
-    \x04\x14\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\x0f\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
-    \x12\x13\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\
-    \x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\
-    \x0b\x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\
-    \x04\0\x02\x02\x12\x03\x05\x04\x18\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\
-    \x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x13\n\x0c\n\x05\
-    \x04\0\x02\x02\x03\x12\x03\x05\x16\x17b\x06proto3\
+    \n\nuser.proto\"\\\n\x04User\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\
+    \x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x14\n\x05email\x18\
+    \x03\x20\x01(\tR\x05email\x12\x1a\n\x08password\x18\x04\x20\x01(\tR\x08p\
+    asswordJ\x86\x02\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\x0c\x12\x03\0\0\
+    \x12\n\n\n\x02\x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\
+    \x02\x08\x0c\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\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\r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\
+    \x02\x01\x12\x03\x04\x04\x14\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\x0f\n\x0c\n\x05\x04\
+    \0\x02\x01\x03\x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\
+    \x04\x15\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\
+    \0\x02\x02\x01\x12\x03\x05\x0b\x10\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\
+    \x05\x13\x14\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\
+    \x04\0\x02\x03\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\
+    \x03\x06\x0b\x13\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x16\x17b\x06p\
+    roto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 4 - 3
rust-lib/flowy-user/src/protobuf/proto/user.proto

@@ -1,7 +1,8 @@
 syntax = "proto3";
 
 message User {
-    string name = 1;
-    string email = 2;
-    string password = 3;
+    string id = 1;
+    string name = 2;
+    string email = 3;
+    string password = 4;
 }

+ 21 - 11
rust-lib/flowy-user/src/domain/user_db.rs → rust-lib/flowy-user/src/services/database.rs

@@ -1,5 +1,5 @@
 use crate::errors::UserError;
-use flowy_database::{DBConnection, DataBase};
+use flowy_database::{DBConnection, Database};
 use lazy_static::lazy_static;
 use std::{
     cell::RefCell,
@@ -22,7 +22,7 @@ fn get_user_id() -> Option<String> { USER_ID.with(|id| id.borrow().clone()) }
 static IS_USER_DB_INIT: AtomicBool = AtomicBool::new(false);
 
 lazy_static! {
-    static ref USER_DB_INNER: RwLock<Option<DataBase>> = RwLock::new(None);
+    static ref DB: RwLock<Option<Database>> = RwLock::new(None);
 }
 
 pub(crate) struct UserDB {
@@ -37,17 +37,23 @@ impl UserDB {
     }
 
     fn open_user_db(&self, user_id: &str) -> Result<(), UserError> {
-        let user_dir = format!("{}/{}", self.db_dir, user_id);
-        let database = flowy_database::init(&user_dir)?;
-        let mut write_guard = USER_DB_INNER.write()?;
+        let dir = format!("{}/{}", self.db_dir, user_id);
+        let db = flowy_database::init(&dir).map_err(|e| UserError::Database(format!("{:?}", e)))?;
+
+        let mut user_db = DB
+            .write()
+            .map_err(|e| UserError::Database(format!("Open user db failed. {:?}", e)))?;
+        *(user_db) = Some(db);
+
         set_user_id(Some(user_id.to_owned()));
-        *(write_guard) = Some(database);
         IS_USER_DB_INIT.store(true, Ordering::SeqCst);
         Ok(())
     }
 
     pub(crate) fn close_user_db(&mut self) -> Result<(), UserError> {
-        let mut write_guard = USER_DB_INNER.write()?;
+        let mut write_guard = DB
+            .write()
+            .map_err(|e| UserError::Database(format!("Close user db failed. {:?}", e)))?;
         *write_guard = None;
         set_user_id(None);
         IS_USER_DB_INIT.store(false, Ordering::SeqCst);
@@ -62,16 +68,20 @@ impl UserDB {
         let thread_user_id = get_user_id();
         if thread_user_id != Some(user_id.to_owned()) {
             let msg = format!(
-                "DataBase owner does not match. origin: {:?}, current: {}",
+                "Database owner does not match. origin: {:?}, current: {}",
                 thread_user_id, user_id
             );
             log::error!("{}", msg);
-            return Err(UserError::DBConnection(msg));
+            return Err(UserError::Database(msg));
         }
 
-        let read_guard = USER_DB_INNER.read()?;
+        let read_guard = DB
+            .read()
+            .map_err(|e| UserError::Database(format!("Get user db connection fail. {:?}", e)))?;
         match read_guard.as_ref() {
-            None => Err(UserError::DBNotInit),
+            None => Err(UserError::Database(
+                "Database is not initialization".to_owned(),
+            )),
             Some(database) => Ok(database.get_connection()?),
         }
     }

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

@@ -0,0 +1,3 @@
+pub mod database;
+mod register;
+pub mod user_session;

+ 22 - 0
rust-lib/flowy-user/src/services/register.rs

@@ -0,0 +1,22 @@
+use crate::{
+    domain::{tables::User, SignUpParams},
+    errors::UserError,
+};
+
+pub trait UserRegister {
+    fn register_user(&self, params: SignUpParams) -> Result<User, UserError>;
+}
+
+pub struct MockUserRegister {}
+
+impl UserRegister for MockUserRegister {
+    fn register_user(&self, params: SignUpParams) -> Result<User, UserError> {
+        let user_id = "9527".to_owned();
+        Ok(User::new(
+            user_id,
+            params.name,
+            params.email,
+            params.password,
+        ))
+    }
+}

+ 23 - 0
rust-lib/flowy-user/src/services/user_session/builder.rs

@@ -0,0 +1,23 @@
+use crate::services::{
+    register::MockUserRegister,
+    user_session::{UserSession, UserSessionConfig},
+};
+
+pub struct UserSessionBuilder {
+    config: Option<UserSessionConfig>,
+}
+
+impl UserSessionBuilder {
+    pub fn new() -> Self { Self { config: None } }
+
+    pub fn root_dir(mut self, dir: &str) -> Self {
+        self.config = Some(UserSessionConfig::new(dir));
+        self
+    }
+
+    pub fn build(mut self) -> UserSession {
+        let config = self.config.take().unwrap();
+        let register = MockUserRegister {};
+        UserSession::new(config, register)
+    }
+}

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

@@ -0,0 +1,5 @@
+mod builder;
+mod user_session;
+
+pub use builder::*;
+pub use user_session::*;

+ 86 - 0
rust-lib/flowy-user/src/services/user_session/user_session.rs

@@ -0,0 +1,86 @@
+use crate::{
+    domain::{tables::User, SignUpParams},
+    errors::UserError,
+    services::{database::UserDB, register::UserRegister},
+};
+use ::diesel::query_dsl::*;
+use flowy_database::schema::user_table;
+use flowy_sqlite::DBConnection;
+use lazy_static::lazy_static;
+use std::sync::RwLock;
+
+pub struct UserSessionConfig {
+    root_dir: String,
+}
+
+impl UserSessionConfig {
+    pub fn new(root_dir: &str) -> Self {
+        Self {
+            root_dir: root_dir.to_owned(),
+        }
+    }
+}
+
+pub struct UserSession {
+    database: UserDB,
+    config: UserSessionConfig,
+    register: Box<dyn UserRegister + Send + Sync>,
+}
+
+impl UserSession {
+    pub fn new<R>(config: UserSessionConfig, register: R) -> Self
+    where
+        R: 'static + UserRegister + Send + Sync,
+    {
+        let db = UserDB::new(&config.root_dir);
+        Self {
+            database: db,
+            config,
+            register: Box::new(register),
+        }
+    }
+
+    pub fn get_db_connection(&self) -> Result<DBConnection, UserError> {
+        match get_current_user_id()? {
+            None => Err(UserError::Auth("User is not login yet".to_owned())),
+            Some(user_id) => self.database.get_connection(&user_id),
+        }
+    }
+
+    pub fn sign_up(&self, params: SignUpParams) -> Result<User, UserError> {
+        let user = self.register.register_user(params)?;
+        set_current_user_id(Some(user.id.clone()));
+
+        let conn = self.get_db_connection()?;
+        let _ = diesel::insert_into(user_table::table)
+            .values(user.clone())
+            .execute(&*conn)?;
+
+        Ok(user)
+    }
+
+    pub fn sign_out(&self) -> Result<(), UserError> {
+        set_current_user_id(None);
+        // TODO: close the db
+        unimplemented!()
+    }
+}
+
+lazy_static! {
+    pub static ref CURRENT_USER_ID: RwLock<Option<String>> = RwLock::new(None);
+}
+fn get_current_user_id() -> Result<Option<String>, UserError> {
+    let current_user_id = CURRENT_USER_ID
+        .read()
+        .map_err(|e| UserError::Auth(format!("Read current user id failed. {:?}", e)))?;
+
+    Ok((*current_user_id).clone())
+}
+
+pub fn set_current_user_id(user_id: Option<String>) -> Result<(), UserError> {
+    let mut current_user_id = CURRENT_USER_ID
+        .write()
+        .map_err(|e| UserError::Auth(format!("Write current user id failed. {:?}", e)))?;
+    *current_user_id = user_id;
+    Ok(())
+}

+ 3 - 5
rust-lib/flowy-user/tests/auth.rs → rust-lib/flowy-user/tests/auth_test.rs

@@ -9,11 +9,9 @@ fn sign_up_success() {
         password: valid_password(),
     };
 
-    let response = EventTester::new(SignUp)
-        .request(request)
-        .sync_send()
-        .parse::<SignUpResponse>();
-    dbg!(&response);
+    let response = EventTester::new(SignUp).request(request).sync_send();
+    // .parse::<SignUpResponse>();
+    // dbg!(&response);
 }
 
 #[test]

+ 1 - 1
rust-lib/flowy-user/tests/main.rs

@@ -1 +1 @@
-mod auth;
+mod auth_test;