This commit is contained in:
appflowy 2021-12-06 15:49:21 +08:00
parent 29c14949cb
commit 6298a0d96d
36 changed files with 676 additions and 578 deletions

View File

@ -188,7 +188,7 @@ impl std::convert::From<TestServer> for TestUserServer {
pg_pool: server.pg_pool,
user_token: None,
user_id: None,
client_server_config: server.client_server_config.clone(),
client_server_config: server.client_server_config,
}
}
}

View File

@ -0,0 +1,134 @@
use crate::{
entities::workspace::RepeatedWorkspace,
errors::{WorkspaceError, WorkspaceResult},
module::WorkspaceUser,
notify::{send_dart_notification, WorkspaceNotification},
services::{server::Server, AppController, TrashController, ViewController, WorkspaceController},
};
use chrono::Utc;
use flowy_document_infra::{entities::doc::DocDelta, user_default::initial_read_me};
use flowy_workspace_infra::user_default;
use lazy_static::lazy_static;
use lib_infra::entities::network_state::NetworkType;
use parking_lot::RwLock;
use std::{collections::HashMap, sync::Arc};
lazy_static! {
static ref INIT_WORKSPACE: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
}
pub struct FlowyCore {
pub user: Arc<dyn WorkspaceUser>,
server: Server,
pub workspace_controller: Arc<WorkspaceController>,
pub(crate) app_controller: Arc<AppController>,
pub(crate) view_controller: Arc<ViewController>,
pub(crate) trash_controller: Arc<TrashController>,
}
impl FlowyCore {
pub(crate) fn new(
user: Arc<dyn WorkspaceUser>,
server: Server,
workspace_controller: Arc<WorkspaceController>,
app_controller: Arc<AppController>,
view_controller: Arc<ViewController>,
trash_controller: Arc<TrashController>,
) -> Self {
if let Ok(token) = user.token() {
INIT_WORKSPACE.write().insert(token, false);
}
Self {
user,
server,
workspace_controller,
app_controller,
view_controller,
trash_controller,
}
}
async fn init(&self, token: &str) -> Result<(), WorkspaceError> {
if let Some(is_init) = INIT_WORKSPACE.read().get(token) {
if *is_init {
return Ok(());
}
}
log::debug!("Start initializing flowy core");
INIT_WORKSPACE.write().insert(token.to_owned(), true);
let _ = self.server.init();
let _ = self.workspace_controller.init()?;
let _ = self.app_controller.init()?;
let _ = self.view_controller.init()?;
let _ = self.trash_controller.init()?;
log::debug!("Finish initializing core");
Ok(())
}
pub fn network_state_changed(&self, new_type: NetworkType) {
match new_type {
NetworkType::UnknownNetworkType => {},
NetworkType::Wifi => {},
NetworkType::Cell => {},
NetworkType::Ethernet => {},
}
}
pub async fn user_did_sign_in(&self, token: &str) -> WorkspaceResult<()> {
// TODO: (nathan) do something here
log::debug!("workspace initialize after sign in");
let _ = self.init(token).await?;
Ok(())
}
pub async fn user_did_logout(&self) {
// TODO: (nathan) do something here
}
pub async fn user_session_expired(&self) {
// TODO: (nathan) do something here
}
pub async fn user_did_sign_up(&self, _token: &str) -> WorkspaceResult<()> {
log::debug!("Create user default workspace");
let time = Utc::now();
let mut workspace = user_default::create_default_workspace(time);
let apps = workspace.take_apps().into_inner();
let cloned_workspace = workspace.clone();
let _ = self.workspace_controller.create_workspace(workspace).await?;
for mut app in apps {
let views = app.take_belongings().into_inner();
let _ = self.app_controller.create_app(app).await?;
for (index, view) in views.into_iter().enumerate() {
if index == 0 {
let delta = initial_read_me();
let doc_delta = DocDelta {
doc_id: view.id.clone(),
data: delta.to_json(),
};
let _ = self.view_controller.apply_doc_delta(doc_delta).await?;
self.view_controller.set_latest_view(&view);
}
let _ = self.view_controller.create_view(view).await?;
}
}
let token = self.user.token()?;
let repeated_workspace = RepeatedWorkspace {
items: vec![cloned_workspace],
};
send_dart_notification(&token, WorkspaceNotification::UserCreateWorkspace)
.payload(repeated_workspace)
.send();
log::debug!("workspace initialize after sign up");
let _ = self.init(&token).await?;
Ok(())
}
}

View File

@ -0,0 +1,4 @@
mod flowy_core;
mod task;
pub use flowy_core::*;

View File

@ -0,0 +1,69 @@
use crate::{errors::WorkspaceError, services::WorkspaceController};
use flowy_workspace_infra::entities::workspace::{QueryWorkspaceRequest, RepeatedWorkspace, WorkspaceIdentifier};
use lib_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc};
#[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn read_workspaces_handler(
data: Data<QueryWorkspaceRequest>,
controller: Unit<Arc<WorkspaceController>>,
) -> DataResult<RepeatedWorkspace, WorkspaceError> {
let params: WorkspaceIdentifier = data.into_inner().try_into()?;
let user_id = controller.user.user_id()?;
let workspaces = controller.read_local_workspaces(
params.workspace_id.clone(),
&user_id,
&*controller.database.db_connection()?,
)?;
let _ = controller.read_workspaces_on_server(user_id, params);
data_result(workspaces)
}
// #[tracing::instrument(level = "debug", skip(self), err)]
// fn read_workspaces_on_server(&self, user_id: String, params:
// WorkspaceIdentifier) -> Result<(), WorkspaceError> { let (token, server)
// = self.token_with_server()?; let workspace_sql =
// self.workspace_sql.clone(); let app_ctrl = self.app_controller.clone();
// let view_ctrl = self.view_controller.clone();
// let conn = self.database.db_connection()?;
// tokio::spawn(async move {
// // Opti: handle the error and retry?
// let workspaces = server.read_workspace(&token, params).await?;
// let _ = (&*conn).immediate_transaction::<_, WorkspaceError, _>(|| {
// tracing::debug!("Save {} workspace", workspaces.len());
// for workspace in &workspaces.items {
// let m_workspace = workspace.clone();
// let apps = m_workspace.apps.clone().into_inner();
// let workspace_table = WorkspaceTable::new(m_workspace,
// &user_id);
//
// let _ = workspace_sql.create_workspace(workspace_table,
// &*conn)?; tracing::debug!("Save {} apps", apps.len());
// for app in apps {
// let views = app.belongings.clone().into_inner();
// match app_ctrl.save_app(app, &*conn) {
// Ok(_) => {},
// Err(e) => log::error!("create app failed: {:?}", e),
// }
//
// tracing::debug!("Save {} views", views.len());
// for view in views {
// match view_ctrl.save_view(view, &*conn) {
// Ok(_) => {},
// Err(e) => log::error!("create view failed: {:?}",
// e), }
// }
// }
// }
// Ok(())
// })?;
//
// send_dart_notification(&token,
// WorkspaceNotification::WorkspaceListUpdated) .payload(workspaces)
// .send();
// Result::<(), WorkspaceError>::Ok(())
// });
//
// Ok(())
// }

