Bläddra i källkod

[rust]: initialize the workspace when user status changed

appflowy 3 år sedan
förälder
incheckning
60bc41dda5

+ 1 - 5
app_flowy/lib/workspace/infrastructure/repos/user_repo.dart

@@ -27,11 +27,7 @@ class UserRepo {
   }
 
   Future<Either<Unit, UserError>> initUser() async {
-    return Future(() async {
-      final result = await UserEventInitUser().send();
-      await WorkspaceEventInitWorkspace().send();
-      return result;
-    });
+    return UserEventInitUser().send();
   }
 
   Future<Either<List<Workspace>, WorkspaceError>> getWorkspaces() {

+ 0 - 14
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -395,20 +395,6 @@ class WorkspaceEventApplyDocDelta {
     }
 }
 
-class WorkspaceEventInitWorkspace {
-    WorkspaceEventInitWorkspace();
-
-    Future<Either<Unit, WorkspaceError>> send() {
-     final request = FFIRequest.create()
-        ..event = WorkspaceEvent.InitWorkspace.toString();
-
-     return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
-        (bytes) => left(unit),
-        (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
-      ));
-    }
-}
-
 class UserEventInitUser {
     UserEventInitUser();
 

+ 0 - 4
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbenum.dart

@@ -16,7 +16,6 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
   static const WorkspaceEvent DeleteWorkspace = WorkspaceEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteWorkspace');
   static const WorkspaceEvent OpenWorkspace = WorkspaceEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenWorkspace');
   static const WorkspaceEvent ReadWorkspaceApps = WorkspaceEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadWorkspaceApps');
-  static const WorkspaceEvent CreateDefaultWorkspace = WorkspaceEvent._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspace');
   static const WorkspaceEvent CreateApp = WorkspaceEvent._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateApp');
   static const WorkspaceEvent DeleteApp = WorkspaceEvent._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteApp');
   static const WorkspaceEvent ReadApp = WorkspaceEvent._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadApp');
@@ -35,7 +34,6 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
   static const WorkspaceEvent RestoreAll = WorkspaceEvent._(303, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RestoreAll');
   static const WorkspaceEvent DeleteAll = WorkspaceEvent._(304, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteAll');
   static const WorkspaceEvent ApplyDocDelta = WorkspaceEvent._(400, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplyDocDelta');
-  static const WorkspaceEvent InitWorkspace = WorkspaceEvent._(1000, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InitWorkspace');
 
   static const $core.List<WorkspaceEvent> values = <WorkspaceEvent> [
     CreateWorkspace,
@@ -44,7 +42,6 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
     DeleteWorkspace,
     OpenWorkspace,
     ReadWorkspaceApps,
-    CreateDefaultWorkspace,
     CreateApp,
     DeleteApp,
     ReadApp,
@@ -63,7 +60,6 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
     RestoreAll,
     DeleteAll,
     ApplyDocDelta,
-    InitWorkspace,
   ];
 
   static final $core.Map<$core.int, WorkspaceEvent> _byValue = $pb.ProtobufEnum.initByValue(values);

+ 1 - 3
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbjson.dart

@@ -18,7 +18,6 @@ const WorkspaceEvent$json = const {
     const {'1': 'DeleteWorkspace', '2': 3},
     const {'1': 'OpenWorkspace', '2': 4},
     const {'1': 'ReadWorkspaceApps', '2': 5},
-    const {'1': 'CreateDefaultWorkspace', '2': 6},
     const {'1': 'CreateApp', '2': 101},
     const {'1': 'DeleteApp', '2': 102},
     const {'1': 'ReadApp', '2': 103},
@@ -37,9 +36,8 @@ const WorkspaceEvent$json = const {
     const {'1': 'RestoreAll', '2': 303},
     const {'1': 'DeleteAll', '2': 304},
     const {'1': 'ApplyDocDelta', '2': 400},
-    const {'1': 'InitWorkspace', '2': 1000},
   ],
 };
 
 /// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRIaChZDcmVhdGVEZWZhdWx0V29ya3NwYWNlEAYSDQoJQ3JlYXRlQXBwEGUSDQoJRGVsZXRlQXBwEGYSCwoHUmVhZEFwcBBnEg0KCVVwZGF0ZUFwcBBoEg8KCkNyZWF0ZVZpZXcQyQESDQoIUmVhZFZpZXcQygESDwoKVXBkYXRlVmlldxDLARIPCgpEZWxldGVWaWV3EMwBEhIKDUR1cGxpY2F0ZVZpZXcQzQESDQoIQ29weUxpbmsQzgESDQoIT3BlblZpZXcQzwESDgoJQ2xvc2VWaWV3ENABEg4KCVJlYWRUcmFzaBCsAhIRCgxQdXRiYWNrVHJhc2gQrQISEAoLRGVsZXRlVHJhc2gQrgISDwoKUmVzdG9yZUFsbBCvAhIOCglEZWxldGVBbGwQsAISEgoNQXBwbHlEb2NEZWx0YRCQAxISCg1Jbml0V29ya3NwYWNlEOgH');
+final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARINCghPcGVuVmlldxDPARIOCglDbG9zZVZpZXcQ0AESDgoJUmVhZFRyYXNoEKwCEhEKDFB1dGJhY2tUcmFzaBCtAhIQCgtEZWxldGVUcmFzaBCuAhIPCgpSZXN0b3JlQWxsEK8CEg4KCURlbGV0ZUFsbBCwAhISCg1BcHBseURvY0RlbHRhEJAD');

+ 1 - 1
backend/src/service/user/auth.rs

@@ -1,5 +1,5 @@
 use anyhow::Context;
-use chrono::Utc;
+
 use sqlx::{PgPool, Postgres};
 
 use flowy_net::{

+ 53 - 6
rust-lib/flowy-infra/src/kv/kv.rs

@@ -4,21 +4,35 @@ use diesel::{Connection, SqliteConnection};
 use flowy_derive::ProtoBuf;
 use flowy_sqlite::{DBConnection, Database, PoolConfig};
 use lazy_static::lazy_static;
-use std::{path::Path, sync::RwLock};
+use std::{
+    collections::HashMap,
+    path::Path,
+    sync::{PoisonError, RwLock, RwLockWriteGuard},
+};
 
 const DB_NAME: &str = "kv.db";
 lazy_static! {
-    static ref KV_HOLDER: RwLock<KV> = RwLock::new(KV { database: None });
+    static ref KV_HOLDER: RwLock<KV> = RwLock::new(KV::new());
 }
 
 pub struct KV {
     database: Option<Database>,
+    cache: HashMap<String, KeyValue>,
 }
 
 impl KV {
-    fn set(item: KeyValue) -> Result<(), String> {
+    fn new() -> Self {
+        KV {
+            database: None,
+            cache: HashMap::new(),
+        }
+    }
+
+    fn set(value: KeyValue) -> Result<(), String> {
+        update_cache(value.clone());
+
         let _ = diesel::replace_into(kv_table::table)
-            .values(&item)
+            .values(&value)
             .execute(&*(get_connection()?))
             .map_err(|e| format!("KV set error: {:?}", e))?;
 
@@ -26,16 +40,30 @@ impl KV {
     }
 
     fn get(key: &str) -> Result<KeyValue, String> {
+        if let Some(value) = read_cache(key) {
+            return Ok(value);
+        }
+
         let conn = get_connection()?;
-        let item = dsl::kv_table
+        let value = dsl::kv_table
             .filter(kv_table::key.eq(key))
             .first::<KeyValue>(&*conn)
             .map_err(|e| format!("KV get error: {:?}", e))?;
-        Ok(item)
+
+        update_cache(value.clone());
+
+        Ok(value)
     }
 
     #[allow(dead_code)]
     pub fn remove(key: &str) -> Result<(), String> {
+        match KV_HOLDER.write() {
+            Ok(mut guard) => {
+                guard.cache.remove(key);
+            },
+            Err(e) => log::error!("Require write lock failed: {:?}", e),
+        };
+
         let conn = get_connection()?;
         let sql = dsl::kv_table.filter(kv_table::key.eq(key));
         let _ = diesel::delete(sql)
@@ -63,6 +91,25 @@ impl KV {
     }
 }
 
+fn read_cache(key: &str) -> Option<KeyValue> {
+    match KV_HOLDER.read() {
+        Ok(guard) => guard.cache.get(key).cloned(),
+        Err(e) => {
+            log::error!("Require read lock failed: {:?}", e);
+            None
+        },
+    }
+}
+
+fn update_cache(value: KeyValue) {
+    match KV_HOLDER.write() {
+        Ok(mut guard) => {
+            guard.cache.insert(value.key.clone(), value);
+        },
+        Err(e) => log::error!("Require write lock failed: {:?}", e),
+    };
+}
+
 macro_rules! impl_get_func {
     (
         $func_name:ident,

+ 42 - 29
rust-lib/flowy-sdk/src/lib.rs

@@ -6,11 +6,8 @@ use crate::deps_resolve::WorkspaceDepsResolver;
 use flowy_dispatch::prelude::*;
 use flowy_document::prelude::FlowyDocument;
 use flowy_net::config::ServerConfig;
-use flowy_user::{
-    entities::UserStatus,
-    services::user::{UserSession, UserSessionBuilder},
-};
-use flowy_workspace::prelude::WorkspaceController;
+use flowy_user::services::user::{UserSession, UserSessionBuilder, UserStatus};
+use flowy_workspace::{errors::WorkspaceError, prelude::WorkspaceController};
 use module::mk_modules;
 pub use module::*;
 use std::sync::{
@@ -53,7 +50,8 @@ fn crate_log_filter(level: Option<String>) -> String {
     filters.push(format!("flowy_dart_notify={}", level));
     filters.push(format!("flowy_ot={}", level));
     filters.push(format!("flowy_ws={}", level));
-    filters.push(format!("info"));
+    filters.push(format!("flowy_ws={}", level));
+    filters.push(format!("flowy_infra={}", level));
     filters.join(",")
 }
 
@@ -81,9 +79,7 @@ impl FlowySDK {
         let workspace = mk_workspace(user_session.clone(), flowy_document.clone(), &config.server_config);
         let modules = mk_modules(workspace.clone(), user_session.clone());
         let dispatch = Arc::new(EventDispatch::construct(|| modules));
-
-        let subscribe = user_session.status_subscribe();
-        listen_on_user_status_changed(&dispatch, subscribe, workspace.clone());
+        _init(&dispatch, user_session.clone(), workspace.clone());
 
         Self {
             config,
@@ -97,30 +93,47 @@ impl FlowySDK {
     pub fn dispatch(&self) -> Arc<EventDispatch> { self.dispatch.clone() }
 }
 
-fn listen_on_user_status_changed(
-    dispatch: &EventDispatch,
+fn _init(dispatch: &EventDispatch, user_session: Arc<UserSession>, workspace_controller: Arc<WorkspaceController>) {
+    let subscribe = user_session.status_subscribe();
+    dispatch.spawn(async move {
+        user_session.init();
+        _listen_user_status(subscribe, workspace_controller).await;
+    });
+}
+
+async fn _listen_user_status(
     mut subscribe: broadcast::Receiver<UserStatus>,
     workspace_controller: Arc<WorkspaceController>,
 ) {
-    dispatch.spawn(async move {
-        //
-        loop {
-            match subscribe.recv().await {
-                Ok(status) => match status {
-                    UserStatus::Login { .. } => {
-                        workspace_controller.user_did_login();
-                    },
-                    UserStatus::Expired { .. } => {
-                        workspace_controller.user_session_expired();
-                    },
-                    UserStatus::SignUp { .. } => {
-                        let _ = workspace_controller.user_did_sign_up().await;
-                    },
-                },
-                Err(_) => {},
-            }
+    loop {
+        match subscribe.recv().await {
+            Ok(status) => {
+                let result = || async {
+                    match status {
+                        UserStatus::Login { .. } => {
+                            let _ = workspace_controller.user_did_login()?;
+                        },
+                        UserStatus::Logout { .. } => {
+                            workspace_controller.user_did_logout();
+                        },
+                        UserStatus::Expired { .. } => {
+                            workspace_controller.user_session_expired();
+                        },
+                        UserStatus::SignUp { .. } => {
+                            let _ = workspace_controller.user_did_sign_up().await?;
+                        },
+                    }
+                    Ok::<(), WorkspaceError>(())
+                };
+
+                match result().await {
+                    Ok(_) => {},
+                    Err(e) => log::error!("{}", e),
+                }
+            },
+            Err(_) => {},
         }
-    });
+    }
 }
 
 fn init_kv(root: &str) {

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

@@ -6,13 +6,6 @@ use crate::{
     parser::{UserEmail, UserId, UserName, UserPassword},
 };
 
-#[derive(Clone)]
-pub enum UserStatus {
-    Login { token: String },
-    Expired { token: String },
-    SignUp { profile: UserProfile },
-}
-
 #[derive(Default, ProtoBuf)]
 pub struct UserToken {
     #[pb(index = 1)]

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

@@ -1,6 +1,5 @@
 use crate::services::user::{UserSession, UserSessionConfig};
 use flowy_net::config::ServerConfig;
-use std::sync::Arc;
 
 pub struct UserSessionBuilder {
     config: Option<UserSessionConfig>,

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

@@ -19,13 +19,20 @@ use flowy_database::{
 use flowy_infra::kv::KV;
 use flowy_net::config::ServerConfig;
 use flowy_sqlite::ConnectionPool;
-use flowy_user_infra::entities::UserStatus;
 use flowy_ws::{WsController, WsMessageHandler, WsState};
 use parking_lot::RwLock;
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 use tokio::sync::broadcast;
 
+#[derive(Clone)]
+pub enum UserStatus {
+    Login { token: String },
+    Logout { token: String },
+    Expired { token: String },
+    SignUp { profile: UserProfile },
+}
+
 pub struct UserSessionConfig {
     root_dir: String,
     server_config: ServerConfig,
@@ -67,6 +74,16 @@ impl UserSession {
         user_session
     }
 
+    pub fn init(&self) {
+        log::debug!("😁😁😁 user did login");
+        match self.get_session() {
+            Ok(session) => {
+                let _ = self.status_notifier.send(UserStatus::Login { token: session.token });
+            },
+            Err(_) => {},
+        }
+    }
+
     pub fn status_subscribe(&self) -> broadcast::Receiver<UserStatus> { self.status_notifier.subscribe() }
 
     pub fn db_connection(&self) -> Result<DBConnection, UserError> {
@@ -126,7 +143,7 @@ impl UserSession {
             diesel::delete(dsl::user_table.filter(dsl::id.eq(&session.user_id))).execute(&*(self.db_connection()?))?;
         let _ = self.database.close_user_db(&session.user_id)?;
         let _ = self.set_session(None)?;
-        let _ = self.status_notifier.send(UserStatus::Expired {
+        let _ = self.status_notifier.send(UserStatus::Logout {
             token: session.token.clone(),
         });
         let _ = self.sign_out_on_server(&session.token).await?;

+ 0 - 3
rust-lib/flowy-workspace/src/event.rs

@@ -75,7 +75,4 @@ pub enum WorkspaceEvent {
 
     #[event(input = "DocDelta", output = "DocDelta")]
     ApplyDocDelta     = 400,
-
-    #[event()]
-    InitWorkspace     = 1000,
 }

+ 3 - 15
rust-lib/flowy-workspace/src/handlers/workspace_handler.rs

@@ -1,21 +1,9 @@
-use crate::{
-    errors::WorkspaceError,
-    services::{AppController, ViewController, WorkspaceController},
-};
-use chrono::Utc;
+use crate::{errors::WorkspaceError, services::WorkspaceController};
+
 use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
-use flowy_workspace_infra::{
-    entities::{app::RepeatedApp, workspace::*},
-    user_default,
-};
+use flowy_workspace_infra::entities::{app::RepeatedApp, workspace::*};
 use std::{convert::TryInto, sync::Arc};
 
-#[tracing::instrument(skip(controller), err)]
-pub(crate) async fn init_workspace_handler(controller: Unit<Arc<WorkspaceController>>) -> Result<(), WorkspaceError> {
-    let _ = controller.init()?;
-    Ok(())
-}
-
 #[tracing::instrument(skip(data, controller), err)]
 pub(crate) async fn create_workspace_handler(
     data: Data<CreateWorkspaceRequest>,

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

@@ -70,8 +70,7 @@ pub fn create(workspace: Arc<WorkspaceController>) -> Module {
         .data(workspace.clone())
         .data(workspace.app_controller.clone())
         .data(workspace.view_controller.clone())
-        .data(workspace.trash_can.clone())
-        .event(WorkspaceEvent::InitWorkspace, init_workspace_handler);
+        .data(workspace.trash_can.clone());
 
     module = module
         .event(WorkspaceEvent::CreateWorkspace, create_workspace_handler)

+ 61 - 72
rust-lib/flowy-workspace/src/protobuf/model/event.rs

@@ -31,7 +31,6 @@ pub enum WorkspaceEvent {
     DeleteWorkspace = 3,
     OpenWorkspace = 4,
     ReadWorkspaceApps = 5,
-    CreateDefaultWorkspace = 6,
     CreateApp = 101,
     DeleteApp = 102,
     ReadApp = 103,
@@ -50,7 +49,6 @@ pub enum WorkspaceEvent {
     RestoreAll = 303,
     DeleteAll = 304,
     ApplyDocDelta = 400,
-    InitWorkspace = 1000,
 }
 
 impl ::protobuf::ProtobufEnum for WorkspaceEvent {
@@ -66,7 +64,6 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             3 => ::std::option::Option::Some(WorkspaceEvent::DeleteWorkspace),
             4 => ::std::option::Option::Some(WorkspaceEvent::OpenWorkspace),
             5 => ::std::option::Option::Some(WorkspaceEvent::ReadWorkspaceApps),
-            6 => ::std::option::Option::Some(WorkspaceEvent::CreateDefaultWorkspace),
             101 => ::std::option::Option::Some(WorkspaceEvent::CreateApp),
             102 => ::std::option::Option::Some(WorkspaceEvent::DeleteApp),
             103 => ::std::option::Option::Some(WorkspaceEvent::ReadApp),
@@ -85,7 +82,6 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             303 => ::std::option::Option::Some(WorkspaceEvent::RestoreAll),
             304 => ::std::option::Option::Some(WorkspaceEvent::DeleteAll),
             400 => ::std::option::Option::Some(WorkspaceEvent::ApplyDocDelta),
-            1000 => ::std::option::Option::Some(WorkspaceEvent::InitWorkspace),
             _ => ::std::option::Option::None
         }
     }
@@ -98,7 +94,6 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             WorkspaceEvent::DeleteWorkspace,
             WorkspaceEvent::OpenWorkspace,
             WorkspaceEvent::ReadWorkspaceApps,
-            WorkspaceEvent::CreateDefaultWorkspace,
             WorkspaceEvent::CreateApp,
             WorkspaceEvent::DeleteApp,
             WorkspaceEvent::ReadApp,
@@ -117,7 +112,6 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             WorkspaceEvent::RestoreAll,
             WorkspaceEvent::DeleteAll,
             WorkspaceEvent::ApplyDocDelta,
-            WorkspaceEvent::InitWorkspace,
         ];
         values
     }
@@ -146,74 +140,69 @@ impl ::protobuf::reflect::ProtobufValue for WorkspaceEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*\xe6\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
+    \n\x0bevent.proto*\xb6\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
     ace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorkspa\
     ces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspac\
-    e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\x1a\n\x16CreateDefa\
-    ultWorkspace\x10\x06\x12\r\n\tCreateApp\x10e\x12\r\n\tDeleteApp\x10f\x12\
-    \x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\x10h\x12\x0f\n\nCreateView\x10\
-    \xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\x12\x0f\n\nUpdateView\x10\xcb\
-    \x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\x12\n\rDuplicateView\x10\xcd\
-    \x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\r\n\x08OpenView\x10\xcf\x01\x12\
-    \x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tReadTrash\x10\xac\x02\x12\x11\n\
-    \x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0bDeleteTrash\x10\xae\x02\x12\
-    \x0f\n\nRestoreAll\x10\xaf\x02\x12\x0e\n\tDeleteAll\x10\xb0\x02\x12\x12\
-    \n\rApplyDocDelta\x10\x90\x03\x12\x12\n\rInitWorkspace\x10\xe8\x07J\xd4\
-    \x08\n\x06\x12\x04\0\0\x1d\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
-    \x05\0\x12\x04\x02\0\x1d\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x13\n\
-    \x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\
-    \x12\x03\x03\x04\x13\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x16\x17\n\
-    \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x19\n\x0c\n\x05\x05\0\x02\x01\
-    \x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x17\
-    \x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\
-    \x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\
-    \x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\x05\0\
-    \x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\
-    \x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\
-    \x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\x04\x02\x12\
-    \x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1a\n\x0c\n\
-    \x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x05\0\x02\x05\x02\
-    \x12\x03\x08\x18\x19\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x1f\n\x0c\n\
-    \x05\x05\0\x02\x06\x01\x12\x03\t\x04\x1a\n\x0c\n\x05\x05\0\x02\x06\x02\
-    \x12\x03\t\x1d\x1e\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\
-    \x05\x05\0\x02\x07\x01\x12\x03\n\x04\r\n\x0c\n\x05\x05\0\x02\x07\x02\x12\
-    \x03\n\x10\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x14\n\x0c\n\x05\
-    \x05\0\x02\x08\x01\x12\x03\x0b\x04\r\n\x0c\n\x05\x05\0\x02\x08\x02\x12\
-    \x03\x0b\x10\x13\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x12\n\x0c\n\x05\
-    \x05\0\x02\t\x01\x12\x03\x0c\x04\x0b\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\
-    \x0c\x0e\x11\n\x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x14\n\x0c\n\x05\x05\0\
-    \x02\n\x01\x12\x03\r\x04\r\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x10\x13\
-    \n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\x15\n\x0c\n\x05\x05\0\x02\x0b\
-    \x01\x12\x03\x0e\x04\x0e\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x0e\x11\
-    \x14\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\x04\x13\n\x0c\n\x05\x05\0\x02\
-    \x0c\x01\x12\x03\x0f\x04\x0c\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x0f\
-    \x0f\x12\n\x0b\n\x04\x05\0\x02\r\x12\x03\x10\x04\x15\n\x0c\n\x05\x05\0\
-    \x02\r\x01\x12\x03\x10\x04\x0e\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x10\
-    \x11\x14\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\x11\x04\x15\n\x0c\n\x05\x05\0\
-    \x02\x0e\x01\x12\x03\x11\x04\x0e\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\
-    \x11\x11\x14\n\x0b\n\x04\x05\0\x02\x0f\x12\x03\x12\x04\x18\n\x0c\n\x05\
-    \x05\0\x02\x0f\x01\x12\x03\x12\x04\x11\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\
-    \x03\x12\x14\x17\n\x0b\n\x04\x05\0\x02\x10\x12\x03\x13\x04\x13\n\x0c\n\
-    \x05\x05\0\x02\x10\x01\x12\x03\x13\x04\x0c\n\x0c\n\x05\x05\0\x02\x10\x02\
-    \x12\x03\x13\x0f\x12\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x14\x04\x13\n\x0c\
-    \n\x05\x05\0\x02\x11\x01\x12\x03\x14\x04\x0c\n\x0c\n\x05\x05\0\x02\x11\
-    \x02\x12\x03\x14\x0f\x12\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x15\x04\x14\n\
-    \x0c\n\x05\x05\0\x02\x12\x01\x12\x03\x15\x04\r\n\x0c\n\x05\x05\0\x02\x12\
-    \x02\x12\x03\x15\x10\x13\n\x0b\n\x04\x05\0\x02\x13\x12\x03\x16\x04\x14\n\
-    \x0c\n\x05\x05\0\x02\x13\x01\x12\x03\x16\x04\r\n\x0c\n\x05\x05\0\x02\x13\
-    \x02\x12\x03\x16\x10\x13\n\x0b\n\x04\x05\0\x02\x14\x12\x03\x17\x04\x17\n\
-    \x0c\n\x05\x05\0\x02\x14\x01\x12\x03\x17\x04\x10\n\x0c\n\x05\x05\0\x02\
-    \x14\x02\x12\x03\x17\x13\x16\n\x0b\n\x04\x05\0\x02\x15\x12\x03\x18\x04\
-    \x16\n\x0c\n\x05\x05\0\x02\x15\x01\x12\x03\x18\x04\x0f\n\x0c\n\x05\x05\0\
-    \x02\x15\x02\x12\x03\x18\x12\x15\n\x0b\n\x04\x05\0\x02\x16\x12\x03\x19\
-    \x04\x15\n\x0c\n\x05\x05\0\x02\x16\x01\x12\x03\x19\x04\x0e\n\x0c\n\x05\
-    \x05\0\x02\x16\x02\x12\x03\x19\x11\x14\n\x0b\n\x04\x05\0\x02\x17\x12\x03\
-    \x1a\x04\x14\n\x0c\n\x05\x05\0\x02\x17\x01\x12\x03\x1a\x04\r\n\x0c\n\x05\
-    \x05\0\x02\x17\x02\x12\x03\x1a\x10\x13\n\x0b\n\x04\x05\0\x02\x18\x12\x03\
-    \x1b\x04\x18\n\x0c\n\x05\x05\0\x02\x18\x01\x12\x03\x1b\x04\x11\n\x0c\n\
-    \x05\x05\0\x02\x18\x02\x12\x03\x1b\x14\x17\n\x0b\n\x04\x05\0\x02\x19\x12\
-    \x03\x1c\x04\x19\n\x0c\n\x05\x05\0\x02\x19\x01\x12\x03\x1c\x04\x11\n\x0c\
-    \n\x05\x05\0\x02\x19\x02\x12\x03\x1c\x14\x18b\x06proto3\
+    e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10e\
+    \x12\r\n\tDeleteApp\x10f\x12\x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\
+    \x10h\x12\x0f\n\nCreateView\x10\xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\
+    \x12\x0f\n\nUpdateView\x10\xcb\x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\
+    \x12\n\rDuplicateView\x10\xcd\x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\r\
+    \n\x08OpenView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tR\
+    eadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0b\
+    DeleteTrash\x10\xae\x02\x12\x0f\n\nRestoreAll\x10\xaf\x02\x12\x0e\n\tDel\
+    eteAll\x10\xb0\x02\x12\x12\n\rApplyDocDelta\x10\x90\x03J\x82\x08\n\x06\
+    \x12\x04\0\0\x1b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\
+    \x04\x02\0\x1b\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x13\n\x0b\n\x04\
+    \x05\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\
+    \x04\x13\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\
+    \0\x02\x01\x12\x03\x04\x04\x19\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\
+    \x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x17\x18\n\x0b\n\x04\
+    \x05\0\x02\x02\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\
+    \x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\x15\x16\n\x0b\n\
+    \x04\x05\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\x05\0\x02\x03\x01\x12\
+    \x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x16\x17\n\x0b\
+    \n\x04\x05\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x01\
+    \x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x14\x15\n\
+    \x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x05\
+    \x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x18\
+    \x19\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\
+    \x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\x10\x13\
+    \n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\x05\x05\0\x02\x07\
+    \x01\x12\x03\n\x04\r\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\x10\x13\n\
+    \x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x12\n\x0c\n\x05\x05\0\x02\x08\
+    \x01\x12\x03\x0b\x04\x0b\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0b\x0e\
+    \x11\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x14\n\x0c\n\x05\x05\0\x02\t\
+    \x01\x12\x03\x0c\x04\r\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x0c\x10\x13\n\
+    \x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x15\n\x0c\n\x05\x05\0\x02\n\x01\x12\
+    \x03\r\x04\x0e\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x11\x14\n\x0b\n\x04\
+    \x05\0\x02\x0b\x12\x03\x0e\x04\x13\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\
+    \x0e\x04\x0c\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x0e\x0f\x12\n\x0b\n\
+    \x04\x05\0\x02\x0c\x12\x03\x0f\x04\x15\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\
+    \x03\x0f\x04\x0e\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x0f\x11\x14\n\x0b\
+    \n\x04\x05\0\x02\r\x12\x03\x10\x04\x15\n\x0c\n\x05\x05\0\x02\r\x01\x12\
+    \x03\x10\x04\x0e\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x10\x11\x14\n\x0b\n\
+    \x04\x05\0\x02\x0e\x12\x03\x11\x04\x18\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\
+    \x03\x11\x04\x11\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\x11\x14\x17\n\x0b\
+    \n\x04\x05\0\x02\x0f\x12\x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0f\x01\
+    \x12\x03\x12\x04\x0c\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\x12\x0f\x12\n\
+    \x0b\n\x04\x05\0\x02\x10\x12\x03\x13\x04\x13\n\x0c\n\x05\x05\0\x02\x10\
+    \x01\x12\x03\x13\x04\x0c\n\x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x13\x0f\
+    \x12\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x14\x04\x14\n\x0c\n\x05\x05\0\x02\
+    \x11\x01\x12\x03\x14\x04\r\n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x14\x10\
+    \x13\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x15\x04\x14\n\x0c\n\x05\x05\0\x02\
+    \x12\x01\x12\x03\x15\x04\r\n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x15\x10\
+    \x13\n\x0b\n\x04\x05\0\x02\x13\x12\x03\x16\x04\x17\n\x0c\n\x05\x05\0\x02\
+    \x13\x01\x12\x03\x16\x04\x10\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x16\
+    \x13\x16\n\x0b\n\x04\x05\0\x02\x14\x12\x03\x17\x04\x16\n\x0c\n\x05\x05\0\
+    \x02\x14\x01\x12\x03\x17\x04\x0f\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\
+    \x17\x12\x15\n\x0b\n\x04\x05\0\x02\x15\x12\x03\x18\x04\x15\n\x0c\n\x05\
+    \x05\0\x02\x15\x01\x12\x03\x18\x04\x0e\n\x0c\n\x05\x05\0\x02\x15\x02\x12\
+    \x03\x18\x11\x14\n\x0b\n\x04\x05\0\x02\x16\x12\x03\x19\x04\x14\n\x0c\n\
+    \x05\x05\0\x02\x16\x01\x12\x03\x19\x04\r\n\x0c\n\x05\x05\0\x02\x16\x02\
+    \x12\x03\x19\x10\x13\n\x0b\n\x04\x05\0\x02\x17\x12\x03\x1a\x04\x18\n\x0c\
+    \n\x05\x05\0\x02\x17\x01\x12\x03\x1a\x04\x11\n\x0c\n\x05\x05\0\x02\x17\
+    \x02\x12\x03\x1a\x14\x17b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 0 - 2
rust-lib/flowy-workspace/src/protobuf/proto/event.proto

@@ -7,7 +7,6 @@ enum WorkspaceEvent {
     DeleteWorkspace = 3;
     OpenWorkspace = 4;
     ReadWorkspaceApps = 5;
-    CreateDefaultWorkspace = 6;
     CreateApp = 101;
     DeleteApp = 102;
     ReadApp = 103;
@@ -26,5 +25,4 @@ enum WorkspaceEvent {
     RestoreAll = 303;
     DeleteAll = 304;
     ApplyDocDelta = 400;
-    InitWorkspace = 1000;
 }

+ 28 - 5
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -12,7 +12,12 @@ use flowy_workspace_infra::{
     entities::{app::RepeatedApp, workspace::*},
     user_default,
 };
-use std::sync::Arc;
+use std::sync::{
+    atomic::{AtomicBool, Ordering},
+    Arc,
+};
+
+static INIT_WORKSPACE: AtomicBool = AtomicBool::new(false);
 
 pub struct WorkspaceController {
     pub user: Arc<dyn WorkspaceUser>,
@@ -45,7 +50,13 @@ impl WorkspaceController {
         }
     }
 
-    pub fn init(&self) -> Result<(), WorkspaceError> {
+    fn init(&self) -> Result<(), WorkspaceError> {
+        if INIT_WORKSPACE.load(Ordering::SeqCst) {
+            return Ok(());
+        }
+
+        log::debug!("workspace initialize");
+        INIT_WORKSPACE.store(true, Ordering::SeqCst);
         let _ = self.server.init();
         let _ = self.trash_can.init()?;
         let _ = self.view_controller.init()?;
@@ -54,9 +65,19 @@ impl WorkspaceController {
         Ok(())
     }
 
-    pub fn user_did_login(&self) {}
+    pub fn user_did_login(&self) -> WorkspaceResult<()> {
+        // TODO: (nathan) do something here
+        let _ = self.init()?;
+        Ok(())
+    }
+
+    pub fn user_did_logout(&self) {
+        // TODO: (nathan) do something here
+    }
 
-    pub fn user_session_expired(&self) {}
+    pub fn user_session_expired(&self) {
+        // TODO: (nathan) do something here
+    }
 
     pub async fn user_did_sign_up(&self) -> WorkspaceResult<()> {
         log::debug!("Create user default workspace");
@@ -78,9 +99,11 @@ impl WorkspaceController {
         let repeated_workspace = RepeatedWorkspace {
             items: vec![cloned_workspace],
         };
+
         send_dart_notification(&token, WorkspaceNotification::UserCreateWorkspace)
             .payload(repeated_workspace)
             .send();
+        let _ = self.init()?;
         Ok(())
     }
 
@@ -347,7 +370,7 @@ impl WorkspaceController {
 
 const CURRENT_WORKSPACE_ID: &str = "current_workspace_id";
 
-fn set_current_workspace(workspace: &str) { KV::set_str(CURRENT_WORKSPACE_ID, workspace.to_owned()); }
+fn set_current_workspace(workspace_id: &str) { KV::set_str(CURRENT_WORKSPACE_ID, workspace_id.to_owned()); }
 
 fn get_current_workspace() -> Result<String, WorkspaceError> {
     match KV::get_str(CURRENT_WORKSPACE_ID) {