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