View File

@ -1,9 +0,0 @@
mod app_handler;
mod trash_handler;
mod view_handler;
mod workspace_handler;
pub(crate) use app_handler::*;
pub(crate) use trash_handler::*;
pub(crate) use view_handler::*;
pub(crate) use workspace_handler::*;

View File

@ -10,15 +10,14 @@ mod macros;
#[macro_use]
extern crate flowy_database;
pub mod core;
pub mod errors;
pub mod handlers;
mod notify;
pub mod protobuf;
mod sql_tables;
mod util;
pub mod prelude {
pub use flowy_workspace_infra::entities::{app::*, trash::*, view::*, workspace::*};
pub use crate::{errors::*, module::*, services::*};
pub use crate::{core::*, errors::*, module::*};
}

View File

@ -1,15 +1,27 @@
use crate::{
errors::WorkspaceError,
event::WorkspaceEvent,
handlers::*,
services::{server::construct_workspace_server, AppController, TrashCan, ViewController, WorkspaceController},
};
use std::sync::Arc;
use backend_service::configuration::ClientServerConfiguration;
use flowy_database::DBConnection;
use flowy_document::module::FlowyDocument;
use lib_dispatch::prelude::*;
use lib_sqlite::ConnectionPool;
use std::sync::Arc;
use crate::{
core::FlowyCore,
errors::WorkspaceError,
event::WorkspaceEvent,
services::{
app::event_handler::*,
server::construct_workspace_server,
trash::event_handler::*,
view::event_handler::*,
workspace::event_handler::*,
AppController,
TrashController,
ViewController,
WorkspaceController,
},
};
pub trait WorkspaceDeps: WorkspaceUser + WorkspaceDatabase {}
@ -28,48 +40,57 @@ pub trait WorkspaceDatabase: Send + Sync {
}
}
pub fn init_workspace_controller(
pub fn init_core(
user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>,
flowy_document: Arc<FlowyDocument>,
server_config: &ClientServerConfiguration,
) -> Arc<WorkspaceController> {
) -> Arc<FlowyCore> {
let server = construct_workspace_server(server_config);
let trash_can = Arc::new(TrashCan::new(database.clone(), server.clone(), user.clone()));
let trash_controller = Arc::new(TrashController::new(database.clone(), server.clone(), user.clone()));
let view_controller = Arc::new(ViewController::new(
user.clone(),
database.clone(),
server.clone(),
trash_can.clone(),
trash_controller.clone(),
flowy_document,
));
let app_controller = Arc::new(AppController::new(
user.clone(),
database.clone(),
trash_can.clone(),
trash_controller.clone(),
server.clone(),
));
Arc::new(WorkspaceController::new(
let workspace_controller = Arc::new(WorkspaceController::new(
user.clone(),
database.clone(),
app_controller.clone(),
view_controller.clone(),
trash_controller.clone(),
server.clone(),
));
Arc::new(FlowyCore::new(
user,
database,
server,
workspace_controller,
app_controller,
view_controller,
trash_can,
server,
trash_controller,
))
}
pub fn create(workspace: Arc<WorkspaceController>) -> Module {
pub fn create(core: Arc<FlowyCore>) -> Module {
let mut module = Module::new()
.name("Flowy-Workspace")
.data(workspace.clone())
.data(workspace.app_controller.clone())
.data(workspace.view_controller.clone())
.data(workspace.trash_can.clone());
.data(core.workspace_controller.clone())
.data(core.app_controller.clone())
.data(core.view_controller.clone())
.data(core.trash_controller.clone());
module = module
.event(WorkspaceEvent::CreateWorkspace, create_workspace_handler)

View File

@ -1,9 +1,3 @@
use std::{collections::HashSet, sync::Arc};
use futures::{FutureExt, StreamExt};
use flowy_database::SqliteConnection;
use crate::{
entities::{
app::{App, CreateAppParams, *},
@ -12,14 +6,21 @@ use crate::{
errors::*,
module::{WorkspaceDatabase, WorkspaceUser},
notify::*,
services::{server::Server, TrashCan, TrashEvent},
sql_tables::app::{AppTable, AppTableChangeset, AppTableSql},
services::{
app::sql::{AppTable, AppTableChangeset, AppTableSql},
server::Server,
TrashController,
TrashEvent,
},
};
use flowy_database::SqliteConnection;
use futures::{FutureExt, StreamExt};
use std::{collections::HashSet, sync::Arc};
pub(crate) struct AppController {
user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
server: Server,
}
@ -27,7 +28,7 @@ impl AppController {
pub(crate) fn new(
user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
server: Server,
) -> Self {
Self {
@ -185,7 +186,7 @@ impl AppController {
}
#[tracing::instrument(level = "trace", skip(database, trash_can))]
async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc<TrashCan>, event: TrashEvent) {
async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc<TrashController>, event: TrashEvent) {
let db_result = database.db_connection();
match event {
TrashEvent::NewTrash(identifiers, ret) | TrashEvent::Putback(identifiers, ret) => {
@ -226,7 +227,11 @@ async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc
}
#[tracing::instrument(skip(workspace_id, trash_can, conn), err)]
fn notify_apps_changed(workspace_id: &str, trash_can: Arc<TrashCan>, conn: &SqliteConnection) -> WorkspaceResult<()> {
fn notify_apps_changed(
workspace_id: &str,
trash_can: Arc<TrashController>,
conn: &SqliteConnection,
) -> WorkspaceResult<()> {
let repeated_app = read_local_workspace_apps(workspace_id, trash_can, conn)?;
send_dart_notification(workspace_id, WorkspaceNotification::WorkspaceAppsChanged)
.payload(repeated_app)
@ -236,7 +241,7 @@ fn notify_apps_changed(workspace_id: &str, trash_can: Arc<TrashCan>, conn: &Sqli
pub fn read_local_workspace_apps(
workspace_id: &str,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
conn: &SqliteConnection,
) -> Result<RepeatedApp, WorkspaceError> {
let mut app_tables = AppTableSql::read_workspace_apps(workspace_id, false, conn)?;

View File

@ -12,7 +12,7 @@ use crate::{
trash::Trash,
},
errors::WorkspaceError,
services::{AppController, TrashCan, ViewController},
services::{AppController, TrashController, ViewController},
};
use lib_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc};
@ -30,7 +30,7 @@ pub(crate) async fn create_app_handler(
pub(crate) async fn delete_app_handler(
data: Data<QueryAppRequest>,
controller: Unit<Arc<AppController>>,
trash_can: Unit<Arc<TrashCan>>,
trash_can: Unit<Arc<TrashController>>,
) -> Result<(), WorkspaceError> {
let params: AppIdentifier = data.into_inner().try_into()?;
let trash = controller

View File

@ -0,0 +1,3 @@
pub mod controller;
pub mod event_handler;
pub(crate) mod sql;

View File

@ -1,18 +1,87 @@
use std::convert::TryInto;
use diesel::sql_types::Binary;
use serde::{Deserialize, Serialize, __private::TryFrom};
use flowy_database::schema::app_table;
use crate::{
entities::{
app::{App, ColorStyle, UpdateAppParams},
trash::{Trash, TrashType},
view::RepeatedView,
},
sql_tables::workspace::WorkspaceTable,
services::workspace::sql::WorkspaceTable,
};
use diesel::sql_types::Binary;
use flowy_database::{
prelude::*,
schema::{app_table, app_table::dsl},
SqliteConnection,
};
use serde::{Deserialize, Serialize, __private::TryFrom};
use std::convert::TryInto;
use crate::errors::WorkspaceError;
pub struct AppTableSql {}
impl AppTableSql {
pub(crate) fn create_app(app_table: AppTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
match diesel_record_count!(app_table, &app_table.id, conn) {
0 => diesel_insert_table!(app_table, &app_table, conn),
_ => {
let changeset = AppTableChangeset::from_table(app_table);
diesel_update_table!(app_table, changeset, conn)
},
}
Ok(())
}
pub(crate) fn update_app(changeset: AppTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_update_table!(app_table, changeset, conn);
Ok(())
}
pub(crate) fn read_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
let filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed();
let app_table = filter.first::<AppTable>(conn)?;
Ok(app_table)
}
pub(crate) fn read_workspace_apps(
workspace_id: &str,
is_trash: bool,
conn: &SqliteConnection,
) -> Result<Vec<AppTable>, WorkspaceError> {
let app_table = dsl::app_table
.filter(app_table::workspace_id.eq(workspace_id))
.filter(app_table::is_trash.eq(is_trash))
.order(app_table::create_time.asc())
.load::<AppTable>(conn)?;
Ok(app_table)
}
pub(crate) fn delete_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
let app_table = dsl::app_table
.filter(app_table::id.eq(app_id))
.first::<AppTable>(conn)?;
diesel_delete_table!(app_table, app_id, conn);
Ok(app_table)
}
// pub(crate) fn read_views_belong_to_app(
// &self,
// app_id: &str,
// ) -> Result<Vec<ViewTable>, WorkspaceError> {
// let conn = self.database.db_connection()?;
//
// let views = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
// let app_table: AppTable = dsl::app_table
// .filter(app_table::id.eq(app_id))
// .first::<AppTable>(&*(conn))?;
// let views =
// ViewTable::belonging_to(&app_table).load::<ViewTable>(&*conn)?;
// Ok(views)
// })?;
//
// Ok(views)
// }
}
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[belongs_to(WorkspaceTable, foreign_key = "workspace_id")]

View File

@ -1,11 +1,10 @@
pub(crate) use app_controller::*;
pub(crate) use trash_can::*;
pub(crate) use view_controller::*;
pub use workspace_controller::*;
pub(crate) use app::controller::*;
pub(crate) use trash::controller::*;
pub(crate) use view::controller::*;
pub(crate) use workspace::controller::*;
mod app_controller;
mod database;
pub(crate) mod app;
pub(crate) mod server;
mod trash_can;
mod view_controller;
mod workspace_controller;
pub(crate) mod trash;
pub(crate) mod view;
pub(crate) mod workspace;

View File

@ -1,27 +1,23 @@
use std::{fmt::Formatter, sync::Arc};
use crossbeam_utils::thread;
use tokio::sync::{broadcast, mpsc};
use flowy_database::SqliteConnection;
use crate::{
entities::trash::{RepeatedTrash, Trash, TrashIdentifier, TrashIdentifiers, TrashType},
errors::{WorkspaceError, WorkspaceResult},
module::{WorkspaceDatabase, WorkspaceUser},
notify::{send_anonymous_dart_notification, WorkspaceNotification},
services::server::Server,
sql_tables::trash::TrashTableSql,
services::{server::Server, trash::sql::TrashTableSql},
};
use crossbeam_utils::thread;
use flowy_database::SqliteConnection;
use std::{fmt::Formatter, sync::Arc};
use tokio::sync::{broadcast, mpsc};
pub struct TrashCan {
pub struct TrashController {
pub database: Arc<dyn WorkspaceDatabase>,
notify: broadcast::Sender<TrashEvent>,
server: Server,
user: Arc<dyn WorkspaceUser>,
}
impl TrashCan {
impl TrashController {
pub fn new(database: Arc<dyn WorkspaceDatabase>, server: Server, user: Arc<dyn WorkspaceUser>) -> Self {
let (tx, _) = broadcast::channel(10);
@ -196,7 +192,7 @@ impl TrashCan {
}
}
impl TrashCan {
impl TrashController {
#[tracing::instrument(level = "debug", skip(self, trash), err)]
fn create_trash_on_server<T: Into<TrashIdentifiers>>(&self, trash: T) -> WorkspaceResult<()> {
let token = self.user.token()?;

View File

@ -1,13 +1,15 @@
use crate::{
entities::trash::{RepeatedTrash, TrashIdentifier, TrashIdentifiers},
errors::WorkspaceError,
services::TrashCan,
services::TrashController,
};
use lib_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::sync::Arc;
#[tracing::instrument(skip(controller), err)]
pub(crate) async fn read_trash_handler(controller: Unit<Arc<TrashCan>>) -> DataResult<RepeatedTrash, WorkspaceError> {
pub(crate) async fn read_trash_handler(
controller: Unit<Arc<TrashController>>,
) -> DataResult<RepeatedTrash, WorkspaceError> {
let conn = controller.database.db_connection()?;
let repeated_trash = controller.read_trash(&conn)?;
data_result(repeated_trash)
@ -16,7 +18,7 @@ pub(crate) async fn read_trash_handler(controller: Unit<Arc<TrashCan>>) -> DataR
#[tracing::instrument(skip(identifier, controller), err)]
pub(crate) async fn putback_trash_handler(
identifier: Data<TrashIdentifier>,
controller: Unit<Arc<TrashCan>>,
controller: Unit<Arc<TrashController>>,
) -> Result<(), WorkspaceError> {
let _ = controller.putback(&identifier.id).await?;
Ok(())
@ -25,20 +27,20 @@ pub(crate) async fn putback_trash_handler(
#[tracing::instrument(skip(identifiers, controller), err)]
pub(crate) async fn delete_trash_handler(
identifiers: Data<TrashIdentifiers>,
controller: Unit<Arc<TrashCan>>,
controller: Unit<Arc<TrashController>>,
) -> Result<(), WorkspaceError> {
let _ = controller.delete(identifiers.into_inner()).await?;
Ok(())
}
#[tracing::instrument(skip(controller), err)]
pub(crate) async fn restore_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
pub(crate) async fn restore_all_handler(controller: Unit<Arc<TrashController>>) -> Result<(), WorkspaceError> {
let _ = controller.restore_all().await?;
Ok(())
}
#[tracing::instrument(skip(controller), err)]
pub(crate) async fn delete_all_handler(controller: Unit<Arc<TrashCan>>) -> Result<(), WorkspaceError> {
pub(crate) async fn delete_all_handler(controller: Unit<Arc<TrashController>>) -> Result<(), WorkspaceError> {
let _ = controller.delete_all().await?;
Ok(())
}

View File

@ -0,0 +1,3 @@
pub mod controller;
pub mod event_handler;
mod sql;

View File

@ -1,6 +1,55 @@
use crate::entities::trash::{Trash, TrashType};
use crate::{
entities::trash::{RepeatedTrash, Trash, TrashType},
errors::WorkspaceError,
};
use diesel::sql_types::Integer;
use flowy_database::schema::trash_table;
use flowy_database::{
prelude::*,
schema::{trash_table, trash_table::dsl},
SqliteConnection,
};
pub struct TrashTableSql {}
impl TrashTableSql {
pub(crate) fn create_trash(repeated_trash: Vec<Trash>, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
for trash in repeated_trash {
let trash_table: TrashTable = trash.into();
match diesel_record_count!(trash_table, &trash_table.id, conn) {
0 => diesel_insert_table!(trash_table, &trash_table, conn),
_ => {
let changeset = TrashTableChangeset::from(trash_table);
diesel_update_table!(trash_table, changeset, conn)
},
}
}
Ok(())
}
pub(crate) fn read_all(conn: &SqliteConnection) -> Result<RepeatedTrash, WorkspaceError> {
let trash_tables = dsl::trash_table.load::<TrashTable>(conn)?;
let items = trash_tables.into_iter().map(|t| t.into()).collect::<Vec<Trash>>();
Ok(RepeatedTrash { items })
}
pub(crate) fn delete_all(conn: &SqliteConnection) -> Result<(), WorkspaceError> {
let _ = diesel::delete(dsl::trash_table).execute(conn)?;
Ok(())
}
pub(crate) fn read(trash_id: &str, conn: &SqliteConnection) -> Result<TrashTable, WorkspaceError> {
let trash_table = dsl::trash_table
.filter(trash_table::id.eq(trash_id))
.first::<TrashTable>(conn)?;
Ok(trash_table)
}
pub(crate) fn delete_trash(trash_id: &str, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_delete_table!(trash_table, trash_id, conn);
Ok(())
}
}
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "trash_table"]

View File

@ -11,8 +11,12 @@ use crate::{
errors::{internal_error, WorkspaceError, WorkspaceResult},
module::{WorkspaceDatabase, WorkspaceUser},
notify::{send_dart_notification, WorkspaceNotification},
services::{server::Server, TrashCan, TrashEvent},
sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
services::{
server::Server,
view::sql::{ViewTable, ViewTableChangeset, ViewTableSql},
TrashController,
TrashEvent,
},
};
use flowy_document::module::FlowyDocument;
use flowy_workspace_infra::entities::share::{ExportData, ExportParams};
@ -24,7 +28,7 @@ pub(crate) struct ViewController {
user: Arc<dyn WorkspaceUser>,
server: Server,
database: Arc<dyn WorkspaceDatabase>,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
document: Arc<FlowyDocument>,
}
@ -33,7 +37,7 @@ impl ViewController {
user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>,
server: Server,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
document: Arc<FlowyDocument>,
) -> Self {
Self {
@ -296,7 +300,7 @@ impl ViewController {
async fn handle_trash_event(
database: Arc<dyn WorkspaceDatabase>,
document: Arc<FlowyDocument>,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
event: TrashEvent,
) {
let db_result = database.db_connection();
@ -372,7 +376,11 @@ fn notify_dart(view_table: ViewTable, notification: WorkspaceNotification) {
}
#[tracing::instrument(skip(belong_to_id, trash_can, conn), fields(view_count), err)]
fn notify_views_changed(belong_to_id: &str, trash_can: Arc<TrashCan>, conn: &SqliteConnection) -> WorkspaceResult<()> {
fn notify_views_changed(
belong_to_id: &str,
trash_can: Arc<TrashController>,
conn: &SqliteConnection,
) -> WorkspaceResult<()> {
let repeated_view = read_local_belonging_view(belong_to_id, trash_can.clone(), conn)?;
tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str());
send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged)
@ -383,7 +391,7 @@ fn notify_views_changed(belong_to_id: &str, trash_can: Arc<TrashCan>, conn: &Sql
fn read_local_belonging_view(
belong_to_id: &str,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
conn: &SqliteConnection,
) -> WorkspaceResult<RepeatedView> {
let mut view_tables = ViewTableSql::read_views(belong_to_id, conn)?;

View File

@ -13,7 +13,7 @@ use crate::{
},
},
errors::WorkspaceError,
services::{TrashCan, ViewController},
services::{TrashController, ViewController},
};
use flowy_document_infra::entities::doc::DocDelta;
use flowy_workspace_infra::entities::share::{ExportData, ExportParams, ExportRequest};
@ -63,7 +63,7 @@ pub(crate) async fn apply_doc_delta_handler(
pub(crate) async fn delete_view_handler(
data: Data<QueryViewRequest>,
controller: Unit<Arc<ViewController>>,
trash_can: Unit<Arc<TrashCan>>,
trash_can: Unit<Arc<TrashController>>,
) -> Result<(), WorkspaceError> {
let params: ViewIdentifiers = data.into_inner().try_into()?;
for view_id in &params.view_ids {

View File

@ -0,0 +1,3 @@
pub mod controller;
pub mod event_handler;
mod sql;

View File

@ -1,15 +1,112 @@
use diesel::sql_types::Integer;
use flowy_database::schema::view_table;
use lib_infra::timestamp;
use crate::{
entities::{
trash::{Trash, TrashType},
view::{RepeatedView, UpdateViewParams, View, ViewType},
},
sql_tables::app::AppTable,
errors::WorkspaceError,
services::app::sql::AppTable,
};
use diesel::sql_types::Integer;
use flowy_database::{
prelude::*,
schema::{view_table, view_table::dsl},
SqliteConnection,
};
use lib_infra::timestamp;
pub struct ViewTableSql {}
impl ViewTableSql {
pub(crate) fn create_view(view_table: ViewTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
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(())
}
pub(crate) fn read_view(view_id: &str, conn: &SqliteConnection) -> Result<ViewTable, WorkspaceError> {
// https://docs.diesel.rs/diesel/query_builder/struct.UpdateStatement.html
// let mut filter =
// dsl::view_table.filter(view_table::id.eq(view_id)).into_boxed();
// if let Some(is_trash) = is_trash {
// filter = filter.filter(view_table::is_trash.eq(is_trash));
// }
// let repeated_view = filter.first::<ViewTable>(conn)?;
let view_table = dsl::view_table
.filter(view_table::id.eq(view_id))
.first::<ViewTable>(conn)?;
Ok(view_table)
}
// belong_to_id will be the app_id or view_id.
pub(crate) fn read_views(belong_to_id: &str, conn: &SqliteConnection) -> Result<Vec<ViewTable>, WorkspaceError> {
let view_tables = dsl::view_table
.filter(view_table::belong_to_id.eq(belong_to_id))
.order(view_table::create_time.asc())
.into_boxed()
.load::<ViewTable>(conn)?;
Ok(view_tables)
}
pub(crate) fn update_view(changeset: ViewTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_update_table!(view_table, changeset, conn);
Ok(())
}
pub(crate) fn delete_view(view_id: &str, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_delete_table!(view_table, view_id, conn);
Ok(())
}
}
// pub(crate) fn read_views(
// belong_to_id: &str,
// is_trash: Option<bool>,
// conn: &SqliteConnection,
// ) -> Result<RepeatedView, WorkspaceError> {
// let views = dsl::view_table
// .inner_join(trash_table::dsl::trash_table.on(trash_id.ne(view_table::
// id))) .filter(view_table::belong_to_id.eq(belong_to_id))
// .select((
// view_table::id,
// view_table::belong_to_id,
// view_table::name,
// view_table::desc,
// view_table::modified_time,
// view_table::create_time,
// view_table::thumbnail,
// view_table::view_type,
// view_table::version,
// ))
// .load(conn)?
// .into_iter()
// .map(
// |(id, belong_to_id, name, desc, create_time, modified_time,
// thumbnail, view_type, version)| { ViewTable {
// id,
// belong_to_id,
// name,
// desc,
// modified_time,
// create_time,
// thumbnail,
// view_type,
// version,
// is_trash: false,
// }
// .into()
// },
// )
// .collect::<Vec<View>>();
//
// Ok(RepeatedView { items: views })
// }
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[belongs_to(AppTable, foreign_key = "belong_to_id")]

View File

@ -2,24 +2,19 @@ use crate::{
errors::*,
module::{WorkspaceDatabase, WorkspaceUser},
notify::*,
services::{read_local_workspace_apps, server::Server, AppController, TrashCan, ViewController},
sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
services::{
read_local_workspace_apps,
server::Server,
workspace::sql::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
AppController,
TrashController,
ViewController,
},
};
use chrono::Utc;
use flowy_database::SqliteConnection;
use flowy_document_infra::{entities::doc::DocDelta, user_default::initial_read_me};
use flowy_workspace_infra::{
entities::{app::RepeatedApp, view::View, workspace::*},
user_default,
};
use lazy_static::lazy_static;
use lib_infra::{entities::network_state::NetworkType, kv::KV};
use parking_lot::RwLock;
use std::{collections::HashMap, sync::Arc};
lazy_static! {
static ref INIT_WORKSPACE: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
}
use flowy_workspace_infra::entities::{app::RepeatedApp, view::View, workspace::*};
use lib_infra::kv::KV;
use std::sync::Arc;
pub struct WorkspaceController {
pub user: Arc<dyn WorkspaceUser>,
@ -27,7 +22,7 @@ pub struct WorkspaceController {
pub(crate) view_controller: Arc<ViewController>,
pub(crate) database: Arc<dyn WorkspaceDatabase>,
pub(crate) app_controller: Arc<AppController>,
pub(crate) trash_can: Arc<TrashCan>,
pub(crate) trash_controller: Arc<TrashController>,
server: Server,
}
@ -37,13 +32,9 @@ impl WorkspaceController {
database: Arc<dyn WorkspaceDatabase>,
app_controller: Arc<AppController>,
view_controller: Arc<ViewController>,
trash_can: Arc<TrashCan>,
trash_can: Arc<TrashController>,
server: Server,
) -> Self {
if let Ok(token) = user.token() {
INIT_WORKSPACE.write().insert(token, false);
}
let workspace_sql = Arc::new(WorkspaceTableSql {});
Self {
user,
@ -51,92 +42,12 @@ impl WorkspaceController {
view_controller,
database,
app_controller,
trash_can,
trash_controller: trash_can,
server,
}
}
async fn init(&self, token: &str) -> Result<(), WorkspaceError> {
log::debug!("Start initializing workspace");
if let Some(is_init) = INIT_WORKSPACE.read().get(token) {
if *is_init {
return Ok(());
}
}
log::debug!("Finish initializing workspace");
INIT_WORKSPACE.write().insert(token.to_owned(), true);
let _ = self.server.init();
let _ = self.trash_can.init()?;
let _ = self.view_controller.init()?;
let _ = self.app_controller.init()?;
Ok(())
}
pub fn network_state_changed(&self, new_type: NetworkType) {
match new_type {
NetworkType::UnknownNetworkType => {},
NetworkType::Wifi => {},
NetworkType::Cell => {},
NetworkType::Ethernet => {},
}
}
pub async fn user_did_sign_in(&self, token: &str) -> WorkspaceResult<()> {
// TODO: (nathan) do something here
log::debug!("workspace initialize after sign in");
let _ = self.init(token).await?;
Ok(())
}
pub async fn user_did_logout(&self) {
// TODO: (nathan) do something here
}
pub async fn user_session_expired(&self) {
// TODO: (nathan) do something here
}
pub async fn user_did_sign_up(&self, _token: &str) -> WorkspaceResult<()> {
log::debug!("Create user default workspace");
let time = Utc::now();
let mut workspace = user_default::create_default_workspace(time);
let apps = workspace.take_apps().into_inner();
let cloned_workspace = workspace.clone();
let _ = self.create_workspace(workspace).await?;
for mut app in apps {
let views = app.take_belongings().into_inner();
let _ = self.app_controller.create_app(app).await?;
for (index, view) in views.into_iter().enumerate() {
if index == 0 {
let delta = initial_read_me();
let doc_delta = DocDelta {
doc_id: view.id.clone(),
data: delta.to_json(),
};
let _ = self.view_controller.apply_doc_delta(doc_delta).await?;
self.view_controller.set_latest_view(&view);
}
let _ = self.view_controller.create_view(view).await?;
}
}
let token = self.user.token()?;
let repeated_workspace = RepeatedWorkspace {
items: vec![cloned_workspace],
};
send_dart_notification(&token, WorkspaceNotification::UserCreateWorkspace)
.payload(repeated_workspace)
.send();
log::debug!("workspace initialize after sign up");
let _ = self.init(&token).await?;
Ok(())
}
pub(crate) fn init(&self) -> Result<(), WorkspaceError> { Ok(()) }
pub(crate) async fn create_workspace_from_params(
&self,
@ -263,7 +174,7 @@ impl WorkspaceController {
}
#[tracing::instrument(level = "debug", skip(self, conn), err)]
fn read_local_workspaces(
pub(crate) fn read_local_workspaces(
&self,
workspace_id: Option<String>,
user_id: &str,
@ -301,7 +212,7 @@ impl WorkspaceController {
#[tracing::instrument(level = "debug", skip(self, conn), err)]
fn read_local_apps(&self, workspace_id: &str, conn: &SqliteConnection) -> Result<RepeatedApp, WorkspaceError> {
let repeated_app = read_local_workspace_apps(workspace_id, self.trash_can.clone(), conn)?;
let repeated_app = read_local_workspace_apps(workspace_id, self.trash_controller.clone(), conn)?;
Ok(repeated_app)
}
}
@ -354,7 +265,11 @@ impl WorkspaceController {
}
#[tracing::instrument(level = "debug", skip(self), err)]
fn read_workspaces_on_server(&self, user_id: String, params: WorkspaceIdentifier) -> Result<(), WorkspaceError> {
pub(crate) fn read_workspaces_on_server(
&self,
user_id: String,
params: WorkspaceIdentifier,
) -> Result<(), WorkspaceError> {
let (token, server) = self.token_with_server()?;
let workspace_sql = self.workspace_sql.clone();
let app_ctrl = self.app_controller.clone();

View File

@ -0,0 +1,3 @@
pub mod controller;
pub mod event_handler;
pub(crate) mod sql;

View File

@ -1,15 +1,15 @@
use crate::{
entities::{
app::RepeatedApp,
workspace::{UpdateWorkspaceParams, Workspace},
},
errors::WorkspaceError,
};
use diesel::SqliteConnection;
use flowy_database::{
prelude::*,
schema::{workspace_table, workspace_table::dsl},
};
use crate::{
errors::WorkspaceError,
sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset},
};
pub(crate) struct WorkspaceTableSql {}
impl WorkspaceTableSql {
@ -64,3 +64,69 @@ impl WorkspaceTableSql {
Ok(())
}
}
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable)]
#[table_name = "workspace_table"]
pub struct WorkspaceTable {
pub id: String,
pub name: String,
pub desc: String,
pub modified_time: i64,
pub create_time: i64,
pub user_id: String,
pub version: i64,
}
impl WorkspaceTable {
#[allow(dead_code)]
pub fn new(workspace: Workspace, user_id: &str) -> Self {
WorkspaceTable {
id: workspace.id,
name: workspace.name,
desc: workspace.desc,
modified_time: workspace.modified_time,
create_time: workspace.create_time,
user_id: user_id.to_owned(),
version: 0,
}
}
}
impl std::convert::From<WorkspaceTable> for Workspace {
fn from(table: WorkspaceTable) -> Self {
Workspace {
id: table.id,
name: table.name,
desc: table.desc,
apps: RepeatedApp::default(),
modified_time: table.modified_time,
create_time: table.create_time,
}
}
}
#[derive(AsChangeset, Identifiable, Clone, Default, Debug)]
#[table_name = "workspace_table"]
pub struct WorkspaceTableChangeset {
pub id: String,
pub name: Option<String>,
pub desc: Option<String>,
}
impl WorkspaceTableChangeset {
pub fn new(params: UpdateWorkspaceParams) -> Self {
WorkspaceTableChangeset {
id: params.id,
name: params.name,
desc: params.desc,
}
}
pub(crate) fn from_table(table: WorkspaceTable) -> Self {
WorkspaceTableChangeset {
id: table.id,
name: Some(table.name),
desc: Some(table.desc),
}
}
}

View File

@ -1,76 +0,0 @@
use flowy_database::{
prelude::*,
schema::{app_table, app_table::dsl},
SqliteConnection,
};
use crate::{
errors::WorkspaceError,
sql_tables::app::{AppTable, AppTableChangeset},
};
pub struct AppTableSql {}
impl AppTableSql {
pub(crate) fn create_app(app_table: AppTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
match diesel_record_count!(app_table, &app_table.id, conn) {
0 => diesel_insert_table!(app_table, &app_table, conn),
_ => {
let changeset = AppTableChangeset::from_table(app_table);
diesel_update_table!(app_table, changeset, conn)
},
}
Ok(())
}
pub(crate) fn update_app(changeset: AppTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_update_table!(app_table, changeset, conn);
Ok(())
}
pub(crate) fn read_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
let filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed();
let app_table = filter.first::<AppTable>(conn)?;
Ok(app_table)
}
pub(crate) fn read_workspace_apps(
workspace_id: &str,
is_trash: bool,
conn: &SqliteConnection,
) -> Result<Vec<AppTable>, WorkspaceError> {
let app_table = dsl::app_table
.filter(app_table::workspace_id.eq(workspace_id))
.filter(app_table::is_trash.eq(is_trash))
.order(app_table::create_time.asc())
.load::<AppTable>(conn)?;
Ok(app_table)
}
pub(crate) fn delete_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
let app_table = dsl::app_table
.filter(app_table::id.eq(app_id))
.first::<AppTable>(conn)?;
diesel_delete_table!(app_table, app_id, conn);
Ok(app_table)
}
// pub(crate) fn read_views_belong_to_app(
// &self,
// app_id: &str,
// ) -> Result<Vec<ViewTable>, WorkspaceError> {
// let conn = self.database.db_connection()?;
//
// let views = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
// let app_table: AppTable = dsl::app_table
// .filter(app_table::id.eq(app_id))
// .first::<AppTable>(&*(conn))?;
// let views =
// ViewTable::belonging_to(&app_table).load::<ViewTable>(&*conn)?;
// Ok(views)
// })?;
//
// Ok(views)
// }
}

View File

@ -1,5 +0,0 @@
mod app_sql;
mod app_table;
pub(crate) use app_sql::*;
pub(crate) use app_table::*;

View File

@ -1,4 +0,0 @@
pub mod app;
pub mod trash;
pub mod view;
pub mod workspace;

View File

@ -1,5 +0,0 @@
mod trash_sql;
mod trash_table;
pub(crate) use trash_sql::*;
pub(crate) use trash_table::*;

View File

@ -1,53 +0,0 @@
use flowy_database::{
prelude::*,
schema::{trash_table, trash_table::dsl},
SqliteConnection,
};
use crate::{
entities::trash::{RepeatedTrash, Trash},
errors::WorkspaceError,
sql_tables::trash::{TrashTable, TrashTableChangeset},
};
pub struct TrashTableSql {}
impl TrashTableSql {
pub(crate) fn create_trash(repeated_trash: Vec<Trash>, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
for trash in repeated_trash {
let trash_table: TrashTable = trash.into();
match diesel_record_count!(trash_table, &trash_table.id, conn) {
0 => diesel_insert_table!(trash_table, &trash_table, conn),
_ => {
let changeset = TrashTableChangeset::from(trash_table);
diesel_update_table!(trash_table, changeset, conn)
},
}
}
Ok(())
}
pub(crate) fn read_all(conn: &SqliteConnection) -> Result<RepeatedTrash, WorkspaceError> {
let trash_tables = dsl::trash_table.load::<TrashTable>(conn)?;
let items = trash_tables.into_iter().map(|t| t.into()).collect::<Vec<Trash>>();
Ok(RepeatedTrash { items })
}
pub(crate) fn delete_all(conn: &SqliteConnection) -> Result<(), WorkspaceError> {
let _ = diesel::delete(dsl::trash_table).execute(conn)?;
Ok(())
}
pub(crate) fn read(trash_id: &str, conn: &SqliteConnection) -> Result<TrashTable, WorkspaceError> {
let trash_table = dsl::trash_table
.filter(trash_table::id.eq(trash_id))
.first::<TrashTable>(conn)?;
Ok(trash_table)
}
pub(crate) fn delete_trash(trash_id: &str, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_delete_table!(trash_table, trash_id, conn);
Ok(())
}
}

View File

@ -1,5 +0,0 @@
mod view_sql;
mod view_table;
pub use view_sql::*;
pub use view_table::*;

View File

@ -1,104 +0,0 @@
use flowy_database::{
prelude::*,
schema::{view_table, view_table::dsl},
SqliteConnection,
};
use crate::{
errors::WorkspaceError,
sql_tables::view::{ViewTable, ViewTableChangeset},
};
pub struct ViewTableSql {}
impl ViewTableSql {
pub(crate) fn create_view(view_table: ViewTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
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(())
}
pub(crate) fn read_view(view_id: &str, conn: &SqliteConnection) -> Result<ViewTable, WorkspaceError> {
// https://docs.diesel.rs/diesel/query_builder/struct.UpdateStatement.html
// let mut filter =
// dsl::view_table.filter(view_table::id.eq(view_id)).into_boxed();
// if let Some(is_trash) = is_trash {
// filter = filter.filter(view_table::is_trash.eq(is_trash));
// }
// let repeated_view = filter.first::<ViewTable>(conn)?;
let view_table = dsl::view_table
.filter(view_table::id.eq(view_id))
.first::<ViewTable>(conn)?;
Ok(view_table)
}
// belong_to_id will be the app_id or view_id.
pub(crate) fn read_views(belong_to_id: &str, conn: &SqliteConnection) -> Result<Vec<ViewTable>, WorkspaceError> {
let view_tables = dsl::view_table
.filter(view_table::belong_to_id.eq(belong_to_id))
.order(view_table::create_time.asc())
.into_boxed()
.load::<ViewTable>(conn)?;
Ok(view_tables)
}
pub(crate) fn update_view(changeset: ViewTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_update_table!(view_table, changeset, conn);
Ok(())
}
pub(crate) fn delete_view(view_id: &str, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_delete_table!(view_table, view_id, conn);
Ok(())
}
}
// pub(crate) fn read_views(
// belong_to_id: &str,
// is_trash: Option<bool>,
// conn: &SqliteConnection,
// ) -> Result<RepeatedView, WorkspaceError> {
// let views = dsl::view_table
// .inner_join(trash_table::dsl::trash_table.on(trash_id.ne(view_table::
// id))) .filter(view_table::belong_to_id.eq(belong_to_id))
// .select((
// view_table::id,
// view_table::belong_to_id,
// view_table::name,
// view_table::desc,
// view_table::modified_time,
// view_table::create_time,
// view_table::thumbnail,
// view_table::view_type,
// view_table::version,
// ))
// .load(conn)?
// .into_iter()
// .map(
// |(id, belong_to_id, name, desc, create_time, modified_time,
// thumbnail, view_type, version)| { ViewTable {
// id,
// belong_to_id,
// name,
// desc,
// modified_time,
// create_time,
// thumbnail,
// view_type,
// version,
// is_trash: false,
// }
// .into()
// },
// )
// .collect::<Vec<View>>();
//
// Ok(RepeatedView { items: views })
// }

View File

@ -1,5 +0,0 @@
mod workspace_sql;
mod workspace_table;
pub(crate) use workspace_sql::*;
pub(crate) use workspace_table::*;

View File

@ -1,71 +0,0 @@
use crate::entities::{
app::RepeatedApp,
workspace::{UpdateWorkspaceParams, Workspace},
};
use flowy_database::schema::workspace_table;
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable)]
#[table_name = "workspace_table"]
pub struct WorkspaceTable {
pub id: String,
pub name: String,
pub desc: String,
pub modified_time: i64,
pub create_time: i64,
pub user_id: String,
pub version: i64,
}
impl WorkspaceTable {
#[allow(dead_code)]
pub fn new(workspace: Workspace, user_id: &str) -> Self {
WorkspaceTable {
id: workspace.id,
name: workspace.name,
desc: workspace.desc,
modified_time: workspace.modified_time,
create_time: workspace.create_time,
user_id: user_id.to_owned(),
version: 0,
}
}
}
impl std::convert::From<WorkspaceTable> for Workspace {
fn from(table: WorkspaceTable) -> Self {
Workspace {
id: table.id,
name: table.name,
desc: table.desc,
apps: RepeatedApp::default(),
modified_time: table.modified_time,
create_time: table.create_time,
}
}
}
#[derive(AsChangeset, Identifiable, Clone, Default, Debug)]
#[table_name = "workspace_table"]
pub struct WorkspaceTableChangeset {
pub id: String,
pub name: Option<String>,
pub desc: Option<String>,
}
impl WorkspaceTableChangeset {
pub fn new(params: UpdateWorkspaceParams) -> Self {
WorkspaceTableChangeset {
id: params.id,
name: params.name,
desc: params.desc,
}
}
pub(crate) fn from_table(table: WorkspaceTable) -> Self {
WorkspaceTableChangeset {
id: table.id,
name: Some(table.name),
desc: Some(table.desc),
}
}
}

View File

@ -3,7 +3,7 @@ mod deps_resolve;
pub mod module;
use crate::deps_resolve::WorkspaceDepsResolver;
use backend_service::configuration::ClientServerConfiguration;
use flowy_core::{errors::WorkspaceError, prelude::WorkspaceController};
use flowy_core::{errors::WorkspaceError, module::init_core, prelude::FlowyCore};
use flowy_document::module::FlowyDocument;
use flowy_user::{
prelude::UserStatus,
@ -66,7 +66,7 @@ pub struct FlowySDK {
config: FlowySDKConfig,
pub user_session: Arc<UserSession>,
pub flowy_document: Arc<FlowyDocument>,
pub workspace_ctrl: Arc<WorkspaceController>,
pub core: Arc<FlowyCore>,
pub dispatcher: Arc<EventDispatcher>,
}
@ -81,17 +81,17 @@ impl FlowySDK {
let user_config = UserSessionConfig::new(&config.root, &config.server_config, &session_cache_key);
let user_session = Arc::new(UserSession::new(user_config));
let flowy_document = mk_document_module(user_session.clone(), &config.server_config);
let workspace_ctrl =
mk_workspace_controller(user_session.clone(), flowy_document.clone(), &config.server_config);
let modules = mk_modules(workspace_ctrl.clone(), user_session.clone());
let core = mk_core(user_session.clone(), flowy_document.clone(), &config.server_config);
let modules = mk_modules(core.clone(), user_session.clone());
let dispatcher = Arc::new(EventDispatcher::construct(|| modules));
_init(&dispatcher, user_session.clone(), workspace_ctrl.clone());
_init(&dispatcher, user_session.clone(), core.clone());
Self {
config,
user_session,
flowy_document,
workspace_ctrl,
core,
dispatcher,
}
}
@ -99,38 +99,35 @@ impl FlowySDK {
pub fn dispatcher(&self) -> Arc<EventDispatcher> { self.dispatcher.clone() }
}
fn _init(dispatch: &EventDispatcher, user_session: Arc<UserSession>, workspace_controller: Arc<WorkspaceController>) {
fn _init(dispatch: &EventDispatcher, user_session: Arc<UserSession>, core: Arc<FlowyCore>) {
let user_status_subscribe = user_session.notifier.user_status_subscribe();
let network_status_subscribe = user_session.notifier.network_type_subscribe();
let cloned_workspace_controller = workspace_controller.clone();
let cloned_core = core.clone();
dispatch.spawn(async move {
user_session.init();
_listen_user_status(user_status_subscribe, workspace_controller.clone()).await;
_listen_user_status(user_status_subscribe, core.clone()).await;
});
dispatch.spawn(async move {
_listen_network_status(network_status_subscribe, cloned_workspace_controller).await;
_listen_network_status(network_status_subscribe, cloned_core).await;
});
}
async fn _listen_user_status(
mut subscribe: broadcast::Receiver<UserStatus>,
workspace_controller: Arc<WorkspaceController>,
) {
async fn _listen_user_status(mut subscribe: broadcast::Receiver<UserStatus>, core: Arc<FlowyCore>) {
while let Ok(status) = subscribe.recv().await {
let result = || async {
match status {
UserStatus::Login { token } => {
let _ = workspace_controller.user_did_sign_in(&token).await?;
let _ = core.user_did_sign_in(&token).await?;
},
UserStatus::Logout { .. } => {
workspace_controller.user_did_logout().await;
core.user_did_logout().await;
},
UserStatus::Expired { .. } => {
workspace_controller.user_session_expired().await;
core.user_session_expired().await;
},
UserStatus::SignUp { profile, ret } => {
let _ = workspace_controller.user_did_sign_up(&profile.token).await?;
let _ = core.user_did_sign_up(&profile.token).await?;
let _ = ret.send(());
},
}
@ -144,12 +141,9 @@ async fn _listen_user_status(
}
}
async fn _listen_network_status(
mut subscribe: broadcast::Receiver<NetworkType>,
workspace_controller: Arc<WorkspaceController>,
) {
async fn _listen_network_status(mut subscribe: broadcast::Receiver<NetworkType>, core: Arc<FlowyCore>) {
while let Ok(new_type) = subscribe.recv().await {
workspace_controller.network_state_changed(new_type);
core.network_state_changed(new_type);
}
}
@ -170,12 +164,12 @@ fn init_log(config: &FlowySDKConfig) {
}
}
fn mk_workspace_controller(
fn mk_core(
user_session: Arc<UserSession>,
flowy_document: Arc<FlowyDocument>,
server_config: &ClientServerConfiguration,
) -> Arc<WorkspaceController> {
) -> Arc<FlowyCore> {
let workspace_deps = WorkspaceDepsResolver::new(user_session);
let (user, database) = workspace_deps.split_into();
flowy_core::module::init_workspace_controller(user, database, flowy_document, server_config)
init_core(user, database, flowy_document, server_config)
}

View File

@ -1,22 +1,19 @@
use crate::deps_resolve::DocumentDepsResolver;
use backend_service::configuration::ClientServerConfiguration;
use flowy_core::prelude::WorkspaceController;
use flowy_core::prelude::FlowyCore;
use flowy_document::module::FlowyDocument;
use flowy_user::services::user::UserSession;
use lib_dispatch::prelude::Module;
use std::sync::Arc;
pub fn mk_modules(workspace_controller: Arc<WorkspaceController>, user_session: Arc<UserSession>) -> Vec<Module> {
pub fn mk_modules(core: Arc<FlowyCore>, user_session: Arc<UserSession>) -> Vec<Module> {
let user_module = mk_user_module(user_session);
let workspace_module = mk_workspace_module(workspace_controller);
let workspace_module = mk_core_module(core);
vec![user_module, workspace_module]
}
fn mk_user_module(user_session: Arc<UserSession>) -> Module { flowy_user::module::create(user_session) }
fn mk_workspace_module(workspace_controller: Arc<WorkspaceController>) -> Module {
flowy_core::module::create(workspace_controller)
}
fn mk_core_module(core: Arc<FlowyCore>) -> Module { flowy_core::module::create(core) }
pub fn mk_document_module(
user_session: Arc<UserSession>,