mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add mock server
This commit is contained in:
parent
df432d11c3
commit
31086ad4df
8
backend/Cargo.lock
generated
8
backend/Cargo.lock
generated
@ -467,6 +467,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"jsonwebtoken",
|
||||
"lazy_static",
|
||||
"lib-infra",
|
||||
"lib-ot",
|
||||
"lib-ws",
|
||||
"linkify",
|
||||
@ -505,6 +506,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"config",
|
||||
"derive_more",
|
||||
"flowy-collaboration",
|
||||
"flowy-core-infra",
|
||||
"flowy-user-infra",
|
||||
"hyper",
|
||||
@ -1205,6 +1207,7 @@ dependencies = [
|
||||
"dashmap",
|
||||
"flowy-derive",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"lib-ot",
|
||||
"log",
|
||||
"md5",
|
||||
@ -1339,6 +1342,7 @@ dependencies = [
|
||||
name = "flowy-net"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flowy-derive",
|
||||
"protobuf",
|
||||
]
|
||||
@ -1354,6 +1358,7 @@ dependencies = [
|
||||
"flowy-core",
|
||||
"flowy-database",
|
||||
"flowy-document",
|
||||
"flowy-net",
|
||||
"flowy-user",
|
||||
"futures-core",
|
||||
"lib-dispatch",
|
||||
@ -1402,7 +1407,6 @@ dependencies = [
|
||||
"derive_more",
|
||||
"diesel",
|
||||
"diesel_derives",
|
||||
"flowy-collaboration",
|
||||
"flowy-database",
|
||||
"flowy-derive",
|
||||
"flowy-net",
|
||||
@ -1954,11 +1958,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"flowy-derive",
|
||||
"futures-core",
|
||||
"log",
|
||||
"pin-project 1.0.8",
|
||||
"protobuf",
|
||||
"rand",
|
||||
"tokio",
|
||||
"uuid",
|
||||
|
@ -64,6 +64,7 @@ flowy-core-infra = { path = "../shared-lib/flowy-core-infra" }
|
||||
flowy-collaboration = { path = "../shared-lib/flowy-collaboration" }
|
||||
lib-ws = { path = "../shared-lib/lib-ws" }
|
||||
lib-ot = { path = "../shared-lib/lib-ot" }
|
||||
lib-infra = { path = "../shared-lib/lib-infra" }
|
||||
backend-service = { path = "../shared-lib/backend-service", features = ["http_server"] }
|
||||
|
||||
ormx = { version = "0.7", features = ["postgres"]}
|
||||
|
@ -1,16 +1,23 @@
|
||||
use crate::{
|
||||
services::doc::ws_actor::{DocWsActor, DocWsMsg},
|
||||
services::doc::{
|
||||
read_doc,
|
||||
update_doc,
|
||||
ws_actor::{DocWsActor, DocWsMsg},
|
||||
},
|
||||
web_socket::{WsBizHandler, WsClientData},
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
|
||||
use flowy_collaboration::{
|
||||
core::sync::{ServerDocManager, ServerDocPersistence},
|
||||
entities::doc::Doc,
|
||||
errors::CollaborateResult,
|
||||
errors::CollaborateError,
|
||||
protobuf::{DocIdentifier, UpdateDocParams},
|
||||
};
|
||||
use lib_infra::future::FutureResultSend;
|
||||
use lib_ot::rich_text::RichTextDelta;
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
pub struct DocumentCore {
|
||||
@ -21,7 +28,7 @@ pub struct DocumentCore {
|
||||
|
||||
impl DocumentCore {
|
||||
pub fn new(pg_pool: Data<PgPool>) -> Self {
|
||||
let manager = Arc::new(ServerDocManager::new(Arc::new(DocPersistenceImpl())));
|
||||
let manager = Arc::new(ServerDocManager::new(Arc::new(DocPersistenceImpl(pg_pool.clone()))));
|
||||
let (ws_sender, rx) = mpsc::channel(100);
|
||||
let actor = DocWsActor::new(rx, manager.clone());
|
||||
tokio::task::spawn(actor.run());
|
||||
@ -57,11 +64,38 @@ impl WsBizHandler for DocumentCore {
|
||||
}
|
||||
}
|
||||
|
||||
struct DocPersistenceImpl();
|
||||
struct DocPersistenceImpl(Data<PgPool>);
|
||||
impl ServerDocPersistence for DocPersistenceImpl {
|
||||
fn create_doc(&self, doc_id: &str, delta: RichTextDelta) -> CollaborateResult<()> { unimplemented!() }
|
||||
fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
|
||||
let pg_pool = self.0.clone();
|
||||
let mut params = UpdateDocParams::new();
|
||||
let doc_json = delta.to_json();
|
||||
params.set_doc_id(doc_id.to_string());
|
||||
params.set_data(doc_json);
|
||||
params.set_rev_id(rev_id);
|
||||
|
||||
fn update_doc(&self, doc_id: &str, delta: RichTextDelta) -> CollaborateResult<()> { unimplemented!() }
|
||||
FutureResultSend::new(async move {
|
||||
let _ = update_doc(pg_pool.get_ref(), params)
|
||||
.await
|
||||
.map_err(|e| CollaborateError::internal().context(e))?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn read_doc(&self, doc_id: &str) -> CollaborateResult<Doc> { unimplemented!() }
|
||||
fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError> {
|
||||
let params = DocIdentifier {
|
||||
doc_id: doc_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
let pg_pool = self.0.clone();
|
||||
FutureResultSend::new(async move {
|
||||
let mut pb_doc = read_doc(pg_pool.get_ref(), params)
|
||||
.await
|
||||
.map_err(|e| CollaborateError::internal().context(e))?;
|
||||
let doc = (&mut pb_doc)
|
||||
.try_into()
|
||||
.map_err(|e| CollaborateError::internal().context(e))?;
|
||||
Ok(doc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
services::{
|
||||
doc::{editor::ServerDocUser, read_doc},
|
||||
doc::editor::ServerDocUser,
|
||||
util::{md5, parse_from_bytes},
|
||||
},
|
||||
web_socket::{entities::Socket, WsClientData, WsUser},
|
||||
@ -11,7 +11,7 @@ use async_stream::stream;
|
||||
use backend_service::errors::{internal_error, Result as DocResult, ServerError};
|
||||
use flowy_collaboration::{
|
||||
core::sync::{OpenDocHandle, ServerDocManager},
|
||||
protobuf::{DocIdentifier, NewDocUser, WsDataType, WsDocumentData},
|
||||
protobuf::{NewDocUser, WsDataType, WsDocumentData},
|
||||
};
|
||||
use futures::stream::StreamExt;
|
||||
use lib_ot::protobuf::Revision;
|
||||
@ -128,30 +128,13 @@ impl DocWsActor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_doc_handle(&self, doc_id: &str, pg_pool: Data<PgPool>) -> Option<Arc<OpenDocHandle>> {
|
||||
match self.doc_manager.get(doc_id) {
|
||||
Some(edit_doc) => Some(edit_doc),
|
||||
None => {
|
||||
let params = DocIdentifier {
|
||||
doc_id: doc_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let f = || async {
|
||||
let mut pb_doc = read_doc(pg_pool.get_ref(), params).await?;
|
||||
let doc = (&mut pb_doc).try_into().map_err(internal_error)?;
|
||||
self.doc_manager.cache(doc).await.map_err(internal_error)?;
|
||||
let handler = self.doc_manager.get(doc_id);
|
||||
Ok::<Option<Arc<OpenDocHandle>>, ServerError>(handler)
|
||||
};
|
||||
|
||||
match f().await {
|
||||
Ok(handler) => handler,
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
async fn get_doc_handle(&self, doc_id: &str, _pg_pool: Data<PgPool>) -> Option<Arc<OpenDocHandle>> {
|
||||
match self.doc_manager.get(doc_id).await {
|
||||
Ok(Some(edit_doc)) => Some(edit_doc),
|
||||
Ok(None) => None,
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
use crate::services::view::{create_view_with_args, sql_builder::NewViewSqlBuilder};
|
||||
use backend_service::errors::ServerError;
|
||||
use chrono::Utc;
|
||||
use flowy_collaboration::user_default::doc_initial_string;
|
||||
use flowy_collaboration::core::document::default::initial_string;
|
||||
use flowy_core_infra::protobuf::Workspace;
|
||||
use std::convert::TryInto;
|
||||
|
||||
@ -42,7 +42,7 @@ pub async fn create_default_workspace(
|
||||
|
||||
for view in views.take_items() {
|
||||
let (sql, args, view) = NewViewSqlBuilder::from_view(view)?.build()?;
|
||||
let _ = create_view_with_args(transaction, sql, args, view, doc_initial_string()).await?;
|
||||
let _ = create_view_with_args(transaction, sql, args, view, initial_string()).await?;
|
||||
}
|
||||
}
|
||||
Ok(workspace)
|
||||
|
@ -2,7 +2,6 @@
|
||||
members = [
|
||||
"lib-dispatch",
|
||||
"lib-log",
|
||||
"lib-infra",
|
||||
"flowy-net",
|
||||
"flowy-sdk",
|
||||
"dart-ffi",
|
||||
|
@ -12,14 +12,13 @@ flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
lib-ot = { path = "../../../shared-lib/lib-ot" }
|
||||
lib-sqlite = { path = "../../../shared-lib/lib-sqlite" }
|
||||
backend-service = { path = "../../../shared-lib/backend-service" }
|
||||
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
flowy-document = { path = "../flowy-document" }
|
||||
flowy-database = { path = "../flowy-database" }
|
||||
flowy-net = { path = "../flowy-net" }
|
||||
dart-notify = { path = "../dart-notify" }
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
|
||||
|
||||
parking_lot = "0.11"
|
||||
@ -41,7 +40,7 @@ derive_more = {version = "0.99", features = ["display"]}
|
||||
bincode = { version = "1.3"}
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
bytes = { version = "1.0" }
|
||||
crossbeam = "0.8.1"
|
||||
crossbeam = "0.8"
|
||||
crossbeam-utils = "0.8"
|
||||
chrono = "0.4"
|
||||
|
||||
|
@ -1,3 +1,13 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use chrono::Utc;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use flowy_collaboration::{core::document::default::initial_read_me, entities::doc::DocDelta};
|
||||
use flowy_core_infra::user_default;
|
||||
use flowy_net::entities::NetworkType;
|
||||
|
||||
use crate::{
|
||||
entities::workspace::RepeatedWorkspace,
|
||||
errors::{WorkspaceError, WorkspaceResult},
|
||||
@ -5,13 +15,7 @@ use crate::{
|
||||
notify::{send_dart_notification, WorkspaceNotification},
|
||||
services::{server::Server, AppController, TrashController, ViewController, WorkspaceController},
|
||||
};
|
||||
use chrono::Utc;
|
||||
use flowy_collaboration::{entities::doc::DocDelta, user_default::initial_read_me};
|
||||
use flowy_core_infra::user_default;
|
||||
use flowy_net::entities::NetworkType;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
lazy_static! {
|
||||
static ref INIT_WORKSPACE: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
errors::WorkspaceError,
|
||||
};
|
||||
use backend_service::configuration::ClientServerConfiguration;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) type Server = Arc<dyn WorkspaceServerAPI + Send + Sync>;
|
||||
@ -24,42 +24,42 @@ pub trait WorkspaceServerAPI {
|
||||
fn init(&self);
|
||||
|
||||
// Workspace
|
||||
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<Workspace, WorkspaceError>;
|
||||
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> FutureResult<Workspace, WorkspaceError>;
|
||||
|
||||
fn read_workspace(
|
||||
&self,
|
||||
token: &str,
|
||||
params: WorkspaceIdentifier,
|
||||
) -> ResultFuture<RepeatedWorkspace, WorkspaceError>;
|
||||
) -> FutureResult<RepeatedWorkspace, WorkspaceError>;
|
||||
|
||||
fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError>;
|
||||
fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
fn delete_workspace(&self, token: &str, params: WorkspaceIdentifier) -> ResultFuture<(), WorkspaceError>;
|
||||
fn delete_workspace(&self, token: &str, params: WorkspaceIdentifier) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
// View
|
||||
fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture<View, WorkspaceError>;
|
||||
fn create_view(&self, token: &str, params: CreateViewParams) -> FutureResult<View, WorkspaceError>;
|
||||
|
||||
fn read_view(&self, token: &str, params: ViewIdentifier) -> ResultFuture<Option<View>, WorkspaceError>;
|
||||
fn read_view(&self, token: &str, params: ViewIdentifier) -> FutureResult<Option<View>, WorkspaceError>;
|
||||
|
||||
fn delete_view(&self, token: &str, params: ViewIdentifiers) -> ResultFuture<(), WorkspaceError>;
|
||||
fn delete_view(&self, token: &str, params: ViewIdentifiers) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError>;
|
||||
fn update_view(&self, token: &str, params: UpdateViewParams) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
// App
|
||||
fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<App, WorkspaceError>;
|
||||
fn create_app(&self, token: &str, params: CreateAppParams) -> FutureResult<App, WorkspaceError>;
|
||||
|
||||
fn read_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError>;
|
||||
fn read_app(&self, token: &str, params: AppIdentifier) -> FutureResult<Option<App>, WorkspaceError>;
|
||||
|
||||
fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>;
|
||||
fn update_app(&self, token: &str, params: UpdateAppParams) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
fn delete_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<(), WorkspaceError>;
|
||||
fn delete_app(&self, token: &str, params: AppIdentifier) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
// Trash
|
||||
fn create_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError>;
|
||||
fn create_trash(&self, token: &str, params: TrashIdentifiers) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
fn delete_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError>;
|
||||
fn delete_trash(&self, token: &str, params: TrashIdentifiers) -> FutureResult<(), WorkspaceError>;
|
||||
|
||||
fn read_trash(&self, token: &str) -> ResultFuture<RepeatedTrash, WorkspaceError>;
|
||||
fn read_trash(&self, token: &str) -> FutureResult<RepeatedTrash, WorkspaceError>;
|
||||
}
|
||||
|
||||
pub(crate) fn construct_workspace_server(
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
};
|
||||
use backend_service::{configuration::ClientServerConfiguration, middleware::*, workspace_request::*};
|
||||
use flowy_core_infra::errors::ErrorCode;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub struct WorkspaceHttpServer {
|
||||
config: ClientServerConfiguration,
|
||||
@ -34,10 +34,10 @@ impl WorkspaceServerAPI for WorkspaceHttpServer {
|
||||
});
|
||||
}
|
||||
|
||||
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> ResultFuture<Workspace, WorkspaceError> {
|
||||
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> FutureResult<Workspace, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.workspace_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let workspace = create_workspace_request(&token, params, &url).await?;
|
||||
Ok(workspace)
|
||||
})
|
||||
@ -47,127 +47,127 @@ impl WorkspaceServerAPI for WorkspaceHttpServer {
|
||||
&self,
|
||||
token: &str,
|
||||
params: WorkspaceIdentifier,
|
||||
) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
|
||||
) -> FutureResult<RepeatedWorkspace, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.workspace_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let repeated_workspace = read_workspaces_request(&token, params, &url).await?;
|
||||
Ok(repeated_workspace)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError> {
|
||||
fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.workspace_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = update_workspace_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_workspace(&self, token: &str, params: WorkspaceIdentifier) -> ResultFuture<(), WorkspaceError> {
|
||||
fn delete_workspace(&self, token: &str, params: WorkspaceIdentifier) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.workspace_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = delete_workspace_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn create_view(&self, token: &str, params: CreateViewParams) -> ResultFuture<View, WorkspaceError> {
|
||||
fn create_view(&self, token: &str, params: CreateViewParams) -> FutureResult<View, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.view_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let view = create_view_request(&token, params, &url).await?;
|
||||
Ok(view)
|
||||
})
|
||||
}
|
||||
|
||||
fn read_view(&self, token: &str, params: ViewIdentifier) -> ResultFuture<Option<View>, WorkspaceError> {
|
||||
fn read_view(&self, token: &str, params: ViewIdentifier) -> FutureResult<Option<View>, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.view_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let view = read_view_request(&token, params, &url).await?;
|
||||
Ok(view)
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_view(&self, token: &str, params: ViewIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
fn delete_view(&self, token: &str, params: ViewIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.view_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = delete_view_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn update_view(&self, token: &str, params: UpdateViewParams) -> ResultFuture<(), WorkspaceError> {
|
||||
fn update_view(&self, token: &str, params: UpdateViewParams) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.view_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = update_view_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<App, WorkspaceError> {
|
||||
fn create_app(&self, token: &str, params: CreateAppParams) -> FutureResult<App, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.app_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let app = create_app_request(&token, params, &url).await?;
|
||||
Ok(app)
|
||||
})
|
||||
}
|
||||
|
||||
fn read_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError> {
|
||||
fn read_app(&self, token: &str, params: AppIdentifier) -> FutureResult<Option<App>, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.app_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let app = read_app_request(&token, params, &url).await?;
|
||||
Ok(app)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError> {
|
||||
fn update_app(&self, token: &str, params: UpdateAppParams) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.app_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = update_app_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<(), WorkspaceError> {
|
||||
fn delete_app(&self, token: &str, params: AppIdentifier) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.app_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = delete_app_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn create_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
fn create_trash(&self, token: &str, params: TrashIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.trash_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = create_trash_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
fn delete_trash(&self, token: &str, params: TrashIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.trash_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = delete_trash_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn read_trash(&self, token: &str) -> ResultFuture<RepeatedTrash, WorkspaceError> {
|
||||
fn read_trash(&self, token: &str) -> FutureResult<RepeatedTrash, WorkspaceError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.trash_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let repeated_trash = read_trash_request(&token, &url).await?;
|
||||
Ok(repeated_trash)
|
||||
})
|
||||
|
@ -8,14 +8,14 @@ use crate::{
|
||||
errors::WorkspaceError,
|
||||
services::server::WorkspaceServerAPI,
|
||||
};
|
||||
use lib_infra::{future::ResultFuture, timestamp, uuid};
|
||||
use lib_infra::{future::FutureResult, timestamp, uuid};
|
||||
|
||||
pub struct WorkspaceServerMock {}
|
||||
|
||||
impl WorkspaceServerAPI for WorkspaceServerMock {
|
||||
fn init(&self) {}
|
||||
|
||||
fn create_workspace(&self, _token: &str, params: CreateWorkspaceParams) -> ResultFuture<Workspace, WorkspaceError> {
|
||||
fn create_workspace(&self, _token: &str, params: CreateWorkspaceParams) -> FutureResult<Workspace, WorkspaceError> {
|
||||
let time = timestamp();
|
||||
let workspace = Workspace {
|
||||
id: uuid(),
|
||||
@ -26,29 +26,29 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
|
||||
create_time: time,
|
||||
};
|
||||
|
||||
ResultFuture::new(async { Ok(workspace) })
|
||||
FutureResult::new(async { Ok(workspace) })
|
||||
}
|
||||
|
||||
fn read_workspace(
|
||||
&self,
|
||||
_token: &str,
|
||||
_params: WorkspaceIdentifier,
|
||||
) -> ResultFuture<RepeatedWorkspace, WorkspaceError> {
|
||||
ResultFuture::new(async {
|
||||
) -> FutureResult<RepeatedWorkspace, WorkspaceError> {
|
||||
FutureResult::new(async {
|
||||
let repeated_workspace = RepeatedWorkspace { items: vec![] };
|
||||
Ok(repeated_workspace)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_workspace(&self, _token: &str, _params: UpdateWorkspaceParams) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn update_workspace(&self, _token: &str, _params: UpdateWorkspaceParams) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn delete_workspace(&self, _token: &str, _params: WorkspaceIdentifier) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn delete_workspace(&self, _token: &str, _params: WorkspaceIdentifier) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn create_view(&self, _token: &str, params: CreateViewParams) -> ResultFuture<View, WorkspaceError> {
|
||||
fn create_view(&self, _token: &str, params: CreateViewParams) -> FutureResult<View, WorkspaceError> {
|
||||
let time = timestamp();
|
||||
let view = View {
|
||||
id: uuid(),
|
||||
@ -61,22 +61,22 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
|
||||
modified_time: time,
|
||||
create_time: time,
|
||||
};
|
||||
ResultFuture::new(async { Ok(view) })
|
||||
FutureResult::new(async { Ok(view) })
|
||||
}
|
||||
|
||||
fn read_view(&self, _token: &str, _params: ViewIdentifier) -> ResultFuture<Option<View>, WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(None) })
|
||||
fn read_view(&self, _token: &str, _params: ViewIdentifier) -> FutureResult<Option<View>, WorkspaceError> {
|
||||
FutureResult::new(async { Ok(None) })
|
||||
}
|
||||
|
||||
fn delete_view(&self, _token: &str, _params: ViewIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn delete_view(&self, _token: &str, _params: ViewIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn update_view(&self, _token: &str, _params: UpdateViewParams) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn update_view(&self, _token: &str, _params: UpdateViewParams) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn create_app(&self, _token: &str, params: CreateAppParams) -> ResultFuture<App, WorkspaceError> {
|
||||
fn create_app(&self, _token: &str, params: CreateAppParams) -> FutureResult<App, WorkspaceError> {
|
||||
let time = timestamp();
|
||||
let app = App {
|
||||
id: uuid(),
|
||||
@ -88,31 +88,31 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
|
||||
modified_time: time,
|
||||
create_time: time,
|
||||
};
|
||||
ResultFuture::new(async { Ok(app) })
|
||||
FutureResult::new(async { Ok(app) })
|
||||
}
|
||||
|
||||
fn read_app(&self, _token: &str, _params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(None) })
|
||||
fn read_app(&self, _token: &str, _params: AppIdentifier) -> FutureResult<Option<App>, WorkspaceError> {
|
||||
FutureResult::new(async { Ok(None) })
|
||||
}
|
||||
|
||||
fn update_app(&self, _token: &str, _params: UpdateAppParams) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn update_app(&self, _token: &str, _params: UpdateAppParams) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn delete_app(&self, _token: &str, _params: AppIdentifier) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn delete_app(&self, _token: &str, _params: AppIdentifier) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn create_trash(&self, _token: &str, _params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn create_trash(&self, _token: &str, _params: TrashIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn delete_trash(&self, _token: &str, _params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn delete_trash(&self, _token: &str, _params: TrashIdentifiers) -> FutureResult<(), WorkspaceError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn read_trash(&self, _token: &str) -> ResultFuture<RepeatedTrash, WorkspaceError> {
|
||||
ResultFuture::new(async {
|
||||
fn read_trash(&self, _token: &str) -> FutureResult<RepeatedTrash, WorkspaceError> {
|
||||
FutureResult::new(async {
|
||||
let repeated_trash = RepeatedTrash { items: vec![] };
|
||||
Ok(repeated_trash)
|
||||
})
|
||||
|
@ -12,10 +12,10 @@ flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
lib-ot = { path = "../../../shared-lib/lib-ot" }
|
||||
lib-ws = { path = "../../../shared-lib/lib-ws" }
|
||||
backend-service = { path = "../../../shared-lib/backend-service" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
derive_more = {version = "0.99", features = ["display"]}
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
flowy-database = { path = "../flowy-database" }
|
||||
dart-notify = { path = "../dart-notify" }
|
||||
|
||||
@ -52,7 +52,7 @@ color-eyre = { version = "0.5", default-features = false }
|
||||
criterion = "0.3"
|
||||
rand = "0.7.3"
|
||||
env_logger = "0.8.2"
|
||||
|
||||
flowy-user = { path = "../flowy-user", features = ["ws_mock"] }
|
||||
|
||||
[features]
|
||||
http_server = []
|
||||
|
@ -14,7 +14,7 @@ use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use flowy_collaboration::entities::doc::{Doc, DocDelta, DocIdentifier};
|
||||
use flowy_database::ConnectionPool;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) struct DocController {
|
||||
@ -128,14 +128,14 @@ struct RevisionServerImpl {
|
||||
|
||||
impl RevisionServer for RevisionServerImpl {
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn fetch_document(&self, doc_id: &str) -> ResultFuture<Doc, DocError> {
|
||||
fn fetch_document(&self, doc_id: &str) -> FutureResult<Doc, DocError> {
|
||||
let params = DocIdentifier {
|
||||
doc_id: doc_id.to_string(),
|
||||
};
|
||||
let server = self.server.clone();
|
||||
let token = self.token.clone();
|
||||
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
match server.read_doc(&token, params).await? {
|
||||
None => Err(DocError::doc_not_found().context("Remote doesn't have this document")),
|
||||
Some(doc) => Ok(doc),
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use flowy_collaboration::entities::doc::Doc;
|
||||
use flowy_database::ConnectionPool;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ot::{
|
||||
core::{Operation, OperationTransformable},
|
||||
revision::{RevState, RevType, Revision, RevisionDiskCache, RevisionMemoryCache, RevisionRange, RevisionRecord},
|
||||
@ -18,7 +18,7 @@ use tokio::{
|
||||
};
|
||||
|
||||
pub trait RevisionIterator: Send + Sync {
|
||||
fn next(&self) -> ResultFuture<Option<RevisionRecord>, DocError>;
|
||||
fn next(&self) -> FutureResult<Option<RevisionRecord>, DocError>;
|
||||
}
|
||||
|
||||
type DocRevisionDeskCache = dyn RevisionDiskCache<Error = DocError>;
|
||||
@ -136,11 +136,11 @@ impl RevisionCache {
|
||||
}
|
||||
|
||||
impl RevisionIterator for RevisionCache {
|
||||
fn next(&self) -> ResultFuture<Option<RevisionRecord>, DocError> {
|
||||
fn next(&self) -> FutureResult<Option<RevisionRecord>, DocError> {
|
||||
let memory_cache = self.memory_cache.clone();
|
||||
let disk_cache = self.dish_cache.clone();
|
||||
let doc_id = self.doc_id.clone();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
match memory_cache.front_revision().await {
|
||||
None => {
|
||||
//
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use flowy_collaboration::{entities::doc::Doc, util::RevIdCounter};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ot::{
|
||||
core::OperationTransformable,
|
||||
revision::{RevId, RevType, Revision, RevisionRange},
|
||||
@ -15,7 +15,7 @@ use lib_ot::{
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait RevisionServer: Send + Sync {
|
||||
fn fetch_document(&self, doc_id: &str) -> ResultFuture<Doc, DocError>;
|
||||
fn fetch_document(&self, doc_id: &str) -> FutureResult<Doc, DocError>;
|
||||
}
|
||||
|
||||
pub struct RevisionManager {
|
||||
|
@ -7,17 +7,17 @@ pub use server_api::*;
|
||||
use crate::errors::DocError;
|
||||
use backend_service::configuration::ClientServerConfiguration;
|
||||
use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
pub use server_api_mock::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) type Server = Arc<dyn DocumentServerAPI + Send + Sync>;
|
||||
pub trait DocumentServerAPI {
|
||||
fn create_doc(&self, token: &str, params: CreateDocParams) -> ResultFuture<(), DocError>;
|
||||
fn create_doc(&self, token: &str, params: CreateDocParams) -> FutureResult<(), DocError>;
|
||||
|
||||
fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError>;
|
||||
fn read_doc(&self, token: &str, params: DocIdentifier) -> FutureResult<Option<Doc>, DocError>;
|
||||
|
||||
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError>;
|
||||
fn update_doc(&self, token: &str, params: UpdateDocParams) -> FutureResult<(), DocError>;
|
||||
}
|
||||
|
||||
pub(crate) fn construct_doc_server(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{errors::DocError, services::server::DocumentServerAPI};
|
||||
use backend_service::{configuration::*, request::HttpRequestBuilder};
|
||||
use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub struct DocServer {
|
||||
config: ClientServerConfiguration,
|
||||
@ -12,22 +12,22 @@ impl DocServer {
|
||||
}
|
||||
|
||||
impl DocumentServerAPI for DocServer {
|
||||
fn create_doc(&self, token: &str, params: CreateDocParams) -> ResultFuture<(), DocError> {
|
||||
fn create_doc(&self, token: &str, params: CreateDocParams) -> FutureResult<(), DocError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.doc_url();
|
||||
ResultFuture::new(async move { create_doc_request(&token, params, &url).await })
|
||||
FutureResult::new(async move { create_doc_request(&token, params, &url).await })
|
||||
}
|
||||
|
||||
fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError> {
|
||||
fn read_doc(&self, token: &str, params: DocIdentifier) -> FutureResult<Option<Doc>, DocError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.doc_url();
|
||||
ResultFuture::new(async move { read_doc_request(&token, params, &url).await })
|
||||
FutureResult::new(async move { read_doc_request(&token, params, &url).await })
|
||||
}
|
||||
|
||||
fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError> {
|
||||
fn update_doc(&self, token: &str, params: UpdateDocParams) -> FutureResult<(), DocError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.doc_url();
|
||||
ResultFuture::new(async move { update_doc_request(&token, params, &url).await })
|
||||
FutureResult::new(async move { update_doc_request(&token, params, &url).await })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,29 @@
|
||||
use crate::{errors::DocError, services::server::DocumentServerAPI};
|
||||
use flowy_collaboration::{
|
||||
core::document::default::initial_string,
|
||||
entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams},
|
||||
user_default::doc_initial_string,
|
||||
};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::{errors::DocError, services::server::DocumentServerAPI};
|
||||
|
||||
pub struct DocServerMock {}
|
||||
|
||||
impl DocumentServerAPI for DocServerMock {
|
||||
fn create_doc(&self, _token: &str, _params: CreateDocParams) -> ResultFuture<(), DocError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn create_doc(&self, _token: &str, _params: CreateDocParams) -> FutureResult<(), DocError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn read_doc(&self, _token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError> {
|
||||
fn read_doc(&self, _token: &str, params: DocIdentifier) -> FutureResult<Option<Doc>, DocError> {
|
||||
let doc = Doc {
|
||||
id: params.doc_id,
|
||||
data: doc_initial_string(),
|
||||
data: initial_string(),
|
||||
rev_id: 0,
|
||||
base_rev_id: 0,
|
||||
};
|
||||
ResultFuture::new(async { Ok(Some(doc)) })
|
||||
FutureResult::new(async { Ok(Some(doc)) })
|
||||
}
|
||||
|
||||
fn update_doc(&self, _token: &str, _params: UpdateDocParams) -> ResultFuture<(), DocError> {
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
fn update_doc(&self, _token: &str, _params: UpdateDocParams) -> FutureResult<(), DocError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
}
|
||||
|
@ -8,3 +8,4 @@ edition = "2018"
|
||||
[dependencies]
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
protobuf = {version = "2.18.0"}
|
||||
bytes = { version = "1.0" }
|
@ -9,10 +9,11 @@ edition = "2018"
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-log = { path = "../lib-log" }
|
||||
flowy-user = { path = "../flowy-user" }
|
||||
flowy-net = { path = "../flowy-net" }
|
||||
flowy-core = { path = "../flowy-core", default-features = false }
|
||||
flowy-database = { path = "../flowy-database" }
|
||||
flowy-document = { path = "../flowy-document" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
|
||||
tracing = { version = "0.1" }
|
||||
log = "0.4.14"
|
||||
futures-core = { version = "0.3", default-features = false }
|
||||
@ -25,7 +26,7 @@ parking_lot = "0.11"
|
||||
flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
|
||||
lib-ws = { path = "../../../shared-lib/lib-ws" }
|
||||
backend-service = { path = "../../../shared-lib/backend-service" }
|
||||
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
@ -5,12 +5,12 @@ use crate::deps_resolve::WorkspaceDepsResolver;
|
||||
use backend_service::configuration::ClientServerConfiguration;
|
||||
use flowy_core::{errors::WorkspaceError, module::init_core, prelude::CoreContext};
|
||||
use flowy_document::module::FlowyDocument;
|
||||
use flowy_net::entities::NetworkType;
|
||||
use flowy_user::{
|
||||
prelude::UserStatus,
|
||||
services::user::{UserSession, UserSessionConfig},
|
||||
};
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_infra::entities::network_state::NetworkType;
|
||||
use module::mk_modules;
|
||||
pub use module::*;
|
||||
use std::sync::{
|
||||
|
@ -11,11 +11,11 @@ flowy-user = { path = "../flowy-user"}
|
||||
flowy-core = { path = "../flowy-core", default-features = false}
|
||||
flowy-document = { path = "../flowy-document"}
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
|
||||
flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
|
||||
backend-service = { path = "../../../shared-lib/backend-service" }
|
||||
lib-ot = { path = "../../../shared-lib/lib-ot" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = {version = "1.0"}
|
||||
|
@ -8,17 +8,21 @@ edition = "2018"
|
||||
[dependencies]
|
||||
flowy-user-infra = { path = "../../../shared-lib/flowy-user-infra" }
|
||||
backend-service = { path = "../../../shared-lib/backend-service" }
|
||||
flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
lib-ws = { path = "../../../shared-lib/lib-ws" }
|
||||
lib-sqlite = { path = "../../../shared-lib/lib-sqlite" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
|
||||
flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration", optional = true}
|
||||
lib-ot = { path = "../../../shared-lib/lib-ot", optional = true }
|
||||
|
||||
derive_more = {version = "0.99", features = ["display"]}
|
||||
flowy-database = { path = "../flowy-database" }
|
||||
flowy-net = { path = "../flowy-net" }
|
||||
dart-notify = { path = "../dart-notify" }
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
|
||||
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
bytes = "1.0"
|
||||
@ -48,3 +52,4 @@ serial_test = "0.5.1"
|
||||
|
||||
[features]
|
||||
http_server = []
|
||||
ws_mock = ["flowy-collaboration", "lib-ot"]
|
@ -1,8 +1,6 @@
|
||||
mod server_api;
|
||||
mod server_api_mock;
|
||||
|
||||
// #[cfg(feature = "http_server")]
|
||||
pub(crate) mod ws_mock;
|
||||
mod ws_local;
|
||||
|
||||
pub use server_api::*;
|
||||
pub use server_api_mock::*;
|
||||
@ -15,14 +13,14 @@ use crate::{
|
||||
services::user::ws_manager::FlowyWebSocket,
|
||||
};
|
||||
use backend_service::configuration::ClientServerConfiguration;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub trait UserServerAPI {
|
||||
fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError>;
|
||||
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError>;
|
||||
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 sign_up(&self, params: SignUpParams) -> FutureResult<SignUpResponse, UserError>;
|
||||
fn sign_in(&self, params: SignInParams) -> FutureResult<SignInResponse, UserError>;
|
||||
fn sign_out(&self, token: &str) -> FutureResult<(), UserError>;
|
||||
fn update_user(&self, token: &str, params: UpdateUserParams) -> FutureResult<(), UserError>;
|
||||
fn get_user(&self, token: &str) -> FutureResult<UserProfile, UserError>;
|
||||
fn ws_addr(&self) -> String;
|
||||
}
|
||||
|
||||
@ -34,10 +32,11 @@ pub(crate) fn construct_user_server(config: &ClientServerConfiguration) -> Arc<d
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> {
|
||||
if cfg!(debug_assertions) {
|
||||
Arc::new(Arc::new(ws_mock::MockWebSocket::default()))
|
||||
} else {
|
||||
Arc::new(Arc::new(ws_mock::LocalWebSocket::default()))
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "ws_mock")]
|
||||
mod ws_mock;
|
||||
|
||||
#[cfg(not(feature = "ws_mock"))]
|
||||
pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> { Arc::new(Arc::new(ws_local::LocalWebSocket::default())) }
|
||||
|
||||
#[cfg(feature = "ws_mock")]
|
||||
pub(crate) fn local_web_socket() -> Arc<dyn FlowyWebSocket> { Arc::new(Arc::new(ws_mock::MockWebSocket::default())) }
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
services::server::UserServerAPI,
|
||||
};
|
||||
use backend_service::{configuration::*, user_request::*};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub struct UserHttpServer {
|
||||
config: ClientServerConfiguration,
|
||||
@ -14,44 +14,44 @@ impl UserHttpServer {
|
||||
}
|
||||
|
||||
impl UserServerAPI for UserHttpServer {
|
||||
fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
|
||||
fn sign_up(&self, params: SignUpParams) -> FutureResult<SignUpResponse, UserError> {
|
||||
let url = self.config.sign_up_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let resp = user_sign_up_request(params, &url).await?;
|
||||
Ok(resp)
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
||||
fn sign_in(&self, params: SignInParams) -> FutureResult<SignInResponse, UserError> {
|
||||
let url = self.config.sign_in_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let resp = user_sign_in_request(params, &url).await?;
|
||||
Ok(resp)
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_out(&self, token: &str) -> ResultFuture<(), UserError> {
|
||||
fn sign_out(&self, token: &str) -> FutureResult<(), UserError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.sign_out_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = user_sign_out_request(&token, &url).await;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn update_user(&self, token: &str, params: UpdateUserParams) -> ResultFuture<(), UserError> {
|
||||
fn update_user(&self, token: &str, params: UpdateUserParams) -> FutureResult<(), UserError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.user_profile_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = update_user_profile_request(&token, params, &url).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_user(&self, token: &str) -> ResultFuture<UserProfile, UserError> {
|
||||
fn get_user(&self, token: &str) -> FutureResult<UserProfile, UserError> {
|
||||
let token = token.to_owned();
|
||||
let url = self.config.user_profile_url();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let profile = get_user_profile_request(&token, &url).await?;
|
||||
Ok(profile)
|
||||
})
|
||||
|
@ -4,16 +4,16 @@ use crate::{
|
||||
};
|
||||
|
||||
use crate::services::server::UserServerAPI;
|
||||
use lib_infra::{future::ResultFuture, uuid};
|
||||
use lib_infra::{future::FutureResult, uuid};
|
||||
|
||||
pub struct UserServerMock {}
|
||||
|
||||
impl UserServerMock {}
|
||||
|
||||
impl UserServerAPI for UserServerMock {
|
||||
fn sign_up(&self, params: SignUpParams) -> ResultFuture<SignUpResponse, UserError> {
|
||||
fn sign_up(&self, params: SignUpParams) -> FutureResult<SignUpResponse, UserError> {
|
||||
let uid = uuid();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
Ok(SignUpResponse {
|
||||
user_id: uid.clone(),
|
||||
name: params.name,
|
||||
@ -23,9 +23,9 @@ impl UserServerAPI for UserServerMock {
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
||||
fn sign_in(&self, params: SignInParams) -> FutureResult<SignInResponse, UserError> {
|
||||
let user_id = uuid();
|
||||
ResultFuture::new(async {
|
||||
FutureResult::new(async {
|
||||
Ok(SignInResponse {
|
||||
user_id: user_id.clone(),
|
||||
name: params.name,
|
||||
@ -35,14 +35,14 @@ impl UserServerAPI for UserServerMock {
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_out(&self, _token: &str) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) }
|
||||
fn sign_out(&self, _token: &str) -> FutureResult<(), UserError> { FutureResult::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) -> FutureResult<(), UserError> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn get_user(&self, _token: &str) -> ResultFuture<UserProfile, UserError> {
|
||||
ResultFuture::new(async { Ok(UserProfile::default()) })
|
||||
fn get_user(&self, _token: &str) -> FutureResult<UserProfile, UserError> {
|
||||
FutureResult::new(async { Ok(UserProfile::default()) })
|
||||
}
|
||||
|
||||
fn ws_addr(&self) -> String { "ws://localhost:8000/ws/".to_owned() }
|
||||
|
43
frontend/rust-lib/flowy-user/src/services/server/ws_local.rs
Normal file
43
frontend/rust-lib/flowy-user/src/services/server/ws_local.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use crate::{
|
||||
errors::UserError,
|
||||
services::user::ws_manager::{FlowyWebSocket, FlowyWsSender},
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ws::{WsConnectState, WsMessage, WsMessageHandler};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{broadcast, broadcast::Receiver};
|
||||
|
||||
pub(crate) struct LocalWebSocket {
|
||||
state_sender: broadcast::Sender<WsConnectState>,
|
||||
ws_sender: broadcast::Sender<WsMessage>,
|
||||
}
|
||||
|
||||
impl std::default::Default for LocalWebSocket {
|
||||
fn default() -> Self {
|
||||
let (state_sender, _) = broadcast::channel(16);
|
||||
let (ws_sender, _) = broadcast::channel(16);
|
||||
LocalWebSocket {
|
||||
state_sender,
|
||||
ws_sender,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowyWebSocket for Arc<LocalWebSocket> {
|
||||
fn start_connect(&self, _addr: String) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
|
||||
|
||||
fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
|
||||
|
||||
fn reconnect(&self, _count: usize) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
|
||||
|
||||
fn add_handler(&self, _handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> { Ok(()) }
|
||||
|
||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> { Ok(Arc::new(self.ws_sender.clone())) }
|
||||
}
|
||||
|
||||
impl FlowyWsSender for broadcast::Sender<WsMessage> {
|
||||
fn send(&self, msg: WsMessage) -> Result<(), UserError> {
|
||||
let _ = self.send(msg);
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -4,9 +4,19 @@ use crate::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use flowy_collaboration::entities::ws::{WsDataType, WsDocumentData};
|
||||
use lib_infra::future::ResultFuture;
|
||||
use flowy_collaboration::{
|
||||
core::sync::{ServerDocManager, ServerDocPersistence},
|
||||
entities::{
|
||||
doc::{Doc, NewDocUser},
|
||||
ws::{WsDataType, WsDocumentData},
|
||||
},
|
||||
errors::CollaborateError,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use lib_infra::future::{FutureResult, FutureResultSend};
|
||||
use lib_ot::{revision::Revision, rich_text::RichTextDelta};
|
||||
use lib_ws::{WsConnectState, WsMessage, WsMessageHandler, WsModule};
|
||||
use parking_lot::RwLock;
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use tokio::sync::{broadcast, broadcast::Receiver};
|
||||
|
||||
@ -33,33 +43,28 @@ impl MockWebSocket {
|
||||
}
|
||||
|
||||
impl FlowyWebSocket for Arc<MockWebSocket> {
|
||||
fn start_connect(&self, _addr: String) -> ResultFuture<(), UserError> {
|
||||
fn start_connect(&self, _addr: String) -> FutureResult<(), UserError> {
|
||||
let mut ws_receiver = self.ws_sender.subscribe();
|
||||
let cloned_ws = self.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(message) = ws_receiver.recv().await {
|
||||
let ws_data = WsDocumentData::try_from(Bytes::from(message.data.clone())).unwrap();
|
||||
match ws_data.ty {
|
||||
WsDataType::Acked => {},
|
||||
WsDataType::PushRev => {},
|
||||
WsDataType::PullRev => {},
|
||||
WsDataType::Conflict => {},
|
||||
WsDataType::NewDocUser => {},
|
||||
}
|
||||
|
||||
match cloned_ws.handlers.get(&message.module) {
|
||||
None => log::error!("Can't find any handler for message: {:?}", message),
|
||||
Some(handler) => handler.receive_message(message.clone()),
|
||||
match DOC_SERVER.handle_ws_data(ws_data).await {
|
||||
None => {},
|
||||
Some(new_ws_message) => match cloned_ws.handlers.get(&new_ws_message.module) {
|
||||
None => log::error!("Can't find any handler for message: {:?}", new_ws_message),
|
||||
Some(handler) => handler.receive_message(new_ws_message.clone()),
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ResultFuture::new(async { Ok(()) })
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
|
||||
|
||||
fn reconnect(&self, _count: usize) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) }
|
||||
fn reconnect(&self, _count: usize) -> FutureResult<(), UserError> { FutureResult::new(async { Ok(()) }) }
|
||||
|
||||
fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> {
|
||||
let source = handler.source();
|
||||
@ -73,37 +78,48 @@ impl FlowyWebSocket for Arc<MockWebSocket> {
|
||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> { Ok(Arc::new(self.ws_sender.clone())) }
|
||||
}
|
||||
|
||||
impl FlowyWsSender for broadcast::Sender<WsMessage> {
|
||||
fn send(&self, msg: WsMessage) -> Result<(), UserError> {
|
||||
let _ = self.send(msg).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
lazy_static! {
|
||||
static ref DOC_SERVER: Arc<MockDocServer> = Arc::new(MockDocServer::default());
|
||||
}
|
||||
|
||||
pub(crate) struct LocalWebSocket {
|
||||
state_sender: broadcast::Sender<WsConnectState>,
|
||||
ws_sender: broadcast::Sender<WsMessage>,
|
||||
struct MockDocServer {
|
||||
pub manager: Arc<ServerDocManager>,
|
||||
}
|
||||
|
||||
impl std::default::Default for LocalWebSocket {
|
||||
impl std::default::Default for MockDocServer {
|
||||
fn default() -> Self {
|
||||
let (state_sender, _) = broadcast::channel(16);
|
||||
let (ws_sender, _) = broadcast::channel(16);
|
||||
LocalWebSocket {
|
||||
state_sender,
|
||||
ws_sender,
|
||||
}
|
||||
let manager = Arc::new(ServerDocManager::new(Arc::new(MockDocServerPersistence {})));
|
||||
MockDocServer { manager }
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowyWebSocket for Arc<LocalWebSocket> {
|
||||
fn start_connect(&self, _addr: String) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) }
|
||||
|
||||
fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
|
||||
|
||||
fn reconnect(&self, _count: usize) -> ResultFuture<(), UserError> { ResultFuture::new(async { Ok(()) }) }
|
||||
|
||||
fn add_handler(&self, _handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError> { Ok(()) }
|
||||
|
||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError> { Ok(Arc::new(self.ws_sender.clone())) }
|
||||
impl MockDocServer {
|
||||
async fn handle_ws_data(&self, ws_data: WsDocumentData) -> Option<WsMessage> {
|
||||
let bytes = Bytes::from(ws_data.data);
|
||||
match ws_data.ty {
|
||||
WsDataType::Acked => {},
|
||||
WsDataType::PushRev => {
|
||||
let revision = Revision::try_from(bytes).unwrap();
|
||||
log::info!("{:?}", revision);
|
||||
},
|
||||
WsDataType::PullRev => {},
|
||||
WsDataType::Conflict => {},
|
||||
WsDataType::NewDocUser => {
|
||||
let new_doc_user = NewDocUser::try_from(bytes).unwrap();
|
||||
log::info!("{:?}", new_doc_user);
|
||||
// NewDocUser
|
||||
},
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct MockDocServerPersistence {}
|
||||
|
||||
impl ServerDocPersistence for MockDocServerPersistence {
|
||||
fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError> { unimplemented!() }
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
use crate::errors::UserError;
|
||||
|
||||
use flowy_net::entities::NetworkType;
|
||||
use lib_infra::future::ResultFuture;
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ws::{WsConnectState, WsController, WsMessage, WsMessageHandler, WsSender};
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{broadcast, broadcast::Receiver};
|
||||
|
||||
pub trait FlowyWebSocket: Send + Sync {
|
||||
fn start_connect(&self, addr: String) -> ResultFuture<(), UserError>;
|
||||
fn start_connect(&self, addr: String) -> FutureResult<(), UserError>;
|
||||
fn conn_state_subscribe(&self) -> broadcast::Receiver<WsConnectState>;
|
||||
fn reconnect(&self, count: usize) -> ResultFuture<(), UserError>;
|
||||
fn reconnect(&self, count: usize) -> FutureResult<(), UserError>;
|
||||
fn add_handler(&self, handler: Arc<dyn WsMessageHandler>) -> Result<(), UserError>;
|
||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, UserError>;
|
||||
}
|
||||
@ -115,9 +115,9 @@ impl std::default::Default for WsManager {
|
||||
}
|
||||
|
||||
impl FlowyWebSocket for Arc<WsController> {
|
||||
fn start_connect(&self, addr: String) -> ResultFuture<(), UserError> {
|
||||
fn start_connect(&self, addr: String) -> FutureResult<(), UserError> {
|
||||
let cloned_ws = self.clone();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = cloned_ws.start(addr).await?;
|
||||
Ok(())
|
||||
})
|
||||
@ -125,9 +125,9 @@ impl FlowyWebSocket for Arc<WsController> {
|
||||
|
||||
fn conn_state_subscribe(&self) -> Receiver<WsConnectState> { self.state_subscribe() }
|
||||
|
||||
fn reconnect(&self, count: usize) -> ResultFuture<(), UserError> {
|
||||
fn reconnect(&self, count: usize) -> FutureResult<(), UserError> {
|
||||
let cloned_ws = self.clone();
|
||||
ResultFuture::new(async move {
|
||||
FutureResult::new(async move {
|
||||
let _ = cloned_ws.retry(count).await?;
|
||||
Ok(())
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ use tera::Tera;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub fn read_file(path: &str) -> Option<String> {
|
||||
let mut file = File::open(path).expect(&format!("Unable to open file at {}", path));
|
||||
let mut file = File::open(path).unwrap_or_else(|_| panic!("Unable to open file at {}", path));
|
||||
let mut content = String::new();
|
||||
match file.read_to_string(&mut content) {
|
||||
Ok(_) => Some(content),
|
||||
|
4
shared-lib/Cargo.lock
generated
4
shared-lib/Cargo.lock
generated
@ -279,6 +279,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"config",
|
||||
"derive_more",
|
||||
"flowy-collaboration",
|
||||
"flowy-core-infra",
|
||||
"flowy-user-infra",
|
||||
"hyper",
|
||||
@ -688,6 +689,7 @@ dependencies = [
|
||||
"dashmap",
|
||||
"flowy-derive",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"lib-ot",
|
||||
"log",
|
||||
"md5",
|
||||
@ -1132,11 +1134,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"flowy-derive",
|
||||
"futures-core",
|
||||
"log",
|
||||
"pin-project",
|
||||
"protobuf",
|
||||
"rand 0.8.4",
|
||||
"tokio",
|
||||
"uuid",
|
||||
|
@ -6,6 +6,7 @@ members = [
|
||||
"lib-ot",
|
||||
"lib-ws",
|
||||
"lib-sqlite",
|
||||
"lib-infra",
|
||||
"backend-service",
|
||||
"flowy-derive",
|
||||
"flowy-ast",
|
||||
|
@ -8,6 +8,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
flowy-core-infra = { path = "../flowy-core-infra" }
|
||||
flowy-user-infra = { path = "../flowy-user-infra" }
|
||||
flowy-collaboration = { path = "../flowy-collaboration" }
|
||||
|
||||
log = "0.4.14"
|
||||
lazy_static = "1.4.0"
|
||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
lib-ot = { path = "../lib-ot" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
flowy-derive = { path = "../flowy-derive" }
|
||||
protobuf = {version = "2.18.0"}
|
||||
bytes = "1.0"
|
||||
|
@ -0,0 +1 @@
|
||||
[{"insert":"\n👋 Welcome to AppFlowy!"},{"insert":"\n","attributes":{"header":1}},{"insert":"\nHere are the basics"},{"insert":"\n","attributes":{"header":2}},{"insert":"Click anywhere and just start typing"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Highlight","attributes":{"background":"#fff2cd"}},{"insert":" any text, and use the menu at the bottom to "},{"insert":"style","attributes":{"italic":true}},{"insert":" "},{"insert":"your","attributes":{"bold":true}},{"insert":" "},{"insert":"writing","attributes":{"underline":true}},{"insert":" "},{"insert":"however","attributes":{"code":true}},{"insert":" "},{"insert":"you","attributes":{"strike":true}},{"insert":" "},{"insert":"like","attributes":{"background":"#e8e0ff"}},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click "},{"insert":"+ New Page","attributes":{"background":"#defff1","bold":true}},{"insert":" button at the bottom of your sidebar to add a new page"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click the "},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":"+'","attributes":{"background":"#defff1","bold":true}},{"insert":" next to any page title in the sidebar to quickly add a new subpage"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\nHave a question? "},{"insert":"\n","attributes":{"header":2}},{"insert":"Click the "},{"insert":"'?'","attributes":{"background":"#defff1","bold":true}},{"insert":" at the bottom right for help and support.\n\nLike AppFlowy? Follow us:"},{"insert":"\n","attributes":{"header":2}},{"insert":"GitHub: https://github.com/AppFlowy-IO/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Twitter: https://twitter.com/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Newsletter: https://www.appflowy.io/blog"},{"insert":"\n","attributes":{"blockquote":true}}]
|
@ -1,20 +1,20 @@
|
||||
use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta};
|
||||
|
||||
#[inline]
|
||||
pub fn doc_initial_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() }
|
||||
pub fn initial_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() }
|
||||
|
||||
#[inline]
|
||||
pub fn doc_initial_string() -> String { doc_initial_delta().to_json() }
|
||||
pub fn initial_string() -> String { initial_delta().to_json() }
|
||||
|
||||
#[inline]
|
||||
pub fn initial_read_me() -> RichTextDelta {
|
||||
let json = include_str!("READ_ME.json");
|
||||
let json = include_str!("./READ_ME.json");
|
||||
RichTextDelta::from_json(json).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::user_default::initial_read_me;
|
||||
use crate::core::document::default::initial_read_me;
|
||||
|
||||
#[test]
|
||||
fn load_read_me() {
|
@ -1,16 +1,18 @@
|
||||
use crate::{
|
||||
core::document::{
|
||||
history::{History, UndoResult},
|
||||
view::{View, RECORD_THRESHOLD},
|
||||
},
|
||||
errors::CollaborateError,
|
||||
user_default::doc_initial_delta,
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use lib_ot::{
|
||||
core::*,
|
||||
rich_text::{RichTextAttribute, RichTextDelta},
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{
|
||||
core::document::{
|
||||
default::initial_delta,
|
||||
history::{History, UndoResult},
|
||||
view::{View, RECORD_THRESHOLD},
|
||||
},
|
||||
errors::CollaborateError,
|
||||
};
|
||||
|
||||
pub trait CustomDocument {
|
||||
fn init_delta() -> RichTextDelta;
|
||||
@ -23,7 +25,7 @@ impl CustomDocument for PlainDoc {
|
||||
|
||||
pub struct FlowyDoc();
|
||||
impl CustomDocument for FlowyDoc {
|
||||
fn init_delta() -> RichTextDelta { doc_initial_delta() }
|
||||
fn init_delta() -> RichTextDelta { initial_delta() }
|
||||
}
|
||||
|
||||
pub struct Document {
|
||||
|
@ -1,10 +1,12 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
mod data;
|
||||
mod document;
|
||||
mod extensions;
|
||||
pub mod history;
|
||||
mod view;
|
||||
|
||||
pub use document::*;
|
||||
pub(crate) use extensions::*;
|
||||
pub use view::*;
|
||||
|
||||
mod data;
|
||||
pub mod default;
|
||||
mod document;
|
||||
mod extensions;
|
||||
pub mod history;
|
||||
mod view;
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
use async_stream::stream;
|
||||
use dashmap::DashMap;
|
||||
use futures::stream::StreamExt;
|
||||
use lib_infra::future::FutureResultSend;
|
||||
use lib_ot::{errors::OTError, revision::Revision, rich_text::RichTextDelta};
|
||||
use std::sync::{
|
||||
atomic::{AtomicI64, Ordering::SeqCst},
|
||||
@ -20,9 +21,8 @@ use tokio::{
|
||||
};
|
||||
|
||||
pub trait ServerDocPersistence: Send + Sync {
|
||||
fn create_doc(&self, doc_id: &str, delta: RichTextDelta) -> CollaborateResult<()>;
|
||||
fn update_doc(&self, doc_id: &str, delta: RichTextDelta) -> CollaborateResult<()>;
|
||||
fn read_doc(&self, doc_id: &str) -> CollaborateResult<Doc>;
|
||||
fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError>;
|
||||
fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError>;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
@ -59,18 +59,25 @@ impl ServerDocManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, doc_id: &str) -> Option<Arc<OpenDocHandle>> {
|
||||
self.open_doc_map.get(doc_id).map(|ctx| ctx.clone())
|
||||
pub async fn get(&self, doc_id: &str) -> Result<Option<Arc<OpenDocHandle>>, CollaborateError> {
|
||||
match self.open_doc_map.get(doc_id).map(|ctx| ctx.clone()) {
|
||||
Some(edit_doc) => Ok(Some(edit_doc)),
|
||||
None => {
|
||||
let doc = self.persistence.read_doc(doc_id).await?;
|
||||
let handler = self.cache(doc).await.map_err(internal_error)?;
|
||||
Ok(Some(handler))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn cache(&self, doc: Doc) -> Result<(), CollaborateError> {
|
||||
async fn cache(&self, doc: Doc) -> Result<Arc<OpenDocHandle>, CollaborateError> {
|
||||
let doc_id = doc.id.clone();
|
||||
let handle = spawn_blocking(|| OpenDocHandle::new(doc))
|
||||
.await
|
||||
.map_err(internal_error)?;
|
||||
let handle = Arc::new(handle?);
|
||||
self.open_doc_map.insert(doc_id, handle);
|
||||
Ok(())
|
||||
self.open_doc_map.insert(doc_id, handle.clone());
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,5 +2,4 @@ pub mod core;
|
||||
pub mod entities;
|
||||
pub mod errors;
|
||||
pub mod protobuf;
|
||||
pub mod user_default;
|
||||
pub mod util;
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
view::{ViewName, ViewThumbnail},
|
||||
},
|
||||
};
|
||||
use flowy_collaboration::user_default::doc_initial_string;
|
||||
use flowy_collaboration::core::document::default::initial_string;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use std::convert::TryInto;
|
||||
|
||||
@ -81,7 +81,7 @@ impl CreateViewParams {
|
||||
desc,
|
||||
thumbnail,
|
||||
view_type,
|
||||
data: doc_initial_string(),
|
||||
data: initial_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
protobuf = {version = "2.18.0"}
|
||||
log = "0.4.14"
|
||||
chrono = "0.4.19"
|
||||
bytes = { version = "1.0" }
|
@ -33,12 +33,12 @@ where
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct ResultFuture<T, E> {
|
||||
pub struct FutureResult<T, E> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = Result<T, E>> + Sync + Send>>,
|
||||
}
|
||||
|
||||
impl<T, E> ResultFuture<T, E> {
|
||||
impl<T, E> FutureResult<T, E> {
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: Future<Output = Result<T, E>> + Send + Sync + 'static,
|
||||
@ -49,7 +49,7 @@ impl<T, E> ResultFuture<T, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Future for ResultFuture<T, E>
|
||||
impl<T, E> Future for FutureResult<T, E>
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Debug,
|
||||
@ -62,3 +62,34 @@ where
|
||||
Poll::Ready(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct FutureResultSend<T, E> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = Result<T, E>> + Send>>,
|
||||
}
|
||||
|
||||
impl<T, E> FutureResultSend<T, E> {
|
||||
pub fn new<F>(f: F) -> Self
|
||||
where
|
||||
F: Future<Output = Result<T, E>> + Send + 'static,
|
||||
{
|
||||
Self {
|
||||
fut: Box::pin(async { f.await }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Future for FutureResultSend<T, E>
|
||||
where
|
||||
T: Send,
|
||||
E: Debug,
|
||||
{
|
||||
type Output = Result<T, E>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
let result = ready!(this.fut.poll(cx));
|
||||
Poll::Ready(result)
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
flowy-derive = { path = "../flowy-derive" }
|
||||
backend-service = { path = "../backend-service" }
|
||||
lib-infra = { path = "../../frontend/rust-lib/lib-infra" }
|
||||
lib-infra = { path = "../lib-infra" }
|
||||
|
||||
tokio-tungstenite = "0.15"
|
||||
futures-util = "0.3.17"
|
||||
|
Loading…
Reference in New Issue
Block a user