mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add server with flowy_document test
This commit is contained in:
parent
11bc536df8
commit
01c9620e03
@ -96,3 +96,7 @@ 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" }
|
||||
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" }
|
@ -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},
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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<V
|
||||
desc: "View created by AppFlowy".to_string(),
|
||||
thumbnail: "123.png".to_string(),
|
||||
view_type: ViewType::Doc,
|
||||
data: VIEW_DEFAULT_DATA.to_string(),
|
||||
data: DOC_DEFAULT_DATA.to_string(),
|
||||
unknown_fields: Default::default(),
|
||||
cached_size: Default::default(),
|
||||
};
|
||||
|
@ -19,6 +19,7 @@ pub async fn establish_ws_connection(
|
||||
server: Data<Addr<WsServer>>,
|
||||
biz_handlers: Data<WsBizHandlers>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
log::debug!("establish_ws_connection");
|
||||
match LoggedUser::from_token(token.clone()) {
|
||||
Ok(user) => {
|
||||
let ws_user = WsUser::new(user.clone());
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
service::{
|
||||
user::LoggedUser,
|
||||
ws::{
|
||||
entities::{Connect, Disconnect, SessionId, Socket},
|
||||
entities::{Connect, Disconnect, Socket},
|
||||
WsBizHandler,
|
||||
WsBizHandlers,
|
||||
WsMessageAdaptor,
|
||||
|
@ -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(),
|
||||
|
@ -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 {
|
||||
|
97
backend/tests/document/helper.rs
Normal file
97
backend/tests/document/helper.rs
Normal file
@ -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<FlowyDocument>,
|
||||
user_session: Arc<UserSession>,
|
||||
edit_context: Arc<EditDocContext>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum DocScript {
|
||||
SendText(&'static str),
|
||||
SendBinary(Vec<u8>),
|
||||
}
|
||||
|
||||
async fn create_doc(user_session: Arc<UserSession>, flowy_document: Arc<FlowyDocument>) -> Arc<EditDocContext> {
|
||||
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<UserSession>) {
|
||||
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<DocScript>) {
|
||||
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);
|
||||
}
|
||||
}
|
12
backend/tests/document/ws.rs
Normal file
12
backend/tests/document/ws.rs
Normal file
@ -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;
|
||||
}
|
@ -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<String>,
|
||||
}
|
||||
|
||||
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<App> {
|
||||
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<View> {
|
||||
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<Doc> {
|
||||
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<TestServer> 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;
|
||||
|
@ -1,3 +1,3 @@
|
||||
mod api;
|
||||
mod document;
|
||||
pub mod helper;
|
||||
mod ws;
|
||||
|
@ -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<RwLock<WsController>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum WsScript {
|
||||
SendText(&'static str),
|
||||
SendBinary(Vec<u8>),
|
||||
Disconnect(&'static str),
|
||||
}
|
||||
|
||||
impl WsTest {
|
||||
pub async fn new(scripts: Vec<WsScript>) -> 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<WsScript>,
|
||||
sender: Arc<WsSender>,
|
||||
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();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
0
flowy-test/temp/flowy/flowy.log.2021-09-27
Normal file
0
flowy-test/temp/flowy/flowy.log.2021-09-27
Normal file
@ -14,7 +14,6 @@ members = [
|
||||
"flowy-workspace",
|
||||
"flowy-observable",
|
||||
"flowy-document",
|
||||
"flowy-editor",
|
||||
"flowy-ot",
|
||||
"flowy-net",
|
||||
"flowy-ws",
|
||||
|
@ -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);
|
||||
|
@ -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<ConnectionPool>) -> Result<Doc, DocError> {
|
||||
let open_doc = self.doc_ctrl.open(params, pool).await?;
|
||||
Ok(open_doc.doc())
|
||||
pub async fn open(
|
||||
&self,
|
||||
params: QueryDocParams,
|
||||
pool: Arc<ConnectionPool>,
|
||||
) -> Result<Arc<EditDocContext>, DocError> {
|
||||
let edit_context = self.doc_ctrl.open(params, pool).await?;
|
||||
Ok(edit_context)
|
||||
}
|
||||
|
||||
pub async fn apply_doc_delta(&self, params: DocDelta) -> Result<Doc, DocError> {
|
||||
|
@ -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};
|
||||
|
@ -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<RwLock<Document>>,
|
||||
rev_manager: Arc<RevisionManager>,
|
||||
pool: Arc<ConnectionPool>,
|
||||
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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]
|
@ -1,7 +0,0 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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>) -> String {
|
||||
#[derive(Clone)]
|
||||
pub struct FlowySDK {
|
||||
config: FlowySDKConfig,
|
||||
dispatch: Arc<EventDispatch>,
|
||||
pub user_session: Arc<UserSession>,
|
||||
pub flowy_document: Arc<FlowyDocument>,
|
||||
pub dispatch: Arc<EventDispatch>,
|
||||
}
|
||||
|
||||
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<EventDispatch> { 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
|
||||
}
|
||||
|
@ -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<Module> {
|
||||
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<UserSession>,
|
||||
flowy_document: Arc<FlowyDocument>,
|
||||
) -> Vec<Module> {
|
||||
vec![
|
||||
build_user_module(user_session.clone()),
|
||||
build_workspace_module(&server_config, user_session, flowy_document),
|
||||
]
|
||||
}
|
||||
|
||||
fn build_user_module(user_session: Arc<UserSession>) -> Module { flowy_user::module::create(user_session.clone()) }
|
||||
|
||||
fn build_workspace_module(user_session: Arc<UserSession>) -> Module {
|
||||
fn build_workspace_module(
|
||||
server_config: &ServerConfig,
|
||||
user_session: Arc<UserSession>,
|
||||
flowy_document: Arc<FlowyDocument>,
|
||||
) -> 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<UserSession>) -> Arc<FlowyDocument> {
|
||||
pub fn build_document_module(user_session: Arc<UserSession>) -> Arc<FlowyDocument> {
|
||||
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));
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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<T: Debug>(mut self, error: T) -> Self {
|
||||
self.msg = format!("{:?}", error);
|
||||
|
@ -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<SignUpResponse, UserError>;
|
||||
@ -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<UserProfile, UserError>;
|
||||
fn ws_addr(&self) -> String;
|
||||
}
|
||||
|
||||
pub(crate) fn construct_user_server() -> Arc<dyn UserServerAPI + Send + Sync> {
|
||||
pub(crate) fn construct_user_server(config: &ServerConfig) -> Arc<dyn UserServerAPI + Send + Sync> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
@ -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<SignUpResponse, UserError> {
|
||||
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<SignInResponse, UserError> {
|
||||
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<UserProfile, UserError> {
|
||||
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<SignUpResponse, UserError> {
|
||||
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<SignInResponse, UserError> {
|
||||
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(())
|
||||
}
|
||||
|
||||
|
@ -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<UserProfile, UserError> {
|
||||
ResultFuture::new(async { Err(UserError::internal().context("mock data, ignore this error")) })
|
||||
}
|
||||
|
||||
fn ws_addr(&self) -> String { "ws://localhost:8000/ws/".to_owned() }
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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<String, UserError> { Ok(self.get_session()?.token) }
|
||||
|
||||
pub fn add_ws_handler(&self, handler: Arc<dyn WsMessageHandler>) { let _ = self.ws_controller.write().add_handler(handler); }
|
||||
pub fn add_ws_handler(&self, handler: Arc<dyn WsMessageHandler>) {
|
||||
let _ = self.ws_controller.write().add_handler(handler);
|
||||
}
|
||||
|
||||
pub fn get_ws_sender(&self) -> Result<Arc<WsSender>, 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<UserTable, UserError> {
|
||||
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<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> {
|
||||
pub async fn update_user(
|
||||
_server: Server,
|
||||
pool: Arc<ConnectionPool>,
|
||||
params: UpdateUserParams,
|
||||
) -> Result<(), UserError> {
|
||||
let changeset = UserTableChangeset::new(params);
|
||||
let conn = pool.get()?;
|
||||
diesel_update_table!(user_table, changeset, &*conn);
|
||||
|
@ -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<u8> { VIEW_DEFAULT_DATA.as_bytes().to_vec() }
|
||||
pub fn default_delta() -> Vec<u8> { 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyDocument>) -> 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<dyn WorkspaceUser>,
|
||||
database: Arc<dyn WorkspaceDatabase>,
|
||||
flowy_document: Arc<FlowyDocument>,
|
||||
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(
|
||||
|
@ -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<dyn WorkspaceServerAPI + Send + Sync>;
|
||||
@ -30,7 +31,11 @@ pub trait WorkspaceServerAPI {
|
||||
// Workspace
|
||||
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<Workspace, WorkspaceError>;
|
||||
|
||||
fn read_workspace(&self, token: &str, params: QueryWorkspaceParams) -> ResultFuture<RepeatedWorkspace, WorkspaceError>;
|
||||
fn read_workspace(
|
||||
&self,
|
||||
token: &str,
|
||||
params: QueryWorkspaceParams,
|
||||
) -> ResultFuture<RepeatedWorkspace, WorkspaceError>;
|
||||
|
||||
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<dyn WorkspaceServerAPI + Send + Sync> {
|
||||
pub(crate) fn construct_workspace_server(config: &ServerConfig) -> Arc<dyn WorkspaceServerAPI + Send + Sync> {
|
||||
if cfg!(feature = "http_server") {
|
||||
Arc::new(WorkspaceServer {})
|
||||
Arc::new(WorkspaceServer::new(config.clone()))
|
||||
} else {
|
||||
Arc::new(WorkspaceServerMock {})
|
||||
}
|
||||
|
@ -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<Workspace, WorkspaceError> {
|
||||
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<RepeatedWorkspace, WorkspaceError> {
|
||||
fn read_workspace(
|
||||
&self,
|
||||
token: &str,
|
||||
params: QueryWorkspaceParams,
|
||||
) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
|
||||
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<View, WorkspaceError> {
|
||||
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<Option<View>, 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<App, WorkspaceError> {
|
||||
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<Option<App>, 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<Workspace, WorkspaceError> {
|
||||
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<Workspace, WorkspaceError> {
|
||||
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<RepeatedWorkspace, WorkspaceError> {
|
||||
pub async fn read_workspaces_request(
|
||||
token: &str,
|
||||
params: QueryWorkspaceParams,
|
||||
url: &str,
|
||||
) -> Result<RepeatedWorkspace, WorkspaceError> {
|
||||
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<Option<View>, WorkspaceError> {
|
||||
pub async fn read_view_request(
|
||||
token: &str,
|
||||
params: QueryViewParams,
|
||||
url: &str,
|
||||
) -> Result<Option<View>, WorkspaceError> {
|
||||
let view = request_builder()
|
||||
.get(&url.to_owned())
|
||||
.header(HEADER_TOKEN, token)
|
||||
|
@ -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<Doc, WorkspaceError> {
|
||||
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<RepeatedView, WorkspaceError> {
|
||||
fn read_local_views_belong_to(
|
||||
&self,
|
||||
belong_to_id: &str,
|
||||
conn: &SqliteConnection,
|
||||
) -> Result<RepeatedView, WorkspaceError> {
|
||||
let views = self
|
||||
.sql
|
||||
.read_views_belong_to(belong_to_id, conn)?
|
||||
|
@ -103,7 +103,7 @@ impl WsController {
|
||||
|
||||
pub fn get_sender(&self) -> Result<Arc<WsSender>, 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<WsModule, Arc<dyn WsMessageHandler>>, msg_rx: MsgReceiver) -> Self { Self { msg_rx, handlers } }
|
||||
fn new(handlers: HashMap<WsModule, Arc<dyn WsMessageHandler>>, 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<T: Into<WsMessage>>(&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(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user