From 01c9620e033b28fdacc4626a541ad767c73842cd Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 27 Sep 2021 23:23:23 +0800 Subject: [PATCH] add server with flowy_document test --- backend/Cargo.toml | 6 +- backend/src/service/doc/edit_doc_context.rs | 1 - backend/src/service/doc/ws_handler.rs | 3 +- backend/src/service/log/mod.rs | 2 +- backend/src/service/user/user_default.rs | 4 +- backend/src/service/ws/router.rs | 1 + backend/src/service/ws/ws_client.rs | 2 +- backend/tests/api/auth.rs | 24 +-- backend/tests/api/workspace.rs | 9 +- backend/tests/document/helper.rs | 97 ++++++++++++ backend/tests/{ws => document}/mod.rs | 0 backend/tests/document/ws.rs | 12 ++ backend/tests/helper.rs | 138 +++++++----------- backend/tests/main.rs | 2 +- backend/tests/ws/helper.rs | 76 ---------- backend/tests/ws/ws.rs | 13 -- flowy-test/temp/flowy/flowy.log.2021-09-27 | 0 rust-lib/Cargo.toml | 1 - rust-lib/dart-ffi/src/lib.rs | 12 +- rust-lib/flowy-document/src/module.rs | 16 +- .../src/services/doc/doc_controller.rs | 11 +- .../src/services/doc/edit_doc_context.rs | 6 +- .../src/services/doc/rev_manager.rs | 11 +- .../src/sql_tables/doc/doc_op_sql.rs | 9 +- rust-lib/flowy-editor/Cargo.toml | 8 - rust-lib/flowy-editor/src/lib.rs | 7 - rust-lib/flowy-net/src/config.rs | 38 +++++ rust-lib/flowy-sdk/Cargo.toml | 1 + rust-lib/flowy-sdk/src/lib.rs | 34 +++-- rust-lib/flowy-sdk/src/module.rs | 35 +++-- rust-lib/flowy-test/src/lib.rs | 13 +- rust-lib/flowy-user/src/errors.rs | 15 +- .../flowy-user/src/services/server/mod.rs | 9 +- .../src/services/server/server_api.rs | 41 ++++-- .../src/services/server/server_api_mock.rs | 6 +- .../flowy-user/src/services/user/builder.rs | 5 +- .../src/services/user/user_session.rs | 30 +++- .../src/entities/view/view_create.rs | 6 +- rust-lib/flowy-workspace/src/module.rs | 17 ++- .../src/services/server/mod.rs | 11 +- .../src/services/server/server_api.rs | 84 ++++++++--- .../src/services/view_controller.rs | 13 +- rust-lib/flowy-ws/src/ws.rs | 26 +++- 43 files changed, 515 insertions(+), 340 deletions(-) create mode 100644 backend/tests/document/helper.rs rename backend/tests/{ws => document}/mod.rs (100%) create mode 100644 backend/tests/document/ws.rs delete mode 100644 backend/tests/ws/helper.rs delete mode 100644 backend/tests/ws/ws.rs create mode 100644 flowy-test/temp/flowy/flowy.log.2021-09-27 delete mode 100644 rust-lib/flowy-editor/Cargo.toml delete mode 100644 rust-lib/flowy-editor/src/lib.rs diff --git a/backend/Cargo.toml b/backend/Cargo.toml index bf1e13913d..cef6772c94 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -95,4 +95,8 @@ once_cell = "1.7.2" linkify = "0.5.0" flowy-user = { path = "../rust-lib/flowy-user" } flowy-workspace = { path = "../rust-lib/flowy-workspace" } -flowy-ws = { path = "../rust-lib/flowy-ws" } \ No newline at end of file +flowy-ws = { path = "../rust-lib/flowy-ws" } +flowy-sdk = { path = "../rust-lib/flowy-sdk" } +flowy-test = { path = "../rust-lib/flowy-test" } +flowy-infra = { path = "../rust-lib/flowy-infra" } +flowy-ot = { path = "../rust-lib/flowy-ot" } \ No newline at end of file diff --git a/backend/src/service/doc/edit_doc_context.rs b/backend/src/service/doc/edit_doc_context.rs index 9a5cba68a5..e97faaf25c 100644 --- a/backend/src/service/doc/edit_doc_context.rs +++ b/backend/src/service/doc/edit_doc_context.rs @@ -22,7 +22,6 @@ use parking_lot::RwLock; use protobuf::Message; use sqlx::PgPool; use std::{ - cmp::min, convert::TryInto, sync::{ atomic::{AtomicI64, Ordering::SeqCst}, diff --git a/backend/src/service/doc/ws_handler.rs b/backend/src/service/doc/ws_handler.rs index f2273c318b..d987790713 100644 --- a/backend/src/service/doc/ws_handler.rs +++ b/backend/src/service/doc/ws_handler.rs @@ -6,8 +6,7 @@ use crate::service::{ }; use actix_web::web::Data; -use crate::service::ws::WsUser; -use flowy_document::protobuf::{QueryDocParams, Revision, RevisionRange, WsDataType, WsDocumentData}; +use flowy_document::protobuf::{QueryDocParams, Revision, WsDataType, WsDocumentData}; use flowy_net::errors::ServerError; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use protobuf::Message; diff --git a/backend/src/service/log/mod.rs b/backend/src/service/log/mod.rs index 48b25ff8e8..7e821832da 100644 --- a/backend/src/service/log/mod.rs +++ b/backend/src/service/log/mod.rs @@ -28,7 +28,7 @@ impl Builder { let env_filter = EnvFilter::new(self.env_filter); let subscriber = tracing_subscriber::fmt() .with_target(true) - .with_max_level(tracing::Level::TRACE) + .with_max_level(tracing::Level::DEBUG) .with_writer(std::io::stderr) .with_thread_ids(false) .compact() diff --git a/backend/src/service/user/user_default.rs b/backend/src/service/user/user_default.rs index 225e6aa6d3..66a27c3d53 100644 --- a/backend/src/service/user/user_default.rs +++ b/backend/src/service/user/user_default.rs @@ -8,7 +8,7 @@ use crate::{ }; use flowy_net::errors::ServerError; use flowy_workspace::{ - entities::view::VIEW_DEFAULT_DATA, + entities::view::DOC_DEFAULT_DATA, protobuf::{App, CreateViewParams, View, ViewType, Workspace}, }; @@ -62,7 +62,7 @@ async fn create_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result>, biz_handlers: Data, ) -> Result { + log::debug!("establish_ws_connection"); match LoggedUser::from_token(token.clone()) { Ok(user) => { let ws_user = WsUser::new(user.clone()); diff --git a/backend/src/service/ws/ws_client.rs b/backend/src/service/ws/ws_client.rs index b173026eb4..a034a278e9 100644 --- a/backend/src/service/ws/ws_client.rs +++ b/backend/src/service/ws/ws_client.rs @@ -3,7 +3,7 @@ use crate::{ service::{ user::LoggedUser, ws::{ - entities::{Connect, Disconnect, SessionId, Socket}, + entities::{Connect, Disconnect, Socket}, WsBizHandler, WsBizHandlers, WsMessageAdaptor, diff --git a/backend/tests/api/auth.rs b/backend/tests/api/auth.rs index efc53279d6..e342d98b33 100644 --- a/backend/tests/api/auth.rs +++ b/backend/tests/api/auth.rs @@ -1,9 +1,9 @@ -use crate::helper::{spawn_server, TestServer}; +use crate::helper::{spawn_user_server, TestUserServer}; use flowy_user::entities::{SignInParams, SignUpParams, SignUpResponse, UpdateUserParams}; #[actix_rt::test] async fn user_register() { - let app = spawn_server().await; + let app = spawn_user_server().await; let response = register_user(&app, "annie@appflowy.io", "HelloWorld123!").await; log::info!("{:?}", response); } @@ -11,7 +11,7 @@ async fn user_register() { #[actix_rt::test] #[should_panic] async fn user_sign_in_with_invalid_password() { - let app = spawn_server().await; + let app = spawn_user_server().await; let email = "annie@appflowy.io"; let password = "123"; let _ = register_user(&app, email, password).await; @@ -20,7 +20,7 @@ async fn user_sign_in_with_invalid_password() { #[actix_rt::test] #[should_panic] async fn user_sign_in_with_invalid_email() { - let app = spawn_server().await; + let app = spawn_user_server().await; let email = "annie@gmail@"; let password = "HelloWorld123!"; let _ = register_user(&app, email, password).await; @@ -28,7 +28,7 @@ async fn user_sign_in_with_invalid_email() { #[actix_rt::test] async fn user_sign_in() { - let app = spawn_server().await; + let app = spawn_user_server().await; let email = "annie@appflowy.io"; let password = "HelloWorld123!"; let _ = register_user(&app, email, password).await; @@ -42,7 +42,7 @@ async fn user_sign_in() { #[actix_rt::test] #[should_panic] async fn user_sign_out() { - let server = TestServer::new().await; + let server = TestUserServer::new().await; server.sign_out().await; // user_detail will be empty because use was sign out. @@ -51,13 +51,13 @@ async fn user_sign_out() { #[actix_rt::test] async fn user_get_detail() { - let server = TestServer::new().await; + let server = TestUserServer::new().await; log::info!("{:?}", server.get_user_profile().await); } #[actix_rt::test] async fn user_update_password() { - let mut server = spawn_server().await; + let mut server = spawn_user_server().await; let email = "annie@appflowy.io"; let password = "HelloWorld123!"; let sign_up_resp = register_user(&server, email, password).await; @@ -82,7 +82,7 @@ async fn user_update_password() { #[actix_rt::test] async fn user_update_name() { - let server = TestServer::new().await; + let server = TestUserServer::new().await; let name = "tom".to_string(); let params = UpdateUserParams::new(&server.user_id()).name(&name); @@ -94,7 +94,7 @@ async fn user_update_name() { #[actix_rt::test] async fn user_update_email() { - let server = TestServer::new().await; + let server = TestUserServer::new().await; let email = "123@gmail.com".to_string(); let params = UpdateUserParams::new(server.user_id()).email(&email); server.update_user_profile(params).await.unwrap(); @@ -104,14 +104,14 @@ async fn user_update_email() { } #[allow(dead_code)] -async fn sign_up_user(server: &TestServer) -> SignUpResponse { +async fn sign_up_user(server: &TestUserServer) -> SignUpResponse { let email = "annie@appflowy.io"; let password = "HelloWorld123!"; let response = register_user(server, email, password).await; response } -async fn register_user(server: &TestServer, email: &str, password: &str) -> SignUpResponse { +async fn register_user(server: &TestUserServer, email: &str, password: &str) -> SignUpResponse { let params = SignUpParams { email: email.to_string(), name: "annie".to_string(), diff --git a/backend/tests/api/workspace.rs b/backend/tests/api/workspace.rs index e01ceac264..2c4e71c0f7 100644 --- a/backend/tests/api/workspace.rs +++ b/backend/tests/api/workspace.rs @@ -2,12 +2,7 @@ use crate::helper::*; use flowy_workspace::entities::{ app::{DeleteAppParams, QueryAppParams, UpdateAppParams}, view::{DeleteViewParams, QueryViewParams, UpdateViewParams}, - workspace::{ - CreateWorkspaceParams, - DeleteWorkspaceParams, - QueryWorkspaceParams, - UpdateWorkspaceParams, - }, + workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams}, }; #[actix_rt::test] @@ -173,7 +168,7 @@ async fn view_delete() { #[actix_rt::test] async fn workspace_list_read() { - let mut server = spawn_server().await; + let mut server = spawn_user_server().await; let token = server.register_user().await.token; server.user_token = Some(token); for i in 0..3 { diff --git a/backend/tests/document/helper.rs b/backend/tests/document/helper.rs new file mode 100644 index 0000000000..2691cb78ca --- /dev/null +++ b/backend/tests/document/helper.rs @@ -0,0 +1,97 @@ +use crate::helper::*; +use flowy_document::{ + entities::doc::{CreateDocParams, DocDelta, QueryDocParams}, + module::FlowyDocument, + services::doc::edit_doc_context::EditDocContext, +}; +use flowy_infra::uuid; +use flowy_ot::core::Delta; +use flowy_sdk::{FlowySDK, FlowySDKConfig}; +use flowy_test::{prelude::root_dir, FlowyTestSDK}; +use flowy_user::{entities::SignUpParams, services::user::UserSession}; +use flowy_workspace::prelude::DOC_DEFAULT_DATA; +use std::{str::FromStr, sync::Arc}; + +pub struct DocumentTest { + server: TestServer, + sdk: FlowyTestSDK, + flowy_document: Arc, + user_session: Arc, + edit_context: Arc, +} + +#[derive(Clone)] +pub enum DocScript { + SendText(&'static str), + SendBinary(Vec), +} + +async fn create_doc(user_session: Arc, flowy_document: Arc) -> Arc { + let conn = user_session.db_pool().unwrap().get().unwrap(); + let doc_id = uuid(); + let params = CreateDocParams { + id: doc_id.clone(), + data: DOC_DEFAULT_DATA.to_string(), + }; + let _ = flowy_document.create(params, &*conn).unwrap(); + + let edit_context = flowy_document + .open(QueryDocParams { doc_id }, user_session.db_pool().unwrap()) + .await + .unwrap(); + + edit_context +} + +async fn init_user(user_session: Arc) { + let params = SignUpParams { + email: format!("{}@gmail.com", uuid()), + name: "nathan".to_string(), + password: "HelloWorld!@12".to_string(), + }; + + user_session.sign_up(params).await.unwrap(); + user_session.init_user().await.unwrap(); +} + +impl DocumentTest { + pub async fn new() -> Self { + let server = spawn_server().await; + let config = FlowySDKConfig::new(&root_dir(), &server.host, "http", "ws").log_filter("debug"); + let sdk = FlowySDK::new(config); + + let flowy_document = sdk.flowy_document.clone(); + let user_session = sdk.user_session.clone(); + + init_user(user_session.clone()).await; + + let edit_context = create_doc(user_session.clone(), flowy_document.clone()).await; + + Self { + server, + sdk, + flowy_document, + user_session, + edit_context, + } + } + + pub async fn run_scripts(self, scripts: Vec) { + for script in scripts { + match script { + DocScript::SendText(s) => { + let delta = Delta::from_str(s).unwrap(); + let data = delta.to_json(); + let doc_delta = DocDelta { + doc_id: self.edit_context.doc_id.clone(), + data, + }; + + self.flowy_document.apply_doc_delta(doc_delta).await; + }, + DocScript::SendBinary(_bytes) => {}, + } + } + std::mem::forget(self); + } +} diff --git a/backend/tests/ws/mod.rs b/backend/tests/document/mod.rs similarity index 100% rename from backend/tests/ws/mod.rs rename to backend/tests/document/mod.rs diff --git a/backend/tests/document/ws.rs b/backend/tests/document/ws.rs new file mode 100644 index 0000000000..608b474233 --- /dev/null +++ b/backend/tests/document/ws.rs @@ -0,0 +1,12 @@ +use crate::document::helper::{DocScript, DocumentTest}; +use tokio::time::{interval, Duration}; + +#[actix_rt::test] +async fn ws_connect() { + let test = DocumentTest::new().await; + test.run_scripts(vec![DocScript::SendText("abc")]).await; + + let mut interval = interval(Duration::from_secs(10)); + interval.tick().await; + interval.tick().await; +} diff --git a/backend/tests/helper.rs b/backend/tests/helper.rs index a151e03e4d..88ab80eb80 100644 --- a/backend/tests/helper.rs +++ b/backend/tests/helper.rs @@ -12,7 +12,7 @@ use flowy_workspace::prelude::{server::*, *}; use sqlx::{Connection, Executor, PgConnection, PgPool}; use uuid::Uuid; -pub struct TestServer { +pub struct TestUserServer { pub host: String, pub port: u16, pub pg_pool: PgPool, @@ -20,9 +20,9 @@ pub struct TestServer { pub user_id: Option, } -impl TestServer { +impl TestUserServer { pub async fn new() -> Self { - let mut server = spawn_server().await; + let mut server: TestUserServer = spawn_server().await.into(); let response = server.register_user().await; server.user_token = Some(response.token); server.user_id = Some(response.user_id); @@ -36,28 +36,16 @@ impl TestServer { pub async fn sign_out(&self) { let url = format!("{}/api/auth", self.http_addr()); - let _ = user_sign_out_request(self.user_token(), &url) - .await - .unwrap(); + let _ = user_sign_out_request(self.user_token(), &url).await.unwrap(); } - pub fn user_token(&self) -> &str { - self.user_token - .as_ref() - .expect("must call register_user first ") - } + pub fn user_token(&self) -> &str { self.user_token.as_ref().expect("must call register_user first ") } - pub fn user_id(&self) -> &str { - self.user_id - .as_ref() - .expect("must call register_user first ") - } + pub fn user_id(&self) -> &str { self.user_id.as_ref().expect("must call register_user first ") } pub async fn get_user_profile(&self) -> UserProfile { let url = format!("{}/api/user", self.http_addr()); - let user_profile = get_user_profile_request(self.user_token(), &url) - .await - .unwrap(); + let user_profile = get_user_profile_request(self.user_token(), &url).await.unwrap(); user_profile } @@ -68,99 +56,73 @@ impl TestServer { pub async fn create_workspace(&self, params: CreateWorkspaceParams) -> Workspace { let url = format!("{}/api/workspace", self.http_addr()); - let workspace = create_workspace_request(self.user_token(), params, &url) - .await - .unwrap(); + let workspace = create_workspace_request(self.user_token(), params, &url).await.unwrap(); workspace } pub async fn read_workspaces(&self, params: QueryWorkspaceParams) -> RepeatedWorkspace { let url = format!("{}/api/workspace", self.http_addr()); - let workspaces = read_workspaces_request(self.user_token(), params, &url) - .await - .unwrap(); + let workspaces = read_workspaces_request(self.user_token(), params, &url).await.unwrap(); workspaces } pub async fn update_workspace(&self, params: UpdateWorkspaceParams) { let url = format!("{}/api/workspace", self.http_addr()); - update_workspace_request(self.user_token(), params, &url) - .await - .unwrap(); + update_workspace_request(self.user_token(), params, &url).await.unwrap(); } pub async fn delete_workspace(&self, params: DeleteWorkspaceParams) { let url = format!("{}/api/workspace", self.http_addr()); - delete_workspace_request(self.user_token(), params, &url) - .await - .unwrap(); + delete_workspace_request(self.user_token(), params, &url).await.unwrap(); } pub async fn create_app(&self, params: CreateAppParams) -> App { let url = format!("{}/api/app", self.http_addr()); - let app = create_app_request(self.user_token(), params, &url) - .await - .unwrap(); + let app = create_app_request(self.user_token(), params, &url).await.unwrap(); app } pub async fn read_app(&self, params: QueryAppParams) -> Option { let url = format!("{}/api/app", self.http_addr()); - let app = read_app_request(self.user_token(), params, &url) - .await - .unwrap(); + let app = read_app_request(self.user_token(), params, &url).await.unwrap(); app } pub async fn update_app(&self, params: UpdateAppParams) { let url = format!("{}/api/app", self.http_addr()); - update_app_request(self.user_token(), params, &url) - .await - .unwrap(); + update_app_request(self.user_token(), params, &url).await.unwrap(); } pub async fn delete_app(&self, params: DeleteAppParams) { let url = format!("{}/api/app", self.http_addr()); - delete_app_request(self.user_token(), params, &url) - .await - .unwrap(); + delete_app_request(self.user_token(), params, &url).await.unwrap(); } pub async fn create_view(&self, params: CreateViewParams) -> View { let url = format!("{}/api/view", self.http_addr()); - let view = create_view_request(self.user_token(), params, &url) - .await - .unwrap(); + let view = create_view_request(self.user_token(), params, &url).await.unwrap(); view } pub async fn read_view(&self, params: QueryViewParams) -> Option { let url = format!("{}/api/view", self.http_addr()); - let view = read_view_request(self.user_token(), params, &url) - .await - .unwrap(); + let view = read_view_request(self.user_token(), params, &url).await.unwrap(); view } pub async fn update_view(&self, params: UpdateViewParams) { let url = format!("{}/api/view", self.http_addr()); - update_view_request(self.user_token(), params, &url) - .await - .unwrap(); + update_view_request(self.user_token(), params, &url).await.unwrap(); } pub async fn delete_view(&self, params: DeleteViewParams) { let url = format!("{}/api/view", self.http_addr()); - delete_view_request(self.user_token(), params, &url) - .await - .unwrap(); + delete_view_request(self.user_token(), params, &url).await.unwrap(); } pub async fn read_doc(&self, params: QueryDocParams) -> Option { let url = format!("{}/api/doc", self.http_addr()); - let doc = read_doc_request(self.user_token(), params, &url) - .await - .unwrap(); + let doc = read_doc_request(self.user_token(), params, &url).await.unwrap(); doc } @@ -182,14 +144,32 @@ impl TestServer { pub fn http_addr(&self) -> String { format!("http://{}", self.host) } - pub fn ws_addr(&self) -> String { - format!( - "ws://{}/ws/{}", - self.host, - self.user_token.as_ref().unwrap() - ) + pub fn ws_addr(&self) -> String { format!("ws://{}/ws/{}", self.host, self.user_token.as_ref().unwrap()) } +} + +impl std::convert::From for TestUserServer { + fn from(server: TestServer) -> Self { + TestUserServer { + host: server.host, + port: server.port, + pg_pool: server.pg_pool, + user_token: None, + user_id: None, + } } } + +pub async fn spawn_user_server() -> TestUserServer { + let server: TestUserServer = spawn_server().await.into(); + server +} + +pub struct TestServer { + pub host: String, + pub port: u16, + pub pg_pool: PgPool, +} + pub async fn spawn_server() -> TestServer { let database_name = format!("{}", Uuid::new_v4().to_string()); let configuration = { @@ -217,8 +197,6 @@ pub async fn spawn_server() -> TestServer { pg_pool: get_connection_pool(&configuration.database) .await .expect("Failed to connect to the database"), - user_token: None, - user_id: None, } } @@ -265,7 +243,7 @@ async fn drop_test_database(database_name: String) { .expect("Failed to drop database."); } -pub async fn create_test_workspace(server: &TestServer) -> Workspace { +pub async fn create_test_workspace(server: &TestUserServer) -> Workspace { let params = CreateWorkspaceParams { name: "My first workspace".to_string(), desc: "This is my first workspace".to_string(), @@ -275,7 +253,7 @@ pub async fn create_test_workspace(server: &TestServer) -> Workspace { workspace } -pub async fn create_test_app(server: &TestServer, workspace_id: &str) -> App { +pub async fn create_test_app(server: &TestUserServer, workspace_id: &str) -> App { let params = CreateAppParams { workspace_id: workspace_id.to_owned(), name: "My first app".to_string(), @@ -287,7 +265,7 @@ pub async fn create_test_app(server: &TestServer, workspace_id: &str) -> App { app } -pub async fn create_test_view(application: &TestServer, app_id: &str) -> View { +pub async fn create_test_view(application: &TestUserServer, app_id: &str) -> View { let name = "My first view".to_string(); let desc = "This is my first view".to_string(); let thumbnail = "http://1.png".to_string(); @@ -298,43 +276,37 @@ pub async fn create_test_view(application: &TestServer, app_id: &str) -> View { } pub struct WorkspaceTest { - pub server: TestServer, + pub server: TestUserServer, pub workspace: Workspace, } impl WorkspaceTest { pub async fn new() -> Self { - let server = TestServer::new().await; + let server = TestUserServer::new().await; let workspace = create_test_workspace(&server).await; Self { server, workspace } } - pub async fn create_app(&self) -> App { - create_test_app(&self.server, &self.workspace.id).await - } + pub async fn create_app(&self) -> App { create_test_app(&self.server, &self.workspace.id).await } } pub struct AppTest { - pub server: TestServer, + pub server: TestUserServer, pub workspace: Workspace, pub app: App, } impl AppTest { pub async fn new() -> Self { - let server = TestServer::new().await; + let server = TestUserServer::new().await; let workspace = create_test_workspace(&server).await; let app = create_test_app(&server, &workspace.id).await; - Self { - server, - workspace, - app, - } + Self { server, workspace, app } } } pub struct ViewTest { - pub server: TestServer, + pub server: TestUserServer, pub workspace: Workspace, pub app: App, pub view: View, @@ -342,7 +314,7 @@ pub struct ViewTest { impl ViewTest { pub async fn new() -> Self { - let server = TestServer::new().await; + let server = TestUserServer::new().await; let workspace = create_test_workspace(&server).await; let app = create_test_app(&server, &workspace.id).await; let view = create_test_view(&server, &app.id).await; diff --git a/backend/tests/main.rs b/backend/tests/main.rs index b0bc0cbca8..98002f021d 100644 --- a/backend/tests/main.rs +++ b/backend/tests/main.rs @@ -1,3 +1,3 @@ mod api; +mod document; pub mod helper; -mod ws; diff --git a/backend/tests/ws/helper.rs b/backend/tests/ws/helper.rs deleted file mode 100644 index 19d286a061..0000000000 --- a/backend/tests/ws/helper.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::helper::TestServer; -use flowy_ws::{WsController, WsModule, WsSender, WsState}; -use parking_lot::RwLock; -use std::sync::Arc; - -pub struct WsTest { - server: TestServer, - ws_controller: Arc>, -} - -#[derive(Clone)] -pub enum WsScript { - SendText(&'static str), - SendBinary(Vec), - Disconnect(&'static str), -} - -impl WsTest { - pub async fn new(scripts: Vec) -> Self { - let server = TestServer::new().await; - let ws_controller = Arc::new(RwLock::new(WsController::new())); - ws_controller - .write() - .state_callback(move |state| match state { - WsState::Connected(sender) => { - WsScriptRunner { - scripts: scripts.clone(), - sender: sender.clone(), - source: WsModule::Doc, - } - .run(); - }, - _ => {}, - }) - .await; - - Self { - server, - ws_controller, - } - } - - pub async fn run_scripts(&mut self) { - let addr = self.server.ws_addr(); - self.ws_controller - .write() - .connect(addr) - .unwrap() - .await - .unwrap(); - } -} - -struct WsScriptRunner { - scripts: Vec, - sender: Arc, - source: WsModule, -} - -impl WsScriptRunner { - fn run(self) { - for script in self.scripts { - match script { - WsScript::SendText(text) => { - self.sender.send_text(&self.source, text).unwrap(); - }, - WsScript::SendBinary(bytes) => { - self.sender.send_binary(&self.source, bytes).unwrap(); - }, - WsScript::Disconnect(reason) => { - self.sender.send_disconnect(reason).unwrap(); - }, - } - } - } -} diff --git a/backend/tests/ws/ws.rs b/backend/tests/ws/ws.rs deleted file mode 100644 index aa71e1d126..0000000000 --- a/backend/tests/ws/ws.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::ws::helper::{WsScript, WsTest}; - -#[actix_rt::test] -async fn ws_connect() { - let mut ws = WsTest::new(vec![ - WsScript::SendText("abc"), - WsScript::SendText("abc"), - WsScript::SendText("abc"), - WsScript::Disconnect("close by user"), - ]) - .await; - ws.run_scripts().await -} diff --git a/flowy-test/temp/flowy/flowy.log.2021-09-27 b/flowy-test/temp/flowy/flowy.log.2021-09-27 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rust-lib/Cargo.toml b/rust-lib/Cargo.toml index be571a7f68..1318e86dd9 100644 --- a/rust-lib/Cargo.toml +++ b/rust-lib/Cargo.toml @@ -14,7 +14,6 @@ members = [ "flowy-workspace", "flowy-observable", "flowy-document", - "flowy-editor", "flowy-ot", "flowy-net", "flowy-ws", diff --git a/rust-lib/dart-ffi/src/lib.rs b/rust-lib/dart-ffi/src/lib.rs index 88f3909025..4a2124daa9 100644 --- a/rust-lib/dart-ffi/src/lib.rs +++ b/rust-lib/dart-ffi/src/lib.rs @@ -24,7 +24,10 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { let c_str: &CStr = unsafe { CStr::from_ptr(path) }; let path: &str = c_str.to_str().unwrap(); - let config = FlowySDKConfig::new(path).log_filter("debug"); + let host = "localhost"; + let http_schema = "http"; + let ws_schema = "ws"; + let config = FlowySDKConfig::new(path, host, http_schema, ws_schema).log_filter("debug"); *FLOWY_SDK.write() = Some(Arc::new(FlowySDK::new(config))); return 1; @@ -33,7 +36,12 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { #[no_mangle] 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, port); + log::trace!( + "[FFI]: {} Async Event: {:?} with {} port", + &request.id, + &request.event, + port + ); let _ = EventDispatch::async_send_with_callback(dispatch(), request, move |resp: EventResponse| { log::trace!("[FFI]: Post data to dart through {} port", port); diff --git a/rust-lib/flowy-document/src/module.rs b/rust-lib/flowy-document/src/module.rs index 560478739d..d0542e7e44 100644 --- a/rust-lib/flowy-document/src/module.rs +++ b/rust-lib/flowy-document/src/module.rs @@ -8,7 +8,11 @@ use flowy_database::ConnectionPool; use crate::{ entities::doc::{CreateDocParams, Doc, DocDelta, QueryDocParams}, errors::DocError, - services::{doc::doc_controller::DocController, server::construct_doc_server, ws::WsDocumentManager}, + services::{ + doc::{doc_controller::DocController, edit_doc_context::EditDocContext}, + server::construct_doc_server, + ws::WsDocumentManager, + }, }; pub trait DocumentUser: Send + Sync { @@ -38,9 +42,13 @@ impl FlowyDocument { Ok(()) } - pub async fn open(&self, params: QueryDocParams, pool: Arc) -> Result { - let open_doc = self.doc_ctrl.open(params, pool).await?; - Ok(open_doc.doc()) + pub async fn open( + &self, + params: QueryDocParams, + pool: Arc, + ) -> Result, DocError> { + let edit_context = self.doc_ctrl.open(params, pool).await?; + Ok(edit_context) } pub async fn apply_doc_delta(&self, params: DocDelta) -> Result { diff --git a/rust-lib/flowy-document/src/services/doc/doc_controller.rs b/rust-lib/flowy-document/src/services/doc/doc_controller.rs index ef18bd740d..9f8ae0fc02 100644 --- a/rust-lib/flowy-document/src/services/doc/doc_controller.rs +++ b/rust-lib/flowy-document/src/services/doc/doc_controller.rs @@ -2,18 +2,13 @@ use crate::{ entities::doc::{CreateDocParams, Doc, DocDelta, QueryDocParams}, errors::{internal_error, DocError}, module::DocumentUser, - services::{ - cache::DocCache, - doc::{edit_doc_context::EditDocContext, rev_manager::RevisionManager}, - server::Server, - ws::WsDocumentManager, - }, - sql_tables::doc::{DocTable, DocTableSql, OpTableSql}, + services::{cache::DocCache, doc::edit_doc_context::EditDocContext, server::Server, ws::WsDocumentManager}, + sql_tables::doc::{DocTable, DocTableSql}, }; use bytes::Bytes; use flowy_database::{ConnectionPool, SqliteConnection}; use flowy_infra::future::{wrap_future, FnFuture}; -use flowy_ot::core::Delta; + use parking_lot::RwLock; use std::sync::Arc; use tokio::time::{interval, Duration}; diff --git a/rust-lib/flowy-document/src/services/doc/edit_doc_context.rs b/rust-lib/flowy-document/src/services/doc/edit_doc_context.rs index 5014bac8cd..465935512d 100644 --- a/rust-lib/flowy-document/src/services/doc/edit_doc_context.rs +++ b/rust-lib/flowy-document/src/services/doc/edit_doc_context.rs @@ -24,8 +24,8 @@ use std::{convert::TryFrom, sync::Arc}; pub type DocId = String; -pub(crate) struct EditDocContext { - pub(crate) doc_id: DocId, +pub struct EditDocContext { + pub doc_id: DocId, document: Arc>, rev_manager: Arc, pool: Arc, @@ -49,7 +49,7 @@ impl EditDocContext { Ok(edit_context) } - pub(crate) fn doc(&self) -> Doc { + pub fn doc(&self) -> Doc { Doc { id: self.doc_id.clone(), data: self.document.read().to_json(), diff --git a/rust-lib/flowy-document/src/services/doc/rev_manager.rs b/rust-lib/flowy-document/src/services/doc/rev_manager.rs index 6a762da9ce..1239fc2ea4 100644 --- a/rust-lib/flowy-document/src/services/doc/rev_manager.rs +++ b/rust-lib/flowy-document/src/services/doc/rev_manager.rs @@ -1,15 +1,12 @@ use crate::{ entities::doc::{RevType, Revision, RevisionRange}, errors::{internal_error, DocError}, - services::{ - util::RevIdCounter, - ws::{WsDocumentHandler, WsDocumentSender}, - }, - sql_tables::{OpTableSql, RevChangeset, RevState, RevTable}, + services::{util::RevIdCounter, ws::WsDocumentSender}, + sql_tables::{OpTableSql, RevChangeset, RevState}, }; -use dashmap::{DashMap, DashSet}; +use dashmap::DashSet; use flowy_database::ConnectionPool; -use parking_lot::{lock_api::RwLockWriteGuard, RawRwLock, RwLock}; +use parking_lot::RwLock; use std::{ collections::{HashMap, VecDeque}, sync::Arc, diff --git a/rust-lib/flowy-document/src/sql_tables/doc/doc_op_sql.rs b/rust-lib/flowy-document/src/sql_tables/doc/doc_op_sql.rs index e27671b6a9..519ac4dcc0 100644 --- a/rust-lib/flowy-document/src/sql_tables/doc/doc_op_sql.rs +++ b/rust-lib/flowy-document/src/sql_tables/doc/doc_op_sql.rs @@ -1,15 +1,12 @@ use crate::{ - entities::doc::{RevType, Revision}, + entities::doc::Revision, errors::DocError, sql_tables::{doc::RevTable, RevChangeset, RevState, RevTableType}, }; -use diesel::{insert_into, select, update}; +use diesel::{insert_into, update}; use flowy_database::{ prelude::*, - schema::{ - rev_table, - rev_table::{columns::*, dsl, dsl::doc_id}, - }, + schema::rev_table::{columns::*, dsl, dsl::doc_id}, SqliteConnection, }; diff --git a/rust-lib/flowy-editor/Cargo.toml b/rust-lib/flowy-editor/Cargo.toml deleted file mode 100644 index 8d3fb43dd9..0000000000 --- a/rust-lib/flowy-editor/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "flowy-editor" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/rust-lib/flowy-editor/src/lib.rs b/rust-lib/flowy-editor/src/lib.rs deleted file mode 100644 index 31e1bb209f..0000000000 --- a/rust-lib/flowy-editor/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/rust-lib/flowy-net/src/config.rs b/rust-lib/flowy-net/src/config.rs index ab1fe8ec70..0051fd144f 100644 --- a/rust-lib/flowy-net/src/config.rs +++ b/rust-lib/flowy-net/src/config.rs @@ -4,6 +4,43 @@ pub const HOST: &'static str = "localhost:8000"; pub const SCHEMA: &'static str = "http://"; pub const HEADER_TOKEN: &'static str = "token"; +#[derive(Debug, Clone)] +pub struct ServerConfig { + http_schema: String, + host: String, + ws_schema: String, +} + +impl ServerConfig { + pub fn new(host: &str, http_schema: &str, ws_schema: &str) -> Self { + Self { + http_schema: http_schema.to_owned(), + host: host.to_owned(), + ws_schema: ws_schema.to_owned(), + } + } + + fn scheme(&self) -> String { format!("{}://", self.http_schema) } + + pub fn sign_up_url(&self) -> String { format!("{}{}/api/register", self.scheme(), self.host) } + + pub fn sign_in_url(&self) -> String { format!("{}{}/api/auth", self.scheme(), self.host) } + + pub fn sign_out_url(&self) -> String { format!("{}{}/api/auth", self.scheme(), self.host) } + + pub fn user_profile_url(&self) -> String { format!("{}{}/api/user", self.scheme(), self.host) } + + pub fn workspace_url(&self) -> String { format!("{}{}/api/workspace", self.scheme(), self.host) } + + pub fn app_url(&self) -> String { format!("{}{}/api/app", self.scheme(), self.host) } + + pub fn view_url(&self) -> String { format!("{}{}/api/view", self.scheme(), self.host) } + + pub fn doc_url(&self) -> String { format!("{}{}/api/doc", self.scheme(), self.host) } + + pub fn ws_addr(&self) -> String { format!("{}://{}/ws", self.ws_schema, self.host) } +} + lazy_static! { pub static ref SIGN_UP_URL: String = format!("{}/{}/api/register", SCHEMA, HOST); pub static ref SIGN_IN_URL: String = format!("{}/{}/api/auth", SCHEMA, HOST); @@ -16,5 +53,6 @@ lazy_static! { pub static ref VIEW_URL: String = format!("{}/{}/api/view", SCHEMA, HOST); pub static ref DOC_URL: String = format!("{}/{}/api/doc", SCHEMA, HOST); + // pub static ref WS_ADDR: String = format!("ws://{}/ws", HOST); } diff --git a/rust-lib/flowy-sdk/Cargo.toml b/rust-lib/flowy-sdk/Cargo.toml index 152045fe83..ae30495463 100644 --- a/rust-lib/flowy-sdk/Cargo.toml +++ b/rust-lib/flowy-sdk/Cargo.toml @@ -14,6 +14,7 @@ flowy-workspace = { path = "../flowy-workspace" } flowy-database = { path = "../flowy-database" } flowy-document = { path = "../flowy-document" } flowy-ws = { path = "../flowy-ws" } +flowy-net = { path = "../flowy-net" } tracing = { version = "0.1" } log = "0.4.14" futures-core = { version = "0.3", default-features = false } diff --git a/rust-lib/flowy-sdk/src/lib.rs b/rust-lib/flowy-sdk/src/lib.rs index f2517eaf71..62a025585a 100644 --- a/rust-lib/flowy-sdk/src/lib.rs +++ b/rust-lib/flowy-sdk/src/lib.rs @@ -3,6 +3,9 @@ mod deps_resolve; pub mod module; use flowy_dispatch::prelude::*; +use flowy_document::prelude::FlowyDocument; +use flowy_net::config::ServerConfig; +use flowy_user::services::user::{UserSession, UserSessionBuilder}; use module::build_modules; pub use module::*; use std::sync::{ @@ -16,13 +19,16 @@ static INIT_LOG: AtomicBool = AtomicBool::new(false); pub struct FlowySDKConfig { root: String, log_filter: String, + server_config: ServerConfig, } impl FlowySDKConfig { - pub fn new(root: &str) -> Self { + pub fn new(root: &str, host: &str, http_schema: &str, ws_schema: &str) -> Self { + let server_config = ServerConfig::new(host, http_schema, ws_schema); FlowySDKConfig { root: root.to_owned(), log_filter: crate_log_filter(None), + server_config, } } @@ -49,7 +55,9 @@ fn crate_log_filter(level: Option) -> String { #[derive(Clone)] pub struct FlowySDK { config: FlowySDKConfig, - dispatch: Arc, + pub user_session: Arc, + pub flowy_document: Arc, + pub dispatch: Arc, } impl FlowySDK { @@ -58,9 +66,21 @@ impl FlowySDK { init_kv(&config.root); tracing::debug!("🔥 {:?}", config); - let dispatch = Arc::new(init_dispatch(&config.root)); + let user_session = Arc::new( + UserSessionBuilder::new() + .root_dir(&config.root, &config.server_config) + .build(), + ); + let flowy_document = build_document_module(user_session.clone()); + let modules = build_modules(&config.server_config, user_session.clone(), flowy_document.clone()); + let dispatch = Arc::new(EventDispatch::construct(|| modules)); - Self { config, dispatch } + Self { + config, + user_session, + flowy_document, + dispatch, + } } pub fn dispatch(&self) -> Arc { self.dispatch.clone() } @@ -83,9 +103,3 @@ fn init_log(config: &FlowySDKConfig) { .build(); } } - -fn init_dispatch(root: &str) -> EventDispatch { - let config = ModuleConfig { root: root.to_owned() }; - let dispatch = EventDispatch::construct(|| build_modules(config)); - dispatch -} diff --git a/rust-lib/flowy-sdk/src/module.rs b/rust-lib/flowy-sdk/src/module.rs index f9a19867a4..9a1b378b75 100644 --- a/rust-lib/flowy-sdk/src/module.rs +++ b/rust-lib/flowy-sdk/src/module.rs @@ -1,31 +1,34 @@ -use flowy_dispatch::prelude::Module; - use crate::deps_resolve::{DocumentDepsResolver, WorkspaceDepsResolver}; +use flowy_dispatch::prelude::Module; use flowy_document::module::FlowyDocument; -use flowy_user::services::user::{UserSession, UserSessionBuilder}; - +use flowy_net::config::ServerConfig; +use flowy_user::services::user::UserSession; use std::sync::Arc; -pub struct ModuleConfig { - pub root: String, -} - -pub fn build_modules(config: ModuleConfig) -> Vec { - let user_session = Arc::new(UserSessionBuilder::new().root_dir(&config.root).build()); - vec![build_user_module(user_session.clone()), build_workspace_module(user_session)] +pub fn build_modules( + server_config: &ServerConfig, + user_session: Arc, + flowy_document: Arc, +) -> Vec { + vec![ + build_user_module(user_session.clone()), + build_workspace_module(&server_config, user_session, flowy_document), + ] } fn build_user_module(user_session: Arc) -> Module { flowy_user::module::create(user_session.clone()) } -fn build_workspace_module(user_session: Arc) -> Module { +fn build_workspace_module( + server_config: &ServerConfig, + user_session: Arc, + flowy_document: Arc, +) -> Module { let workspace_deps = WorkspaceDepsResolver::new(user_session.clone()); let (user, database) = workspace_deps.split_into(); - let document = build_document_module(user_session.clone()); - - flowy_workspace::module::create(user, database, document) + flowy_workspace::module::create(user, database, flowy_document, server_config) } -fn build_document_module(user_session: Arc) -> Arc { +pub fn build_document_module(user_session: Arc) -> Arc { let document_deps = DocumentDepsResolver::new(user_session.clone()); let (user, ws_manager) = document_deps.split_into(); let document = Arc::new(FlowyDocument::new(user, ws_manager)); diff --git a/rust-lib/flowy-test/src/lib.rs b/rust-lib/flowy-test/src/lib.rs index 451059bfe7..1a2d7a2686 100644 --- a/rust-lib/flowy-test/src/lib.rs +++ b/rust-lib/flowy-test/src/lib.rs @@ -21,7 +21,12 @@ pub struct FlowyEnv { impl FlowyEnv { pub fn setup() -> Self { - let sdk = init_test_sdk(); + let host = "localhost"; + let http_schema = "http"; + let ws_schema = "ws"; + + let config = FlowySDKConfig::new(&root_dir(), host, http_schema, ws_schema).log_filter("debug"); + let sdk = FlowySDK::new(config); let result = sign_up(sdk.dispatch()); let env = Self { sdk, @@ -35,6 +40,10 @@ impl FlowyEnv { } pub fn init_test_sdk() -> FlowyTestSDK { - let config = FlowySDKConfig::new(&root_dir()).log_filter("debug"); + let host = "localhost"; + let http_schema = "http"; + let ws_schema = "ws"; + + let config = FlowySDKConfig::new(&root_dir(), host, http_schema, ws_schema).log_filter("debug"); FlowySDK::new(config) } diff --git a/rust-lib/flowy-user/src/errors.rs b/rust-lib/flowy-user/src/errors.rs index 2443eef466..9c442662e6 100644 --- a/rust-lib/flowy-user/src/errors.rs +++ b/rust-lib/flowy-user/src/errors.rs @@ -2,7 +2,6 @@ use bytes::Bytes; use derive_more::Display; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_dispatch::prelude::{EventResponse, ResponseBuilder}; - use std::{convert::TryInto, fmt::Debug}; #[derive(Debug, Default, Clone, ProtoBuf)] @@ -27,9 +26,19 @@ macro_rules! static_user_error { } impl UserError { - pub(crate) fn new(code: ErrorCode, msg: &str) -> Self { Self { code, msg: msg.to_owned() } } + pub(crate) fn new(code: ErrorCode, msg: &str) -> Self { + Self { + code, + msg: msg.to_owned(), + } + } - pub(crate) fn code(code: ErrorCode) -> Self { Self { code, msg: "".to_owned() } } + pub(crate) fn code(code: ErrorCode) -> Self { + Self { + code, + msg: "".to_owned(), + } + } pub fn context(mut self, error: T) -> Self { self.msg = format!("{:?}", error); diff --git a/rust-lib/flowy-user/src/services/server/mod.rs b/rust-lib/flowy-user/src/services/server/mod.rs index d35dd41a2a..b98127c96b 100644 --- a/rust-lib/flowy-user/src/services/server/mod.rs +++ b/rust-lib/flowy-user/src/services/server/mod.rs @@ -10,6 +10,7 @@ use crate::{ errors::UserError, }; use flowy_infra::future::ResultFuture; +use flowy_net::config::ServerConfig; pub trait UserServerAPI { fn sign_up(&self, params: SignUpParams) -> ResultFuture; @@ -17,12 +18,14 @@ pub trait UserServerAPI { fn sign_out(&self, token: &str) -> ResultFuture<(), UserError>; fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError>; fn get_user(&self, token: &str) -> ResultFuture; + fn ws_addr(&self) -> String; } -pub(crate) fn construct_user_server() -> Arc { +pub(crate) fn construct_user_server(config: &ServerConfig) -> Arc { if cfg!(feature = "http_server") { - Arc::new(UserServer {}) + Arc::new(UserServer::new(config.clone())) } else { - Arc::new(UserServerMock {}) + // Arc::new(UserServerMock {}) + Arc::new(UserServer::new(config.clone())) } } diff --git a/rust-lib/flowy-user/src/services/server/server_api.rs b/rust-lib/flowy-user/src/services/server/server_api.rs index 84776cc8a6..f9a6d0bc42 100644 --- a/rust-lib/flowy-user/src/services/server/server_api.rs +++ b/rust-lib/flowy-user/src/services/server/server_api.rs @@ -10,37 +10,46 @@ use flowy_net::{ request::{HttpRequestBuilder, ResponseMiddleware}, }; -pub struct UserServer {} +pub struct UserServer { + config: ServerConfig, +} impl UserServer { - pub fn new() -> Self { Self {} } + pub fn new(config: ServerConfig) -> Self { Self { config } } } impl UserServerAPI for UserServer { fn sign_up(&self, params: SignUpParams) -> ResultFuture { - ResultFuture::new(async move { user_sign_up_request(params, SIGN_UP_URL.as_ref()).await }) + let url = self.config.sign_up_url(); + ResultFuture::new(async move { user_sign_up_request(params, &url).await }) } fn sign_in(&self, params: SignInParams) -> ResultFuture { - ResultFuture::new(async move { user_sign_in_request(params, SIGN_IN_URL.as_ref()).await }) + let url = self.config.sign_in_url(); + ResultFuture::new(async move { user_sign_in_request(params, &url).await }) } fn sign_out(&self, token: &str) -> ResultFuture<(), UserError> { let token = token.to_owned(); + let url = self.config.sign_out_url(); ResultFuture::new(async move { - let _ = user_sign_out_request(&token, SIGN_OUT_URL.as_ref()).await; + let _ = user_sign_out_request(&token, &url).await; Ok(()) }) } fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError> { let token = token.to_owned(); - ResultFuture::new(async move { update_user_profile_request(&token, params, USER_PROFILE_URL.as_ref()).await }) + let url = self.config.user_profile_url(); + ResultFuture::new(async move { update_user_profile_request(&token, params, &url).await }) } fn get_user(&self, token: &str) -> ResultFuture { let token = token.to_owned(); - ResultFuture::new(async move { get_user_profile_request(&token, USER_PROFILE_URL.as_ref()).await }) + let url = self.config.user_profile_url(); + ResultFuture::new(async move { get_user_profile_request(&token, &url).await }) } + + fn ws_addr(&self) -> String { self.config.ws_addr() } } use crate::{errors::ErrorCode, observable::*}; @@ -72,17 +81,29 @@ impl ResponseMiddleware for Middleware { pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(MIDDLEWARE.clone()) } pub async fn user_sign_up_request(params: SignUpParams, url: &str) -> Result { - let response = request_builder().post(&url.to_owned()).protobuf(params)?.response().await?; + let response = request_builder() + .post(&url.to_owned()) + .protobuf(params)? + .response() + .await?; Ok(response) } pub async fn user_sign_in_request(params: SignInParams, url: &str) -> Result { - let response = request_builder().post(&url.to_owned()).protobuf(params)?.response().await?; + let response = request_builder() + .post(&url.to_owned()) + .protobuf(params)? + .response() + .await?; Ok(response) } pub async fn user_sign_out_request(token: &str, url: &str) -> Result<(), UserError> { - let _ = request_builder().delete(&url.to_owned()).header(HEADER_TOKEN, token).send().await?; + let _ = request_builder() + .delete(&url.to_owned()) + .header(HEADER_TOKEN, token) + .send() + .await?; Ok(()) } diff --git a/rust-lib/flowy-user/src/services/server/server_api_mock.rs b/rust-lib/flowy-user/src/services/server/server_api_mock.rs index c8dd3d4350..ce500cc33b 100644 --- a/rust-lib/flowy-user/src/services/server/server_api_mock.rs +++ b/rust-lib/flowy-user/src/services/server/server_api_mock.rs @@ -37,9 +37,13 @@ impl UserServerAPI for UserServerMock { fn sign_out(&self, _token: &str) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) } - fn update_user(&self, _token: &str, _params: UpdateUserParams) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) } + fn update_user(&self, _token: &str, _params: UpdateUserParams) -> ResultFuture<(), UserError> { + ResultFuture::new(async { Ok(()) }) + } fn get_user(&self, _token: &str) -> ResultFuture { ResultFuture::new(async { Err(UserError::internal().context("mock data, ignore this error")) }) } + + fn ws_addr(&self) -> String { "ws://localhost:8000/ws/".to_owned() } } diff --git a/rust-lib/flowy-user/src/services/user/builder.rs b/rust-lib/flowy-user/src/services/user/builder.rs index 3a28f68a68..b3b964ae29 100644 --- a/rust-lib/flowy-user/src/services/user/builder.rs +++ b/rust-lib/flowy-user/src/services/user/builder.rs @@ -1,4 +1,5 @@ use crate::services::user::{SessionStatusCallback, UserSession, UserSessionConfig}; +use flowy_net::config::ServerConfig; use std::sync::Arc; pub struct UserSessionBuilder { @@ -14,8 +15,8 @@ impl UserSessionBuilder { } } - pub fn root_dir(mut self, dir: &str) -> Self { - self.config = Some(UserSessionConfig::new(dir)); + pub fn root_dir(mut self, dir: &str, server_config: &ServerConfig) -> Self { + self.config = Some(UserSessionConfig::new(dir, server_config)); self } diff --git a/rust-lib/flowy-user/src/services/user/user_session.rs b/rust-lib/flowy-user/src/services/user/user_session.rs index b66dadb6d7..d1a252b6c8 100644 --- a/rust-lib/flowy-user/src/services/user/user_session.rs +++ b/rust-lib/flowy-user/src/services/user/user_session.rs @@ -17,6 +17,7 @@ use flowy_database::{ UserDatabaseConnection, }; use flowy_infra::kv::KV; +use flowy_net::config::ServerConfig; use flowy_sqlite::ConnectionPool; use flowy_ws::{connect::Retry, WsController, WsMessage, WsMessageHandler, WsSender}; use parking_lot::RwLock; @@ -25,12 +26,14 @@ use std::{sync::Arc, time::Duration}; pub struct UserSessionConfig { root_dir: String, + server_config: ServerConfig, } impl UserSessionConfig { - pub fn new(root_dir: &str) -> Self { + pub fn new(root_dir: &str, server_config: &ServerConfig) -> Self { Self { root_dir: root_dir.to_owned(), + server_config: server_config.clone(), } } } @@ -54,7 +57,7 @@ pub struct UserSession { impl UserSession { pub fn new(config: UserSessionConfig, status_callback: SessionStatusCallback) -> Self { let db = UserDB::new(&config.root_dir); - let server = construct_user_server(); + let server = construct_user_server(&config.server_config); let ws_controller = Arc::new(RwLock::new(WsController::new())); let user_session = Self { database: db, @@ -120,7 +123,8 @@ impl UserSession { #[tracing::instrument(level = "debug", skip(self))] pub async fn sign_out(&self) -> Result<(), UserError> { let session = self.get_session()?; - let _ = diesel::delete(dsl::user_table.filter(dsl::id.eq(&session.user_id))).execute(&*(self.db_connection()?))?; + let _ = + 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)?; (self.status_callback)(SessionStatus::Expired { @@ -178,7 +182,9 @@ impl UserSession { pub fn token(&self) -> Result { Ok(self.get_session()?.token) } - pub fn add_ws_handler(&self, handler: Arc) { let _ = self.ws_controller.write().add_handler(handler); } + pub fn add_ws_handler(&self, handler: Arc) { + let _ = self.ws_controller.write().add_handler(handler); + } pub fn get_ws_sender(&self) -> Result, UserError> { match self.ws_controller.try_read_for(Duration::from_millis(300)) { @@ -204,7 +210,9 @@ impl UserSession { tokio::spawn(async move { match server.get_user(&token).await { Ok(profile) => { - notify(&token, UserObservable::UserProfileUpdated).payload(profile).send(); + notify(&token, UserObservable::UserProfileUpdated) + .payload(profile) + .send(); }, Err(e) => { notify(&token, UserObservable::UserProfileUpdated).error(e).send(); @@ -245,7 +253,9 @@ impl UserSession { async fn save_user(&self, user: UserTable) -> Result { let conn = self.db_connection()?; - let _ = diesel::insert_into(user_table::table).values(user.clone()).execute(&*conn)?; + let _ = diesel::insert_into(user_table::table) + .values(user.clone()) + .execute(&*conn)?; Ok(user) } @@ -285,7 +295,7 @@ impl UserSession { } fn start_ws_connection(&self, token: &str) -> Result<(), UserError> { - let addr = format!("{}/{}", flowy_net::config::WS_ADDR.as_str(), token); + let addr = format!("{}/{}", self.server.ws_addr(), token); let ws_controller = self.ws_controller.clone(); let retry = Retry::new(&addr, move |addr| { let _ = ws_controller.write().connect(addr.to_owned()); @@ -296,7 +306,11 @@ impl UserSession { } } -pub async fn update_user(_server: Server, pool: Arc, params: UpdateUserParams) -> Result<(), UserError> { +pub async fn update_user( + _server: Server, + pool: Arc, + params: UpdateUserParams, +) -> Result<(), UserError> { let changeset = UserTableChangeset::new(params); let conn = pool.get()?; diesel_update_table!(user_table, changeset, &*conn); diff --git a/rust-lib/flowy-workspace/src/entities/view/view_create.rs b/rust-lib/flowy-workspace/src/entities/view/view_create.rs index f9b0d5590b..7da5de27c4 100644 --- a/rust-lib/flowy-workspace/src/entities/view/view_create.rs +++ b/rust-lib/flowy-workspace/src/entities/view/view_create.rs @@ -68,9 +68,9 @@ pub struct CreateViewParams { pub data: String, } -pub const VIEW_DEFAULT_DATA: &str = "[{\"insert\":\"\\n\"}]"; +pub const DOC_DEFAULT_DATA: &str = "[{\"insert\":\"\\n\"}]"; #[allow(dead_code)] -pub fn default_delta() -> Vec { VIEW_DEFAULT_DATA.as_bytes().to_vec() } +pub fn default_delta() -> Vec { DOC_DEFAULT_DATA.as_bytes().to_vec() } impl CreateViewParams { pub fn new(belong_to_id: String, name: String, desc: String, view_type: ViewType, thumbnail: String) -> Self { @@ -80,7 +80,7 @@ impl CreateViewParams { desc, thumbnail, view_type, - data: VIEW_DEFAULT_DATA.to_string(), + data: DOC_DEFAULT_DATA.to_string(), } } } diff --git a/rust-lib/flowy-workspace/src/module.rs b/rust-lib/flowy-workspace/src/module.rs index c967da336e..45f878ee47 100644 --- a/rust-lib/flowy-workspace/src/module.rs +++ b/rust-lib/flowy-workspace/src/module.rs @@ -8,6 +8,7 @@ use crate::{ use flowy_database::DBConnection; use flowy_dispatch::prelude::*; use flowy_document::module::FlowyDocument; +use flowy_net::config::ServerConfig; use flowy_sqlite::ConnectionPool; use std::sync::Arc; @@ -28,9 +29,19 @@ pub trait WorkspaceDatabase: Send + Sync { } } -pub fn create(user: Arc, database: Arc, document: Arc) -> Module { - let server = construct_workspace_server(); - let view_controller = Arc::new(ViewController::new(user.clone(), database.clone(), server.clone(), document)); +pub fn create( + user: Arc, + database: Arc, + flowy_document: Arc, + server_config: &ServerConfig, +) -> Module { + let server = construct_workspace_server(server_config); + let view_controller = Arc::new(ViewController::new( + user.clone(), + database.clone(), + server.clone(), + flowy_document, + )); let app_controller = Arc::new(AppController::new(user.clone(), database.clone(), server.clone())); let workspace_controller = Arc::new(WorkspaceController::new( diff --git a/rust-lib/flowy-workspace/src/services/server/mod.rs b/rust-lib/flowy-workspace/src/services/server/mod.rs index 2a4aaefe6f..7c25d90199 100644 --- a/rust-lib/flowy-workspace/src/services/server/mod.rs +++ b/rust-lib/flowy-workspace/src/services/server/mod.rs @@ -22,6 +22,7 @@ use crate::{ errors::WorkspaceError, }; use flowy_infra::future::ResultFuture; +use flowy_net::config::ServerConfig; use std::sync::Arc; pub(crate) type Server = Arc; @@ -30,7 +31,11 @@ pub trait WorkspaceServerAPI { // Workspace fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture; - fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture; + fn read_workspace( + &self, + token: &str, + params: QueryWorkspaceParams, + ) -> ResultFuture; fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError>; @@ -55,9 +60,9 @@ pub trait WorkspaceServerAPI { fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError>; } -pub(crate) fn construct_workspace_server() -> Arc { +pub(crate) fn construct_workspace_server(config: &ServerConfig) -> Arc { if cfg!(feature = "http_server") { - Arc::new(WorkspaceServer {}) + Arc::new(WorkspaceServer::new(config.clone())) } else { Arc::new(WorkspaceServerMock {}) } diff --git a/rust-lib/flowy-workspace/src/services/server/server_api.rs b/rust-lib/flowy-workspace/src/services/server/server_api.rs index f902b4d2ad..68e01b80f8 100644 --- a/rust-lib/flowy-workspace/src/services/server/server_api.rs +++ b/rust-lib/flowy-workspace/src/services/server/server_api.rs @@ -17,72 +17,100 @@ use crate::{ use flowy_infra::future::ResultFuture; use flowy_net::{config::*, request::HttpRequestBuilder}; -pub struct WorkspaceServer {} +pub struct WorkspaceServer { + config: ServerConfig, +} + +impl WorkspaceServer { + pub fn new(config: ServerConfig) -> WorkspaceServer { Self { config } } +} impl WorkspaceServerAPI for WorkspaceServer { fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture { let token = token.to_owned(); - ResultFuture::new(async move { create_workspace_request(&token, params, WORKSPACE_URL.as_ref()).await }) + let url = self.config.workspace_url(); + ResultFuture::new(async move { create_workspace_request(&token, params, &url).await }) } - fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture { + fn read_workspace( + &self, + token: &str, + params: QueryWorkspaceParams, + ) -> ResultFuture { let token = token.to_owned(); - ResultFuture::new(async move { read_workspaces_request(&token, params, WORKSPACE_URL.as_ref()).await }) + let url = self.config.workspace_url(); + ResultFuture::new(async move { read_workspaces_request(&token, params, &url).await }) } fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { update_workspace_request(&token, params, WORKSPACE_URL.as_ref()).await }) + let url = self.config.workspace_url(); + ResultFuture::new(async move { update_workspace_request(&token, params, &url).await }) } fn delete_workspace(&self, token: &str, params: DeleteWorkspaceParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { delete_workspace_request(&token, params, WORKSPACE_URL.as_ref()).await }) + let url = self.config.workspace_url(); + ResultFuture::new(async move { delete_workspace_request(&token, params, &url).await }) } fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture { let token = token.to_owned(); - ResultFuture::new(async move { create_view_request(&token, params, VIEW_URL.as_ref()).await }) + let url = self.config.view_url(); + ResultFuture::new(async move { create_view_request(&token, params, &url).await }) } fn read_view(&self, token: &str, params: QueryViewParams) -> ResultFuture, WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { read_view_request(&token, params, VIEW_URL.as_ref()).await }) + let url = self.config.view_url(); + ResultFuture::new(async move { read_view_request(&token, params, &url).await }) } fn delete_view(&self, token: &str, params: DeleteViewParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { delete_view_request(&token, params, VIEW_URL.as_ref()).await }) + let url = self.config.view_url(); + ResultFuture::new(async move { delete_view_request(&token, params, &url).await }) } fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { update_view_request(&token, params, VIEW_URL.as_ref()).await }) + let url = self.config.view_url(); + ResultFuture::new(async move { update_view_request(&token, params, &url).await }) } fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture { let token = token.to_owned(); - ResultFuture::new(async move { create_app_request(&token, params, APP_URL.as_ref()).await }) + let url = self.config.app_url(); + ResultFuture::new(async move { create_app_request(&token, params, &url).await }) } fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture, WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { read_app_request(&token, params, APP_URL.as_ref()).await }) + let url = self.config.app_url(); + ResultFuture::new(async move { read_app_request(&token, params, &url).await }) } fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { update_app_request(&token, params, APP_URL.as_ref()).await }) + let url = self.config.app_url(); + ResultFuture::new(async move { update_app_request(&token, params, &url).await }) } fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError> { let token = token.to_owned(); - ResultFuture::new(async move { delete_app_request(&token, params, APP_URL.as_ref()).await }) + let url = self.config.app_url(); + ResultFuture::new(async move { delete_app_request(&token, params, &url).await }) } } -pub(crate) fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(super::middleware::MIDDLEWARE.clone()) } -pub async fn create_workspace_request(token: &str, params: CreateWorkspaceParams, url: &str) -> Result { +pub(crate) fn request_builder() -> HttpRequestBuilder { + HttpRequestBuilder::new().middleware(super::middleware::MIDDLEWARE.clone()) +} +pub async fn create_workspace_request( + token: &str, + params: CreateWorkspaceParams, + url: &str, +) -> Result { let workspace = request_builder() .post(&url.to_owned()) .header(HEADER_TOKEN, token) @@ -92,7 +120,11 @@ pub async fn create_workspace_request(token: &str, params: CreateWorkspaceParams Ok(workspace) } -pub async fn read_workspaces_request(token: &str, params: QueryWorkspaceParams, url: &str) -> Result { +pub async fn read_workspaces_request( + token: &str, + params: QueryWorkspaceParams, + url: &str, +) -> Result { let repeated_workspace = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) @@ -103,7 +135,11 @@ pub async fn read_workspaces_request(token: &str, params: QueryWorkspaceParams, Ok(repeated_workspace) } -pub async fn update_workspace_request(token: &str, params: UpdateWorkspaceParams, url: &str) -> Result<(), WorkspaceError> { +pub async fn update_workspace_request( + token: &str, + params: UpdateWorkspaceParams, + url: &str, +) -> Result<(), WorkspaceError> { let _ = request_builder() .patch(&url.to_owned()) .header(HEADER_TOKEN, token) @@ -113,7 +149,11 @@ pub async fn update_workspace_request(token: &str, params: UpdateWorkspaceParams Ok(()) } -pub async fn delete_workspace_request(token: &str, params: DeleteWorkspaceParams, url: &str) -> Result<(), WorkspaceError> { +pub async fn delete_workspace_request( + token: &str, + params: DeleteWorkspaceParams, + url: &str, +) -> Result<(), WorkspaceError> { let _ = request_builder() .delete(url) .header(HEADER_TOKEN, token) @@ -176,7 +216,11 @@ pub async fn create_view_request(token: &str, params: CreateViewParams, url: &st Ok(view) } -pub async fn read_view_request(token: &str, params: QueryViewParams, url: &str) -> Result, WorkspaceError> { +pub async fn read_view_request( + token: &str, + params: QueryViewParams, + url: &str, +) -> Result, WorkspaceError> { let view = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) diff --git a/rust-lib/flowy-workspace/src/services/view_controller.rs b/rust-lib/flowy-workspace/src/services/view_controller.rs index 7279105b1e..9b840033bf 100644 --- a/rust-lib/flowy-workspace/src/services/view_controller.rs +++ b/rust-lib/flowy-workspace/src/services/view_controller.rs @@ -50,7 +50,8 @@ impl ViewController { // TODO: rollback anything created before if failed? conn.immediate_transaction::<_, WorkspaceError, _>(|| { let _ = self.save_view(view.clone(), conn)?; - self.document.create(CreateDocParams::new(&view.id, params.data), conn)?; + self.document + .create(CreateDocParams::new(&view.id, params.data), conn)?; let repeated_view = self.read_local_views_belong_to(&view.belong_to_id, conn)?; notify(&view.belong_to_id, WorkspaceObservable::AppCreateView) @@ -78,8 +79,8 @@ impl ViewController { #[tracing::instrument(level = "debug", skip(self), err)] pub(crate) async fn open_view(&self, params: QueryDocParams) -> Result { - let doc = self.document.open(params, self.database.db_pool()?).await?; - Ok(doc) + let edit_context = self.document.open(params, self.database.db_pool()?).await?; + Ok(edit_context.doc()) } pub(crate) async fn delete_view(&self, params: DeleteViewParams) -> Result<(), WorkspaceError> { @@ -191,7 +192,11 @@ impl ViewController { } // belong_to_id will be the app_id or view_id. - fn read_local_views_belong_to(&self, belong_to_id: &str, conn: &SqliteConnection) -> Result { + fn read_local_views_belong_to( + &self, + belong_to_id: &str, + conn: &SqliteConnection, + ) -> Result { let views = self .sql .read_views_belong_to(belong_to_id, conn)? diff --git a/rust-lib/flowy-ws/src/ws.rs b/rust-lib/flowy-ws/src/ws.rs index 2b9441d97b..9a653a6730 100644 --- a/rust-lib/flowy-ws/src/ws.rs +++ b/rust-lib/flowy-ws/src/ws.rs @@ -103,7 +103,7 @@ impl WsController { pub fn get_sender(&self) -> Result, WsError> { match &self.sender { - None => Err(WsError::internal().context("WsSender is not initialized")), + None => Err(WsError::internal().context("WsSender is not initialized, should call connect first")), Some(sender) => Ok(sender.clone()), } } @@ -112,7 +112,10 @@ impl WsController { log::debug!("🐴 ws connect: {}", &addr); let (connection, handlers) = self.make_connect(addr.clone()); let state_notify = self.state_notify.clone(); - let sender = self.sender.clone().expect("Sender should be not empty after calling make_connect"); + let sender = self + .sender + .clone() + .expect("Sender should be not empty after calling make_connect"); Ok(tokio::spawn(async move { match connection.await { Ok(stream) => { @@ -158,7 +161,10 @@ impl WsController { let handlers = self.handlers.clone(); self.sender = Some(Arc::new(WsSender { ws_tx })); self.addr = Some(addr.clone()); - (WsConnectionFuture::new(msg_tx, ws_rx, addr), WsHandlerFuture::new(handlers, msg_rx)) + ( + WsConnectionFuture::new(msg_tx, ws_rx, addr), + WsHandlerFuture::new(handlers, msg_rx), + ) } } @@ -170,7 +176,9 @@ pub struct WsHandlerFuture { } impl WsHandlerFuture { - fn new(handlers: HashMap>, msg_rx: MsgReceiver) -> Self { Self { msg_rx, handlers } } + fn new(handlers: HashMap>, msg_rx: MsgReceiver) -> Self { + Self { msg_rx, handlers } + } fn handler_ws_message(&self, message: Message) { match message { @@ -215,7 +223,10 @@ pub struct WsSender { impl WsSender { pub fn send_msg>(&self, msg: T) -> Result<(), WsError> { let msg = msg.into(); - let _ = self.ws_tx.unbounded_send(msg.into()).map_err(|e| WsError::internal().context(e))?; + let _ = self + .ws_tx + .unbounded_send(msg.into()) + .map_err(|e| WsError::internal().context(e))?; Ok(()) } @@ -241,7 +252,10 @@ impl WsSender { reason: reason.to_owned().into(), }; let msg = Message::Close(Some(frame)); - let _ = self.ws_tx.unbounded_send(msg).map_err(|e| WsError::internal().context(e))?; + let _ = self + .ws_tx + .unbounded_send(msg) + .map_err(|e| WsError::internal().context(e))?; Ok(()) } }