fix fmt and clippy warnings

This commit is contained in:
appflowy 2022-01-24 17:35:58 +08:00
parent a9eec5baed
commit bba8f8ae01
277 changed files with 906 additions and 2690 deletions

View File

@ -78,9 +78,15 @@ pub struct FlowyPersistence {
} }
impl FlowyPersistence { impl FlowyPersistence {
pub fn pg_pool(&self) -> PgPool { self.pg_pool.clone() } pub fn pg_pool(&self) -> PgPool {
self.pg_pool.clone()
}
pub fn document_kv_store(&self) -> Arc<DocumentRevisionKV> { self.document_store.clone() } pub fn document_kv_store(&self) -> Arc<DocumentRevisionKV> {
self.document_store.clone()
}
pub fn folder_kv_store(&self) -> Arc<FolderRevisionKV> { self.folder_store.clone() } pub fn folder_kv_store(&self) -> Arc<FolderRevisionKV> {
self.folder_store.clone()
}
} }

View File

@ -10,8 +10,7 @@ use backend_service::errors::{internal_error, Result, ServerError};
use crate::services::web_socket::revision_data_to_ws_message; use crate::services::web_socket::revision_data_to_ws_message;
use flowy_collaboration::{ use flowy_collaboration::{
protobuf::{ protobuf::{
ClientRevisionWSData as ClientRevisionWSDataPB, ClientRevisionWSData as ClientRevisionWSDataPB, ClientRevisionWSDataType as ClientRevisionWSDataTypePB,
ClientRevisionWSDataType as ClientRevisionWSDataTypePB,
Revision as RevisionPB, Revision as RevisionPB,
}, },
server_document::ServerDocumentManager, server_document::ServerDocumentManager,
@ -69,7 +68,7 @@ impl DocumentWebSocketActor {
ret, ret,
} => { } => {
let _ = ret.send(self.handle_document_data(client_data).await); let _ = ret.send(self.handle_document_data(client_data).await);
}, }
} }
} }
@ -94,14 +93,14 @@ impl DocumentWebSocketActor {
.handle_client_revisions(user, document_client_data) .handle_client_revisions(user, document_client_data)
.await .await
.map_err(internal_error)?; .map_err(internal_error)?;
}, }
ClientRevisionWSDataTypePB::ClientPing => { ClientRevisionWSDataTypePB::ClientPing => {
let _ = self let _ = self
.doc_manager .doc_manager
.handle_client_ping(user, document_client_data) .handle_client_ping(user, document_client_data)
.await .await
.map_err(internal_error)?; .map_err(internal_error)?;
}, }
} }
Ok(()) Ok(())
@ -132,26 +131,28 @@ impl std::fmt::Debug for DocumentRevisionUser {
} }
impl RevisionUser for DocumentRevisionUser { impl RevisionUser for DocumentRevisionUser {
fn user_id(&self) -> String { self.user.id().to_string() } fn user_id(&self) -> String {
self.user.id().to_string()
}
fn receive(&self, resp: RevisionSyncResponse) { fn receive(&self, resp: RevisionSyncResponse) {
let result = match resp { let result = match resp {
RevisionSyncResponse::Pull(data) => { RevisionSyncResponse::Pull(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
RevisionSyncResponse::Push(data) => { RevisionSyncResponse::Push(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
RevisionSyncResponse::Ack(data) => { RevisionSyncResponse::Ack(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Document);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
}; };
match result { match result {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("[DocumentRevisionUser]: {}", e), Err(e) => log::error!("[DocumentRevisionUser]: {}", e),
} }
} }

View File

@ -14,9 +14,7 @@ use flowy_collaboration::{
entities::document_info::DocumentInfo, entities::document_info::DocumentInfo,
errors::CollaborateError, errors::CollaborateError,
protobuf::{ protobuf::{
CreateDocParams as CreateDocParamsPB, CreateDocParams as CreateDocParamsPB, DocumentId, RepeatedRevision as RepeatedRevisionPB,
DocumentId,
RepeatedRevision as RepeatedRevisionPB,
Revision as RevisionPB, Revision as RevisionPB,
}, },
server_document::{DocumentCloudPersistence, ServerDocumentManager}, server_document::{DocumentCloudPersistence, ServerDocumentManager},
@ -69,11 +67,11 @@ impl WebSocketReceiver for DocumentWebSocketReceiver {
}; };
match actor_msg_sender.send(msg).await { match actor_msg_sender.send(msg).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("[DocumentWebSocketReceiver]: send message to actor failed: {}", e), Err(e) => log::error!("[DocumentWebSocketReceiver]: send message to actor failed: {}", e),
} }
match rx.await { match rx.await {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("[DocumentWebSocketReceiver]: message ret failed {:?}", e), Err(e) => log::error!("[DocumentWebSocketReceiver]: message ret failed {:?}", e),
}; };
}); });
@ -82,7 +80,9 @@ impl WebSocketReceiver for DocumentWebSocketReceiver {
pub struct HttpDocumentCloudPersistence(pub Arc<DocumentRevisionKV>); pub struct HttpDocumentCloudPersistence(pub Arc<DocumentRevisionKV>);
impl Debug for HttpDocumentCloudPersistence { impl Debug for HttpDocumentCloudPersistence {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str("HttpDocumentCloudPersistence") } fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("HttpDocumentCloudPersistence")
}
} }
impl DocumentCloudPersistence for HttpDocumentCloudPersistence { impl DocumentCloudPersistence for HttpDocumentCloudPersistence {

View File

@ -115,13 +115,13 @@ async fn delete_trash_associate_targets(
match TrashType::from_i32(ty) { match TrashType::from_i32(ty) {
None => log::error!("Parser trash type with value: {} failed", ty), None => log::error!("Parser trash type with value: {} failed", ty),
Some(ty) => match ty { Some(ty) => match ty {
TrashType::Unknown => {}, TrashType::Unknown => {}
TrashType::View => { TrashType::View => {
let _ = delete_view(transaction as &mut DBTransaction<'_>, document_store, vec![id]).await; let _ = delete_view(transaction as &mut DBTransaction<'_>, document_store, vec![id]).await;
}, }
TrashType::App => { TrashType::App => {
let _ = delete_app(transaction as &mut DBTransaction<'_>, id).await; let _ = delete_app(transaction as &mut DBTransaction<'_>, id).await;
}, }
}, },
} }
} }
@ -162,13 +162,13 @@ pub(crate) async fn read_trash(
match TrashType::from_i32(table.ty) { match TrashType::from_i32(table.ty) {
None => log::error!("Parser trash type with value: {} failed", table.ty), None => log::error!("Parser trash type with value: {} failed", table.ty),
Some(ty) => match ty { Some(ty) => match ty {
TrashType::Unknown => {}, TrashType::Unknown => {}
TrashType::View => { TrashType::View => {
trash.push(read_view_table(table.id, transaction).await?.into()); trash.push(read_view_table(table.id, transaction).await?.into());
}, }
TrashType::App => { TrashType::App => {
trash.push(read_app_table(table.id, transaction).await?.into()); trash.push(read_app_table(table.id, transaction).await?.into());
}, }
}, },
} }
} }

View File

@ -2,11 +2,9 @@ use crate::{
context::FlowyPersistence, context::FlowyPersistence,
entities::logged_user::LoggedUser, entities::logged_user::LoggedUser,
services::folder::view::{ services::folder::view::{
create_view, create_view, delete_view,
delete_view,
persistence::{check_view_id, check_view_ids}, persistence::{check_view_id, check_view_ids},
read_view, read_view, update_view,
update_view,
}, },
util::serde_ext::parse_from_payload, util::serde_ext::parse_from_payload,
}; };
@ -22,10 +20,8 @@ use backend_service::{
use flowy_core_data_model::{ use flowy_core_data_model::{
parser::view::{ViewDesc, ViewName, ViewThumbnail}, parser::view::{ViewDesc, ViewName, ViewThumbnail},
protobuf::{ protobuf::{
CreateViewParams as CreateViewParamsPB, CreateViewParams as CreateViewParamsPB, QueryViewRequest as QueryViewRequestPB,
QueryViewRequest as QueryViewRequestPB, UpdateViewParams as UpdateViewParamsPB, ViewId as ViewIdPB,
UpdateViewParams as UpdateViewParamsPB,
ViewId as ViewIdPB,
}, },
}; };
use sqlx::PgPool; use sqlx::PgPool;

View File

@ -1,11 +1,7 @@
use crate::{ use crate::{
entities::logged_user::LoggedUser, entities::logged_user::LoggedUser,
services::folder::workspace::{ services::folder::workspace::{
create_workspace, create_workspace, delete_workspace, persistence::check_workspace_id, read_workspaces, update_workspace,
delete_workspace,
persistence::check_workspace_id,
read_workspaces,
update_workspace,
}, },
util::serde_ext::parse_from_payload, util::serde_ext::parse_from_payload,
}; };
@ -21,8 +17,7 @@ use backend_service::{
use flowy_core_data_model::{ use flowy_core_data_model::{
parser::workspace::{WorkspaceDesc, WorkspaceName}, parser::workspace::{WorkspaceDesc, WorkspaceName},
protobuf::{ protobuf::{
CreateWorkspaceParams as CreateWorkspaceParamsPB, CreateWorkspaceParams as CreateWorkspaceParamsPB, UpdateWorkspaceParams as UpdateWorkspaceParamsPB,
UpdateWorkspaceParams as UpdateWorkspaceParamsPB,
WorkspaceId as WorkspaceIdPB, WorkspaceId as WorkspaceIdPB,
}, },
}; };
@ -110,7 +105,7 @@ pub async fn update_handler(
.map_err(invalid_params)? .map_err(invalid_params)?
.0; .0;
Some(name) Some(name)
}, }
}; };
let desc = match params.has_desc() { let desc = match params.has_desc() {
@ -120,7 +115,7 @@ pub async fn update_handler(
.map_err(invalid_params)? .map_err(invalid_params)?
.0; .0;
Some(desc) Some(desc)
}, }
}; };
let mut transaction = pool let mut transaction = pool

View File

@ -9,8 +9,7 @@ use backend_service::errors::{internal_error, Result};
use flowy_collaboration::{ use flowy_collaboration::{
protobuf::{ protobuf::{
ClientRevisionWSData as ClientRevisionWSDataPB, ClientRevisionWSData as ClientRevisionWSDataPB, ClientRevisionWSDataType as ClientRevisionWSDataTypePB,
ClientRevisionWSDataType as ClientRevisionWSDataTypePB,
}, },
server_folder::ServerFolderManager, server_folder::ServerFolderManager,
synchronizer::{RevisionSyncResponse, RevisionUser}, synchronizer::{RevisionSyncResponse, RevisionUser},
@ -67,7 +66,7 @@ impl FolderWebSocketActor {
ret, ret,
} => { } => {
let _ = ret.send(self.handle_folder_data(client_data).await); let _ = ret.send(self.handle_folder_data(client_data).await);
}, }
} }
} }
@ -92,14 +91,14 @@ impl FolderWebSocketActor {
.handle_client_revisions(user, folder_client_data) .handle_client_revisions(user, folder_client_data)
.await .await
.map_err(internal_error)?; .map_err(internal_error)?;
}, }
ClientRevisionWSDataTypePB::ClientPing => { ClientRevisionWSDataTypePB::ClientPing => {
let _ = self let _ = self
.folder_manager .folder_manager
.handle_client_ping(user, folder_client_data) .handle_client_ping(user, folder_client_data)
.await .await
.map_err(internal_error)?; .map_err(internal_error)?;
}, }
} }
Ok(()) Ok(())
} }
@ -121,26 +120,28 @@ impl std::fmt::Debug for FolderRevisionUser {
} }
impl RevisionUser for FolderRevisionUser { impl RevisionUser for FolderRevisionUser {
fn user_id(&self) -> String { self.user.id().to_string() } fn user_id(&self) -> String {
self.user.id().to_string()
}
fn receive(&self, resp: RevisionSyncResponse) { fn receive(&self, resp: RevisionSyncResponse) {
let result = match resp { let result = match resp {
RevisionSyncResponse::Pull(data) => { RevisionSyncResponse::Pull(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
RevisionSyncResponse::Push(data) => { RevisionSyncResponse::Push(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
RevisionSyncResponse::Ack(data) => { RevisionSyncResponse::Ack(data) => {
let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder); let msg: WebSocketMessage = revision_data_to_ws_message(data, WSChannel::Folder);
self.socket.try_send(msg).map_err(internal_error) self.socket.try_send(msg).map_err(internal_error)
}, }
}; };
match result { match result {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("[FolderRevisionUser]: {}", e), Err(e) => log::error!("[FolderRevisionUser]: {}", e),
} }
} }

View File

@ -57,13 +57,13 @@ impl WebSocketReceiver for FolderWebSocketReceiver {
}; };
match actor_msg_sender.send(msg).await { match actor_msg_sender.send(msg).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => { Err(e) => {
log::error!("[FolderWebSocketReceiver]: send message to actor failed: {}", e); log::error!("[FolderWebSocketReceiver]: send message to actor failed: {}", e);
}, }
} }
match rx.await { match rx.await {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("[FolderWebSocketReceiver]: message ret failed {:?}", e), Err(e) => log::error!("[FolderWebSocketReceiver]: message ret failed {:?}", e),
}; };
}); });
@ -72,7 +72,9 @@ impl WebSocketReceiver for FolderWebSocketReceiver {
pub struct HttpFolderCloudPersistence(pub Arc<FolderRevisionKV>); pub struct HttpFolderCloudPersistence(pub Arc<FolderRevisionKV>);
impl Debug for HttpFolderCloudPersistence { impl Debug for HttpFolderCloudPersistence {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str("HttpFolderCloudPersistence") } fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("HttpFolderCloudPersistence")
}
} }
impl FolderCloudPersistence for HttpFolderCloudPersistence { impl FolderCloudPersistence for HttpFolderCloudPersistence {

View File

@ -16,15 +16,21 @@ pub struct RevisionKVPersistence {
impl std::ops::Deref for RevisionKVPersistence { impl std::ops::Deref for RevisionKVPersistence {
type Target = Arc<KVStore>; type Target = Arc<KVStore>;
fn deref(&self) -> &Self::Target { &self.inner } fn deref(&self) -> &Self::Target {
&self.inner
}
} }
impl std::ops::DerefMut for RevisionKVPersistence { impl std::ops::DerefMut for RevisionKVPersistence {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
} }
impl RevisionKVPersistence { impl RevisionKVPersistence {
pub(crate) fn new(kv_store: Arc<KVStore>) -> Self { RevisionKVPersistence { inner: kv_store } } pub(crate) fn new(kv_store: Arc<KVStore>) -> Self {
RevisionKVPersistence { inner: kv_store }
}
pub(crate) async fn set_revision(&self, revisions: Vec<RevisionPB>) -> Result<(), ServerError> { pub(crate) async fn set_revision(&self, revisions: Vec<RevisionPB>) -> Result<(), ServerError> {
let items = revisions_to_key_value_items(revisions)?; let items = revisions_to_key_value_items(revisions)?;
@ -45,7 +51,7 @@ impl RevisionKVPersistence {
self.inner self.inner
.transaction(|mut t| Box::pin(async move { t.batch_get_start_with(&object_id).await })) .transaction(|mut t| Box::pin(async move { t.batch_get_start_with(&object_id).await }))
.await? .await?
}, }
Some(rev_ids) => { Some(rev_ids) => {
let keys = rev_ids let keys = rev_ids
.into_iter() .into_iter()
@ -55,7 +61,7 @@ impl RevisionKVPersistence {
self.inner self.inner
.transaction(|mut t| Box::pin(async move { t.batch_get(keys).await })) .transaction(|mut t| Box::pin(async move { t.batch_get(keys).await }))
.await? .await?
}, }
}; };
Ok(key_value_items_to_revisions(items)) Ok(key_value_items_to_revisions(items))
@ -72,7 +78,7 @@ impl RevisionKVPersistence {
self.inner self.inner
.transaction(|mut t| Box::pin(async move { t.batch_delete_key_start_with(&object_id).await })) .transaction(|mut t| Box::pin(async move { t.batch_delete_key_start_with(&object_id).await }))
.await .await
}, }
Some(rev_ids) => { Some(rev_ids) => {
let keys = rev_ids let keys = rev_ids
.into_iter() .into_iter()
@ -82,7 +88,7 @@ impl RevisionKVPersistence {
self.inner self.inner
.transaction(|mut t| Box::pin(async move { t.batch_delete(keys).await })) .transaction(|mut t| Box::pin(async move { t.batch_delete(keys).await }))
.await .await
}, }
} }
} }
} }
@ -117,4 +123,6 @@ fn key_value_items_to_revisions(items: Vec<KeyValue>) -> RepeatedRevisionPB {
} }
#[inline] #[inline]
fn make_revision_key(object_id: &str, rev_id: i64) -> String { format!("{}:{}", object_id, rev_id) } fn make_revision_key(object_id: &str, rev_id: i64) -> String {
format!("{}:{}", object_id, rev_id)
}

View File

@ -3,8 +3,7 @@ use crate::{
entities::logged_user::LoggedUser, entities::logged_user::LoggedUser,
services::web_socket::{ services::web_socket::{
entities::{Connect, Disconnect, Socket}, entities::{Connect, Disconnect, Socket},
WSServer, WSServer, WebSocketMessage,
WebSocketMessage,
}, },
}; };
use actix::*; use actix::*;
@ -18,23 +17,24 @@ pub trait WebSocketReceiver: Send + Sync {
fn receive(&self, data: WSClientData); fn receive(&self, data: WSClientData);
} }
#[derive(Default)]
pub struct WebSocketReceivers { pub struct WebSocketReceivers {
inner: HashMap<WSChannel, Arc<dyn WebSocketReceiver>>, inner: HashMap<WSChannel, Arc<dyn WebSocketReceiver>>,
} }
impl std::default::Default for WebSocketReceivers {
fn default() -> Self { Self { inner: HashMap::new() } }
}
impl WebSocketReceivers { impl WebSocketReceivers {
pub fn new() -> Self { WebSocketReceivers::default() } pub fn new() -> Self {
WebSocketReceivers::default()
}
pub fn set(&mut self, channel: WSChannel, receiver: Arc<dyn WebSocketReceiver>) { pub fn set(&mut self, channel: WSChannel, receiver: Arc<dyn WebSocketReceiver>) {
tracing::trace!("Add {:?} receiver", channel); tracing::trace!("Add {:?} receiver", channel);
self.inner.insert(channel, receiver); self.inner.insert(channel, receiver);
} }
pub fn get(&self, source: &WSChannel) -> Option<Arc<dyn WebSocketReceiver>> { self.inner.get(source).cloned() } pub fn get(&self, source: &WSChannel) -> Option<Arc<dyn WebSocketReceiver>> {
self.inner.get(source).cloned()
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -43,9 +43,13 @@ pub struct WSUser {
} }
impl WSUser { impl WSUser {
pub fn new(inner: LoggedUser) -> Self { Self { inner } } pub fn new(inner: LoggedUser) -> Self {
Self { inner }
}
pub fn id(&self) -> &str { &self.inner.user_id } pub fn id(&self) -> &str {
&self.inner.user_id
}
} }
pub struct WSClientData { pub struct WSClientData {
@ -90,7 +94,7 @@ impl WSClient {
match self.ws_receivers.get(&message.channel) { match self.ws_receivers.get(&message.channel) {
None => { None => {
log::error!("Can't find the receiver for {:?}", message.channel); log::error!("Can't find the receiver for {:?}", message.channel);
}, }
Some(handler) => { Some(handler) => {
let client_data = WSClientData { let client_data = WSClientData {
user: self.user.clone(), user: self.user.clone(),
@ -98,7 +102,7 @@ impl WSClient {
data: Bytes::from(message.data), data: Bytes::from(message.data),
}; };
handler.receive(client_data); handler.receive(client_data);
}, }
} }
} }
} }
@ -109,28 +113,28 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSClient {
Ok(ws::Message::Ping(msg)) => { Ok(ws::Message::Ping(msg)) => {
self.hb = Instant::now(); self.hb = Instant::now();
ctx.pong(&msg); ctx.pong(&msg);
}, }
Ok(ws::Message::Pong(_msg)) => { Ok(ws::Message::Pong(_msg)) => {
// tracing::debug!("Receive {} pong {:?}", &self.session_id, &msg); // tracing::debug!("Receive {} pong {:?}", &self.session_id, &msg);
self.hb = Instant::now(); self.hb = Instant::now();
}, }
Ok(ws::Message::Binary(bytes)) => { Ok(ws::Message::Binary(bytes)) => {
let socket = ctx.address().recipient(); let socket = ctx.address().recipient();
self.handle_binary_message(bytes, socket); self.handle_binary_message(bytes, socket);
}, }
Ok(Text(_)) => { Ok(Text(_)) => {
log::warn!("Receive unexpected text message"); log::warn!("Receive unexpected text message");
}, }
Ok(ws::Message::Close(reason)) => { Ok(ws::Message::Close(reason)) => {
ctx.close(reason); ctx.close(reason);
ctx.stop(); ctx.stop();
}, }
Ok(ws::Message::Continuation(_)) => {}, Ok(ws::Message::Continuation(_)) => {}
Ok(ws::Message::Nop) => {}, Ok(ws::Message::Nop) => {}
Err(e) => { Err(e) => {
log::error!("[{}]: WebSocketStream protocol error {:?}", self.user.id(), e); log::error!("[{}]: WebSocketStream protocol error {:?}", self.user.id(), e);
ctx.stop(); ctx.stop();
}, }
} }
} }
} }
@ -138,7 +142,9 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSClient {
impl Handler<WebSocketMessage> for WSClient { impl Handler<WebSocketMessage> for WSClient {
type Result = (); type Result = ();
fn handle(&mut self, msg: WebSocketMessage, ctx: &mut Self::Context) { ctx.binary(msg.0); } fn handle(&mut self, msg: WebSocketMessage, ctx: &mut Self::Context) {
ctx.binary(msg.0);
}
} }
impl Actor for WSClient { impl Actor for WSClient {

View File

@ -88,7 +88,7 @@ async fn user_update_name() {
let server = TestUserServer::new().await; let server = TestUserServer::new().await;
let name = "tom".to_string(); let name = "tom".to_string();
let params = UpdateUserParams::new(&server.user_id()).name(&name); let params = UpdateUserParams::new(server.user_id()).name(&name);
server.update_user_profile(params).await.unwrap(); server.update_user_profile(params).await.unwrap();
let user = server.get_user_profile().await; let user = server.get_user_profile().await;

View File

@ -55,6 +55,7 @@ struct ScriptContext {
client_editor: Option<Arc<ClientDocumentEditor>>, client_editor: Option<Arc<ClientDocumentEditor>>,
client_sdk: FlowySDKTest, client_sdk: FlowySDKTest,
client_user_session: Arc<UserSession>, client_user_session: Arc<UserSession>,
#[allow(dead_code)]
ws_conn: Arc<FlowyWebSocketConnect>, ws_conn: Arc<FlowyWebSocketConnect>,
server: TestServer, server: TestServer,
doc_id: String, doc_id: String,

View File

0
frontend/rust-lib/Cargo.toml Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/Cargo.toml Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/Flowy.toml Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/binding.h Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/c.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/lib.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/model/ffi_request.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/model/ffi_response.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/model/mod.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-ffi/src/protobuf/mod.rs Normal file → Executable file
View File

View File

View File

0
frontend/rust-lib/dart-ffi/src/protobuf/model/mod.rs Normal file → Executable file
View File

View File

View File

0
frontend/rust-lib/dart-ffi/src/util.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/Cargo.toml Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/Flowy.toml Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/src/dart/mod.rs Normal file → Executable file
View File

View File

0
frontend/rust-lib/dart-notify/src/entities/mod.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/src/entities/subject.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/src/lib.rs Normal file → Executable file
View File

0
frontend/rust-lib/dart-notify/src/protobuf/mod.rs Normal file → Executable file
View File

View File

View File

View File

0
frontend/rust-lib/flowy-core/Cargo.toml Normal file → Executable file
View File

0
frontend/rust-lib/flowy-core/Flowy.toml Normal file → Executable file
View File

View File

@ -1,141 +0,0 @@
use std::{collections::HashMap, sync::Arc};
use chrono::Utc;
use lazy_static::lazy_static;
use parking_lot::RwLock;
use flowy_collaboration::document::default::{initial_delta, initial_read_me};
use flowy_core_data_model::{entities::view::CreateViewParams, user_default};
use flowy_net::entities::NetworkType;
use crate::{
entities::workspace::RepeatedWorkspace,
errors::{FlowyError, FlowyResult},
module::{WorkspaceDatabase, WorkspaceUser},
notify::{send_dart_notification, WorkspaceNotification},
services::{server::Server, AppController, TrashController, ViewController, WorkspaceController},
};
lazy_static! {
static ref INIT_WORKSPACE: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
}
pub struct CoreContext {
pub user: Arc<dyn WorkspaceUser>,
pub(crate) server: Server,
pub(crate) database: Arc<dyn WorkspaceDatabase>,
pub workspace_controller: Arc<WorkspaceController>,
pub(crate) app_controller: Arc<AppController>,
pub(crate) view_controller: Arc<ViewController>,
pub(crate) trash_controller: Arc<TrashController>,
}
impl CoreContext {
pub(crate) fn new(
user: Arc<dyn WorkspaceUser>,
server: Server,
database: Arc<dyn WorkspaceDatabase>,
workspace_controller: Arc<WorkspaceController>,
app_controller: Arc<AppController>,
view_controller: Arc<ViewController>,
trash_controller: Arc<TrashController>,
) -> Self {
if let Ok(token) = user.token() {
INIT_WORKSPACE.write().insert(token, false);
}
Self {
user,
server,
database,
workspace_controller,
app_controller,
view_controller,
trash_controller,
}
}
pub fn network_state_changed(&self, new_type: NetworkType) {
match new_type {
NetworkType::UnknownNetworkType => {}
NetworkType::Wifi => {}
NetworkType::Cell => {}
NetworkType::Ethernet => {}
}
}
pub async fn user_did_sign_in(&self, token: &str) -> FlowyResult<()> {
log::debug!("workspace initialize after sign in");
let _ = self.init(token).await?;
Ok(())
}
pub async fn user_did_logout(&self) {
// TODO: (nathan) do something here
}
pub async fn user_session_expired(&self) {
// TODO: (nathan) do something here
}
pub async fn user_did_sign_up(&self, _token: &str) -> FlowyResult<()> {
log::debug!("Create user default workspace");
let time = Utc::now();
let mut workspace = user_default::create_default_workspace(time);
let apps = workspace.take_apps().into_inner();
let cloned_workspace = workspace.clone();
let _ = self.workspace_controller.create_workspace_on_local(workspace).await?;
for mut app in apps {
let app_id = app.id.clone();
let views = app.take_belongings().into_inner();
let _ = self.app_controller.create_app_on_local(app).await?;
for (index, view) in views.into_iter().enumerate() {
let view_data = if index == 0 {
initial_read_me().to_json()
} else {
initial_delta().to_json()
};
self.view_controller.set_latest_view(&view);
let params = CreateViewParams {
belong_to_id: app_id.clone(),
name: view.name,
desc: view.desc,
thumbnail: "".to_string(),
view_type: view.view_type,
view_data,
view_id: view.id.clone(),
};
let _ = self.view_controller.create_view_from_params(params).await?;
}
}
let token = self.user.token()?;
let repeated_workspace = RepeatedWorkspace {
items: vec![cloned_workspace],
};
send_dart_notification(&token, WorkspaceNotification::UserCreateWorkspace)
.payload(repeated_workspace)
.send();
tracing::debug!("Create default workspace after sign up");
let _ = self.init(&token).await?;
Ok(())
}
async fn init(&self, token: &str) -> Result<(), FlowyError> {
if let Some(is_init) = INIT_WORKSPACE.read().get(token) {
if *is_init {
return Ok(());
}
}
INIT_WORKSPACE.write().insert(token.to_owned(), true);
let _ = self.workspace_controller.init()?;
let _ = self.app_controller.init()?;
let _ = self.view_controller.init()?;
let _ = self.trash_controller.init()?;
Ok(())
}
}

41
frontend/rust-lib/flowy-core/src/controller.rs Normal file → Executable file
View File

@ -17,13 +17,8 @@ use crate::{
errors::FlowyResult, errors::FlowyResult,
module::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser}, module::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
services::{ services::{
folder_editor::FolderEditor, folder_editor::FolderEditor, persistence::FolderPersistence, set_current_workspace, AppController,
persistence::FolderPersistence, TrashController, ViewController, WorkspaceController,
set_current_workspace,
AppController,
TrashController,
ViewController,
WorkspaceController,
}, },
}; };
@ -36,19 +31,27 @@ const FOLDER_ID_SPLIT: &str = ":";
#[derive(Clone)] #[derive(Clone)]
pub struct FolderId(String); pub struct FolderId(String);
impl FolderId { impl FolderId {
pub fn new(user_id: &str) -> Self { Self(format!("{}{}{}", user_id, FOLDER_ID_SPLIT, FOLDER_ID)) } pub fn new(user_id: &str) -> Self {
Self(format!("{}{}{}", user_id, FOLDER_ID_SPLIT, FOLDER_ID))
}
} }
impl std::fmt::Display for FolderId { impl std::fmt::Display for FolderId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(FOLDER_ID) } fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(FOLDER_ID)
}
} }
impl std::fmt::Debug for FolderId { impl std::fmt::Debug for FolderId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(FOLDER_ID) } fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(FOLDER_ID)
}
} }
impl AsRef<str> for FolderId { impl AsRef<str> for FolderId {
fn as_ref(&self) -> &str { &self.0 } fn as_ref(&self) -> &str {
&self.0
}
} }
pub struct FolderManager { pub struct FolderManager {
@ -128,15 +131,15 @@ impl FolderManager {
let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into(); let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into();
match result { match result {
Ok(data) => match self.folder_editor.read().await.clone() { Ok(data) => match self.folder_editor.read().await.clone() {
None => {}, None => {}
Some(editor) => match editor.receive_ws_data(data).await { Some(editor) => match editor.receive_ws_data(data).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => tracing::error!("Folder receive data error: {:?}", e), Err(e) => tracing::error!("Folder receive data error: {:?}", e),
}, },
}, },
Err(e) => { Err(e) => {
tracing::error!("Folder ws data parser failed: {:?}", e); tracing::error!("Folder ws data parser failed: {:?}", e);
}, }
} }
} }
@ -165,7 +168,9 @@ impl FolderManager {
self.initialize(user_id, token).await self.initialize(user_id, token).await
} }
pub async fn clear(&self) { *self.folder_editor.write().await = None; } pub async fn clear(&self) {
*self.folder_editor.write().await = None;
}
} }
struct DefaultFolderBuilder(); struct DefaultFolderBuilder();
@ -187,7 +192,7 @@ impl DefaultFolderBuilder {
} else { } else {
initial_delta().to_json() initial_delta().to_json()
}; };
view_controller.set_latest_view(&view); view_controller.set_latest_view(view);
let _ = view_controller let _ = view_controller
.create_view_document_content(&view.id, view_data) .create_view_document_content(&view.id, view_data)
.await?; .await?;
@ -206,5 +211,7 @@ impl DefaultFolderBuilder {
#[cfg(feature = "flowy_unit_test")] #[cfg(feature = "flowy_unit_test")]
impl FolderManager { impl FolderManager {
pub async fn folder_editor(&self) -> Arc<FolderEditor> { self.folder_editor.read().await.clone().unwrap() } pub async fn folder_editor(&self) -> Arc<FolderEditor> {
self.folder_editor.read().await.clone().unwrap()
}
} }

0
frontend/rust-lib/flowy-core/src/dart_notification.rs Normal file → Executable file
View File

48
frontend/rust-lib/flowy-core/src/event.rs Normal file → Executable file
View File

@ -5,77 +5,77 @@ use strum_macros::Display;
#[event_err = "FlowyError"] #[event_err = "FlowyError"]
pub enum WorkspaceEvent { pub enum WorkspaceEvent {
#[event(input = "CreateWorkspaceRequest", output = "Workspace")] #[event(input = "CreateWorkspaceRequest", output = "Workspace")]
CreateWorkspace = 0, CreateWorkspace = 0,
#[event(output = "CurrentWorkspaceSetting")] #[event(output = "CurrentWorkspaceSetting")]
ReadCurWorkspace = 1, ReadCurWorkspace = 1,
#[event(input = "QueryWorkspaceRequest", output = "RepeatedWorkspace")] #[event(input = "QueryWorkspaceRequest", output = "RepeatedWorkspace")]
ReadWorkspaces = 2, ReadWorkspaces = 2,
#[event(input = "QueryWorkspaceRequest")] #[event(input = "QueryWorkspaceRequest")]
DeleteWorkspace = 3, DeleteWorkspace = 3,
#[event(input = "QueryWorkspaceRequest", output = "Workspace")] #[event(input = "QueryWorkspaceRequest", output = "Workspace")]
OpenWorkspace = 4, OpenWorkspace = 4,
#[event(input = "QueryWorkspaceRequest", output = "RepeatedApp")] #[event(input = "QueryWorkspaceRequest", output = "RepeatedApp")]
ReadWorkspaceApps = 5, ReadWorkspaceApps = 5,
#[event(input = "CreateAppRequest", output = "App")] #[event(input = "CreateAppRequest", output = "App")]
CreateApp = 101, CreateApp = 101,
#[event(input = "QueryAppRequest")] #[event(input = "QueryAppRequest")]
DeleteApp = 102, DeleteApp = 102,
#[event(input = "QueryAppRequest", output = "App")] #[event(input = "QueryAppRequest", output = "App")]
ReadApp = 103, ReadApp = 103,
#[event(input = "UpdateAppRequest")] #[event(input = "UpdateAppRequest")]
UpdateApp = 104, UpdateApp = 104,
#[event(input = "CreateViewRequest", output = "View")] #[event(input = "CreateViewRequest", output = "View")]
CreateView = 201, CreateView = 201,
#[event(input = "QueryViewRequest", output = "View")] #[event(input = "QueryViewRequest", output = "View")]
ReadView = 202, ReadView = 202,
#[event(input = "UpdateViewRequest", output = "View")] #[event(input = "UpdateViewRequest", output = "View")]
UpdateView = 203, UpdateView = 203,
#[event(input = "QueryViewRequest")] #[event(input = "QueryViewRequest")]
DeleteView = 204, DeleteView = 204,
#[event(input = "QueryViewRequest")] #[event(input = "QueryViewRequest")]
DuplicateView = 205, DuplicateView = 205,
#[event()] #[event()]
CopyLink = 206, CopyLink = 206,
#[event(input = "QueryViewRequest", output = "DocumentDelta")] #[event(input = "QueryViewRequest", output = "DocumentDelta")]
OpenDocument = 207, OpenDocument = 207,
#[event(input = "QueryViewRequest")] #[event(input = "QueryViewRequest")]
CloseView = 208, CloseView = 208,
#[event(output = "RepeatedTrash")] #[event(output = "RepeatedTrash")]
ReadTrash = 300, ReadTrash = 300,
#[event(input = "TrashId")] #[event(input = "TrashId")]
PutbackTrash = 301, PutbackTrash = 301,
#[event(input = "RepeatedTrashId")] #[event(input = "RepeatedTrashId")]
DeleteTrash = 302, DeleteTrash = 302,
#[event()] #[event()]
RestoreAllTrash = 303, RestoreAllTrash = 303,
#[event()] #[event()]
DeleteAllTrash = 304, DeleteAllTrash = 304,
#[event(input = "DocumentDelta", output = "DocumentDelta")] #[event(input = "DocumentDelta", output = "DocumentDelta")]
ApplyDocDelta = 400, ApplyDocDelta = 400,
#[event(input = "ExportRequest", output = "ExportData")] #[event(input = "ExportRequest", output = "ExportData")]
ExportDocument = 500, ExportDocument = 500,
} }

View File

@ -1,111 +0,0 @@
use crate::{
context::CoreContext,
errors::FlowyError,
notify::{send_dart_notification, WorkspaceNotification},
services::{
get_current_workspace, read_local_workspace_apps,
workspace::sql::{WorkspaceTable, WorkspaceTableSql},
},
};
use flowy_core_data_model::entities::{
view::View,
workspace::{CurrentWorkspaceSetting, QueryWorkspaceRequest, RepeatedWorkspace, WorkspaceId},
};
use lib_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc};
#[tracing::instrument(skip(data, core), err)]
pub(crate) async fn read_workspaces_handler(
data: Data<QueryWorkspaceRequest>,
core: Unit<Arc<CoreContext>>,
) -> DataResult<RepeatedWorkspace, FlowyError> {
let params: WorkspaceId = data.into_inner().try_into()?;
let user_id = core.user.user_id()?;
let conn = &*core.database.db_connection()?;
let workspace_controller = core.workspace_controller.clone();
let trash_controller = core.trash_controller.clone();
let workspaces = conn.immediate_transaction::<_, FlowyError, _>(|| {
let mut workspaces = workspace_controller.read_local_workspaces(params.workspace_id.clone(), &user_id, conn)?;
for workspace in workspaces.iter_mut() {
let apps = read_local_workspace_apps(&workspace.id, trash_controller.clone(), conn)?.into_inner();
workspace.apps.items = apps;
}
Ok(workspaces)
})?;
let _ = read_workspaces_on_server(core, user_id, params);
data_result(workspaces)
}
#[tracing::instrument(skip(core), err)]
pub async fn read_cur_workspace_handler(
core: Unit<Arc<CoreContext>>,
) -> DataResult<CurrentWorkspaceSetting, FlowyError> {
let workspace_id = get_current_workspace()?;
let user_id = core.user.user_id()?;
let params = WorkspaceId {
workspace_id: Some(workspace_id.clone()),
};
let conn = &*core.database.db_connection()?;
let workspace = core
.workspace_controller
.read_local_workspace(workspace_id, &user_id, conn)?;
let latest_view: Option<View> = core.view_controller.latest_visit_view().unwrap_or(None);
let setting = CurrentWorkspaceSetting { workspace, latest_view };
let _ = read_workspaces_on_server(core, user_id, params);
data_result(setting)
}
#[tracing::instrument(level = "debug", skip(core), err)]
fn read_workspaces_on_server(
core: Unit<Arc<CoreContext>>,
user_id: String,
params: WorkspaceId,
) -> Result<(), FlowyError> {
let (token, server) = (core.user.token()?, core.server.clone());
let app_ctrl = core.app_controller.clone();
let view_ctrl = core.view_controller.clone();
let conn = core.database.db_connection()?;
tokio::spawn(async move {
// Opti: handle the error and retry?
let workspaces = server.read_workspace(&token, params).await?;
let _ = (&*conn).immediate_transaction::<_, FlowyError, _>(|| {
tracing::debug!("Save {} workspace", workspaces.len());
for workspace in &workspaces.items {
let m_workspace = workspace.clone();
let apps = m_workspace.apps.clone().into_inner();
let workspace_table = WorkspaceTable::new(m_workspace, &user_id);
let _ = WorkspaceTableSql::create_workspace(workspace_table, &*conn)?;
tracing::debug!("Save {} apps", apps.len());
for app in apps {
let views = app.belongings.clone().into_inner();
match app_ctrl.save_app(app, &*conn) {
Ok(_) => {}
Err(e) => log::error!("create app failed: {:?}", e),
}
tracing::debug!("Save {} views", views.len());
for view in views {
match view_ctrl.save_view(view, &*conn) {
Ok(_) => {}
Err(e) => log::error!("create view failed: {:?}", e),
}
}
}
}
Ok(())
})?;
send_dart_notification(&token, WorkspaceNotification::WorkspaceListUpdated)
.payload(workspaces)
.send();
Result::<(), FlowyError>::Ok(())
});
Ok(())
}

0
frontend/rust-lib/flowy-core/src/lib.rs Normal file → Executable file
View File

0
frontend/rust-lib/flowy-core/src/macros.rs Normal file → Executable file
View File

0
frontend/rust-lib/flowy-core/src/module.rs Normal file → Executable file
View File

0
frontend/rust-lib/flowy-core/src/protobuf/mod.rs Normal file → Executable file
View File

View File

View File

0
frontend/rust-lib/flowy-core/src/protobuf/model/mod.rs Normal file → Executable file
View File

View File

View File

@ -8,8 +8,7 @@ use crate::{
module::{FolderCouldServiceV1, WorkspaceUser}, module::{FolderCouldServiceV1, WorkspaceUser},
services::{ services::{
persistence::{AppChangeset, FolderPersistence, FolderPersistenceTransaction}, persistence::{AppChangeset, FolderPersistence, FolderPersistenceTransaction},
TrashController, TrashController, TrashEvent,
TrashEvent,
}, },
}; };
@ -125,11 +124,11 @@ impl AppController {
let server = self.cloud_service.clone(); let server = self.cloud_service.clone();
tokio::spawn(async move { tokio::spawn(async move {
match server.update_app(&token, params).await { match server.update_app(&token, params).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => { Err(e) => {
// TODO: retry? // TODO: retry?
log::error!("Update app failed: {:?}", e); log::error!("Update app failed: {:?}", e);
}, }
} }
}); });
Ok(()) Ok(())
@ -151,11 +150,11 @@ impl AppController {
send_dart_notification(&app.id, WorkspaceNotification::AppUpdated) send_dart_notification(&app.id, WorkspaceNotification::AppUpdated)
.payload(app) .payload(app)
.send(); .send();
}, }
Err(e) => log::error!("Save app failed: {:?}", e), Err(e) => log::error!("Save app failed: {:?}", e),
} }
}, }
Ok(None) => {}, Ok(None) => {}
Err(e) => log::error!("Read app failed: {:?}", e), Err(e) => log::error!("Read app failed: {:?}", e),
} }
}); });
@ -200,7 +199,7 @@ async fn handle_trash_event(
}) })
.await; .await;
let _ = ret.send(result).await; let _ = ret.send(result).await;
}, }
TrashEvent::Delete(identifiers, ret) => { TrashEvent::Delete(identifiers, ret) => {
let result = persistence let result = persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
@ -218,7 +217,7 @@ async fn handle_trash_event(
}) })
.await; .await;
let _ = ret.send(result).await; let _ = ret.send(result).await;
}, }
} }
} }

View File

0
frontend/rust-lib/flowy-core/src/services/app/mod.rs Normal file → Executable file
View File

View File

@ -7,11 +7,7 @@ use flowy_collaboration::{
use crate::controller::FolderId; use crate::controller::FolderId;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_sync::{ use flowy_sync::{
RevisionCache, RevisionCache, RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket,
RevisionCloudService,
RevisionManager,
RevisionObjectBuilder,
RevisionWebSocket,
RevisionWebSocketManager, RevisionWebSocketManager,
}; };
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
@ -112,5 +108,7 @@ impl RevisionCloudService for FolderRevisionCloudServiceImpl {
#[cfg(feature = "flowy_unit_test")] #[cfg(feature = "flowy_unit_test")]
impl FolderEditor { impl FolderEditor {
pub fn rev_manager(&self) -> Arc<RevisionManager> { self.rev_manager.clone() } pub fn rev_manager(&self) -> Arc<RevisionManager> {
self.rev_manager.clone()
}
} }

0
frontend/rust-lib/flowy-core/src/services/mod.rs Normal file → Executable file
View File

View File

View File

@ -95,7 +95,9 @@ impl FolderPersistence {
} }
} }
pub fn db_pool(&self) -> FlowyResult<Arc<ConnectionPool>> { self.database.db_pool() } pub fn db_pool(&self) -> FlowyResult<Arc<ConnectionPool>> {
self.database.db_pool()
}
pub async fn initialize(&self, user_id: &str, folder_id: &FolderId) -> FlowyResult<()> { pub async fn initialize(&self, user_id: &str, folder_id: &FolderId) -> FlowyResult<()> {
let migrations = FolderMigration::new(user_id, self.database.clone()); let migrations = FolderMigration::new(user_id, self.database.clone());

View File

View File

@ -4,8 +4,7 @@ use crate::services::persistence::{
view_sql::{ViewChangeset, ViewTableSql}, view_sql::{ViewChangeset, ViewTableSql},
workspace_sql::{WorkspaceChangeset, WorkspaceTableSql}, workspace_sql::{WorkspaceChangeset, WorkspaceTableSql},
}, },
FolderPersistenceTransaction, FolderPersistenceTransaction, TrashTableSql,
TrashTableSql,
}; };
use flowy_core_data_model::entities::{ use flowy_core_data_model::entities::{
app::App, app::App,
@ -103,7 +102,7 @@ impl<'a> FolderPersistenceTransaction for V1Transaction<'a> {
Ok(RepeatedTrash { Ok(RepeatedTrash {
items: vec![Trash::from(table)], items: vec![Trash::from(table)],
}) })
}, }
} }
} }
@ -112,10 +111,10 @@ impl<'a> FolderPersistenceTransaction for V1Transaction<'a> {
None => TrashTableSql::delete_all(&*self.0), None => TrashTableSql::delete_all(&*self.0),
Some(trash_ids) => { Some(trash_ids) => {
for trash_id in &trash_ids { for trash_id in &trash_ids {
let _ = TrashTableSql::delete_trash(&trash_id, &*self.0)?; let _ = TrashTableSql::delete_trash(trash_id, &*self.0)?;
} }
Ok(()) Ok(())
}, }
} }
} }
} }
@ -137,33 +136,59 @@ where
(**self).update_workspace(changeset) (**self).update_workspace(changeset)
} }
fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> { (**self).delete_workspace(workspace_id) } fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
(**self).delete_workspace(workspace_id)
}
fn create_app(&self, app: App) -> FlowyResult<()> { (**self).create_app(app) } fn create_app(&self, app: App) -> FlowyResult<()> {
(**self).create_app(app)
}
fn update_app(&self, changeset: AppChangeset) -> FlowyResult<()> { (**self).update_app(changeset) } fn update_app(&self, changeset: AppChangeset) -> FlowyResult<()> {
(**self).update_app(changeset)
}
fn read_app(&self, app_id: &str) -> FlowyResult<App> { (**self).read_app(app_id) } fn read_app(&self, app_id: &str) -> FlowyResult<App> {
(**self).read_app(app_id)
}
fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<App>> { fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<App>> {
(**self).read_workspace_apps(workspace_id) (**self).read_workspace_apps(workspace_id)
} }
fn delete_app(&self, app_id: &str) -> FlowyResult<App> { (**self).delete_app(app_id) } fn delete_app(&self, app_id: &str) -> FlowyResult<App> {
(**self).delete_app(app_id)
}
fn create_view(&self, view: View) -> FlowyResult<()> { (**self).create_view(view) } fn create_view(&self, view: View) -> FlowyResult<()> {
(**self).create_view(view)
}
fn read_view(&self, view_id: &str) -> FlowyResult<View> { (**self).read_view(view_id) } fn read_view(&self, view_id: &str) -> FlowyResult<View> {
(**self).read_view(view_id)
}
fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<View>> { (**self).read_views(belong_to_id) } fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<View>> {
(**self).read_views(belong_to_id)
}
fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()> { (**self).update_view(changeset) } fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()> {
(**self).update_view(changeset)
}
fn delete_view(&self, view_id: &str) -> FlowyResult<()> { (**self).delete_view(view_id) } fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
(**self).delete_view(view_id)
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> { (**self).create_trash(trashes) } fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
(**self).create_trash(trashes)
}
fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<RepeatedTrash> { (**self).read_trash(trash_id) } fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<RepeatedTrash> {
(**self).read_trash(trash_id)
}
fn delete_trash(&self, trash_ids: Option<Vec<String>>) -> FlowyResult<()> { (**self).delete_trash(trash_ids) } fn delete_trash(&self, trash_ids: Option<Vec<String>>) -> FlowyResult<()> {
(**self).delete_trash(trash_ids)
}
} }

View File

@ -17,7 +17,7 @@ impl WorkspaceTableSql {
workspace: Workspace, workspace: Workspace,
conn: &SqliteConnection, conn: &SqliteConnection,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let table = WorkspaceTable::new(workspace, &user_id); let table = WorkspaceTable::new(workspace, user_id);
match diesel_record_count!(workspace_table, &table.id, conn) { match diesel_record_count!(workspace_table, &table.id, conn) {
0 => diesel_insert_table!(workspace_table, &table, conn), 0 => diesel_insert_table!(workspace_table, &table, conn),
_ => { _ => {

View File

View File

@ -70,7 +70,7 @@ impl FolderPersistenceTransaction for FolderEditor {
match workspaces.first() { match workspaces.first() {
None => { None => {
Err(FlowyError::record_not_found().context(format!("can't find workspace with id {}", workspace_id))) Err(FlowyError::record_not_found().context(format!("can't find workspace with id {}", workspace_id)))
}, }
Some(workspace) => Ok(workspace.apps.clone().take_items()), Some(workspace) => Ok(workspace.apps.clone().take_items()),
} }
} }
@ -154,33 +154,59 @@ where
(**self).update_workspace(changeset) (**self).update_workspace(changeset)
} }
fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> { (**self).delete_workspace(workspace_id) } fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
(**self).delete_workspace(workspace_id)
}
fn create_app(&self, app: App) -> FlowyResult<()> { (**self).create_app(app) } fn create_app(&self, app: App) -> FlowyResult<()> {
(**self).create_app(app)
}
fn update_app(&self, changeset: AppChangeset) -> FlowyResult<()> { (**self).update_app(changeset) } fn update_app(&self, changeset: AppChangeset) -> FlowyResult<()> {
(**self).update_app(changeset)
}
fn read_app(&self, app_id: &str) -> FlowyResult<App> { (**self).read_app(app_id) } fn read_app(&self, app_id: &str) -> FlowyResult<App> {
(**self).read_app(app_id)
}
fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<App>> { fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<App>> {
(**self).read_workspace_apps(workspace_id) (**self).read_workspace_apps(workspace_id)
} }
fn delete_app(&self, app_id: &str) -> FlowyResult<App> { (**self).delete_app(app_id) } fn delete_app(&self, app_id: &str) -> FlowyResult<App> {
(**self).delete_app(app_id)
}
fn create_view(&self, view: View) -> FlowyResult<()> { (**self).create_view(view) } fn create_view(&self, view: View) -> FlowyResult<()> {
(**self).create_view(view)
}
fn read_view(&self, view_id: &str) -> FlowyResult<View> { (**self).read_view(view_id) } fn read_view(&self, view_id: &str) -> FlowyResult<View> {
(**self).read_view(view_id)
}
fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<View>> { (**self).read_views(belong_to_id) } fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<View>> {
(**self).read_views(belong_to_id)
}
fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()> { (**self).update_view(changeset) } fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()> {
(**self).update_view(changeset)
}
fn delete_view(&self, view_id: &str) -> FlowyResult<()> { (**self).delete_view(view_id) } fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
(**self).delete_view(view_id)
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> { (**self).create_trash(trashes) } fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
(**self).create_trash(trashes)
}
fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<RepeatedTrash> { (**self).read_trash(trash_id) } fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<RepeatedTrash> {
(**self).read_trash(trash_id)
}
fn delete_trash(&self, trash_ids: Option<Vec<String>>) -> FlowyResult<()> { (**self).delete_trash(trash_ids) } fn delete_trash(&self, trash_ids: Option<Vec<String>>) -> FlowyResult<()> {
(**self).delete_trash(trash_ids)
}
} }

View File

@ -1,172 +0,0 @@
use crate::{
entities::{
app::{App, AppId, CreateAppParams, UpdateAppParams},
trash::{RepeatedTrash, RepeatedTrashId},
view::{CreateViewParams, RepeatedViewId, UpdateViewParams, View, ViewId},
workspace::{CreateWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams, Workspace, WorkspaceId},
},
errors::{ErrorCode, FlowyError},
notify::{send_dart_notification, WorkspaceNotification},
services::server::WorkspaceServerAPI,
};
use backend_service::{configuration::ClientServerConfiguration, http_request::*, middleware::*};
use lib_infra::future::FutureResult;
pub struct WorkspaceHttpServer {
config: ClientServerConfiguration,
}
impl WorkspaceHttpServer {
pub fn new(config: ClientServerConfiguration) -> WorkspaceHttpServer {
Self { config }
}
}
impl WorkspaceServerAPI for WorkspaceHttpServer {
fn init(&self) {
let mut rx = BACKEND_API_MIDDLEWARE.invalid_token_subscribe();
tokio::spawn(async move {
while let Ok(invalid_token) = rx.recv().await {
let error = FlowyError::new(ErrorCode::UserUnauthorized, "");
send_dart_notification(&invalid_token, WorkspaceNotification::UserUnauthorized)
.error(error)
.send()
}
});
}
fn create_workspace(&self, token: &str, params: CreateWorkspaceParams) -> FutureResult<Workspace, FlowyError> {
let token = token.to_owned();
let url = self.config.workspace_url();
FutureResult::new(async move {
let workspace = create_workspace_request(&token, params, &url).await?;
Ok(workspace)
})
}
fn read_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult<RepeatedWorkspace, FlowyError> {
let token = token.to_owned();
let url = self.config.workspace_url();
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) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.workspace_url();
FutureResult::new(async move {
let _ = update_workspace_request(&token, params, &url).await?;
Ok(())
})
}
fn delete_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.workspace_url();
FutureResult::new(async move {
let _ = delete_workspace_request(&token, params, &url).await?;
Ok(())
})
}
fn create_view(&self, token: &str, params: CreateViewParams) -> FutureResult<View, FlowyError> {
let token = token.to_owned();
let url = self.config.view_url();
FutureResult::new(async move {
let view = create_view_request(&token, params, &url).await?;
Ok(view)
})
}
fn read_view(&self, token: &str, params: ViewId) -> FutureResult<Option<View>, FlowyError> {
let token = token.to_owned();
let url = self.config.view_url();
FutureResult::new(async move {
let view = read_view_request(&token, params, &url).await?;
Ok(view)
})
}
fn delete_view(&self, token: &str, params: RepeatedViewId) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.view_url();
FutureResult::new(async move {
let _ = delete_view_request(&token, params, &url).await?;
Ok(())
})
}
fn update_view(&self, token: &str, params: UpdateViewParams) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.view_url();
FutureResult::new(async move {
let _ = update_view_request(&token, params, &url).await?;
Ok(())
})
}
fn create_app(&self, token: &str, params: CreateAppParams) -> FutureResult<App, FlowyError> {
let token = token.to_owned();
let url = self.config.app_url();
FutureResult::new(async move {
let app = create_app_request(&token, params, &url).await?;
Ok(app)
})
}
fn read_app(&self, token: &str, params: AppId) -> FutureResult<Option<App>, FlowyError> {
let token = token.to_owned();
let url = self.config.app_url();
FutureResult::new(async move {
let app = read_app_request(&token, params, &url).await?;
Ok(app)
})
}
fn update_app(&self, token: &str, params: UpdateAppParams) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.app_url();
FutureResult::new(async move {
let _ = update_app_request(&token, params, &url).await?;
Ok(())
})
}
fn delete_app(&self, token: &str, params: AppId) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.app_url();
FutureResult::new(async move {
let _ = delete_app_request(&token, params, &url).await?;
Ok(())
})
}
fn create_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.trash_url();
FutureResult::new(async move {
let _ = create_trash_request(&token, params, &url).await?;
Ok(())
})
}
fn delete_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.trash_url();
FutureResult::new(async move {
let _ = delete_trash_request(&token, params, &url).await?;
Ok(())
})
}
fn read_trash(&self, token: &str) -> FutureResult<RepeatedTrash, FlowyError> {
let token = token.to_owned();
let url = self.config.trash_url();
FutureResult::new(async move {
let repeated_trash = read_trash_request(&token, &url).await?;
Ok(repeated_trash)
})
}
}

View File

@ -119,9 +119,9 @@ impl TrashController {
let _ = self.notify.send(TrashEvent::Delete(trash_identifiers.clone(), tx)); let _ = self.notify.send(TrashEvent::Delete(trash_identifiers.clone(), tx));
match rx.recv().await { match rx.recv().await {
None => {}, None => {}
Some(result) => match result { Some(result) => match result {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("{}", e), Err(e) => log::error!("{}", e),
}, },
} }
@ -179,7 +179,9 @@ impl TrashController {
Ok(()) Ok(())
} }
pub fn subscribe(&self) -> broadcast::Receiver<TrashEvent> { self.notify.subscribe() } pub fn subscribe(&self) -> broadcast::Receiver<TrashEvent> {
self.notify.subscribe()
}
pub async fn read_trash(&self) -> Result<RepeatedTrash, FlowyError> { pub async fn read_trash(&self) -> Result<RepeatedTrash, FlowyError> {
let repeated_trash = self let repeated_trash = self
@ -213,7 +215,7 @@ impl TrashController {
// TODO: retry? // TODO: retry?
let _ = tokio::spawn(async move { let _ = tokio::spawn(async move {
match server.create_trash(&token, trash_identifiers).await { match server.create_trash(&token, trash_identifiers).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("Create trash failed: {:?}", e), Err(e) => log::error!("Create trash failed: {:?}", e),
} }
}); });
@ -227,7 +229,7 @@ impl TrashController {
let server = self.cloud_service.clone(); let server = self.cloud_service.clone();
let _ = tokio::spawn(async move { let _ = tokio::spawn(async move {
match server.delete_trash(&token, trash_identifiers).await { match server.delete_trash(&token, trash_identifiers).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("Delete trash failed: {:?}", e), Err(e) => log::error!("Delete trash failed: {:?}", e),
} }
}); });
@ -254,10 +256,10 @@ impl TrashController {
match result { match result {
Ok(repeated_trash) => { Ok(repeated_trash) => {
notify_trash_changed(repeated_trash); notify_trash_changed(repeated_trash);
}, }
Err(e) => log::error!("Save trash failed: {:?}", e), Err(e) => log::error!("Save trash failed: {:?}", e),
} }
}, }
Err(e) => log::error!("Read trash failed: {:?}", e), Err(e) => log::error!("Read trash failed: {:?}", e),
} }
}); });
@ -307,7 +309,7 @@ impl TrashEvent {
} else { } else {
Some(TrashEvent::Putback(identifiers, sender)) Some(TrashEvent::Putback(identifiers, sender))
} }
}, }
TrashEvent::Delete(mut identifiers, sender) => { TrashEvent::Delete(mut identifiers, sender) => {
identifiers.items.retain(|item| item.ty == s); identifiers.items.retain(|item| item.ty == s);
if identifiers.items.is_empty() { if identifiers.items.is_empty() {
@ -315,7 +317,7 @@ impl TrashEvent {
} else { } else {
Some(TrashEvent::Delete(identifiers, sender)) Some(TrashEvent::Delete(identifiers, sender))
} }
}, }
TrashEvent::NewTrash(mut identifiers, sender) => { TrashEvent::NewTrash(mut identifiers, sender) => {
identifiers.items.retain(|item| item.ty == s); identifiers.items.retain(|item| item.ty == s);
if identifiers.items.is_empty() { if identifiers.items.is_empty() {
@ -323,7 +325,7 @@ impl TrashEvent {
} else { } else {
Some(TrashEvent::NewTrash(identifiers, sender)) Some(TrashEvent::NewTrash(identifiers, sender))
} }
}, }
} }
} }
} }

View File

0
frontend/rust-lib/flowy-core/src/services/trash/mod.rs Normal file → Executable file
View File

View File

@ -18,8 +18,7 @@ use crate::{
module::{FolderCouldServiceV1, WorkspaceUser}, module::{FolderCouldServiceV1, WorkspaceUser},
services::{ services::{
persistence::{FolderPersistence, FolderPersistenceTransaction, ViewChangeset}, persistence::{FolderPersistence, FolderPersistenceTransaction, ViewChangeset},
TrashController, TrashController, TrashEvent,
TrashEvent,
}, },
}; };
use flowy_core_data_model::entities::share::{ExportData, ExportParams}; use flowy_core_data_model::entities::share::{ExportData, ExportParams};
@ -246,11 +245,13 @@ impl ViewController {
.begin_transaction(|transaction| transaction.read_view(&view_id)) .begin_transaction(|transaction| transaction.read_view(&view_id))
.await?; .await?;
Ok(Some(view)) Ok(Some(view))
}, }
} }
} }
pub(crate) fn set_latest_view(&self, view: &View) { KV::set_str(LATEST_VIEW_ID, view.id.clone()); } pub(crate) fn set_latest_view(&self, view: &View) {
KV::set_str(LATEST_VIEW_ID, view.id.clone());
}
} }
impl ViewController { impl ViewController {
@ -267,11 +268,11 @@ impl ViewController {
let server = self.cloud_service.clone(); let server = self.cloud_service.clone();
tokio::spawn(async move { tokio::spawn(async move {
match server.update_view(&token, params).await { match server.update_view(&token, params).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => { Err(e) => {
// TODO: retry? // TODO: retry?
log::error!("Update view failed: {:?}", e); log::error!("Update view failed: {:?}", e);
}, }
} }
}); });
Ok(()) Ok(())
@ -294,11 +295,11 @@ impl ViewController {
send_dart_notification(&view.id, WorkspaceNotification::ViewUpdated) send_dart_notification(&view.id, WorkspaceNotification::ViewUpdated)
.payload(view.clone()) .payload(view.clone())
.send(); .send();
}, }
Err(e) => log::error!("Save view failed: {:?}", e), Err(e) => log::error!("Save view failed: {:?}", e),
} }
}, }
Ok(None) => {}, Ok(None) => {}
Err(e) => log::error!("Read view failed: {:?}", e), Err(e) => log::error!("Read view failed: {:?}", e),
} }
}); });
@ -353,7 +354,7 @@ async fn handle_trash_event(
}) })
.await; .await;
let _ = ret.send(result).await; let _ = ret.send(result).await;
}, }
TrashEvent::Putback(identifiers, ret) => { TrashEvent::Putback(identifiers, ret) => {
let result = persistence let result = persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
@ -366,7 +367,7 @@ async fn handle_trash_event(
}) })
.await; .await;
let _ = ret.send(result).await; let _ = ret.send(result).await;
}, }
TrashEvent::Delete(identifiers, ret) => { TrashEvent::Delete(identifiers, ret) => {
let result = persistence let result = persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
@ -386,7 +387,7 @@ async fn handle_trash_event(
}) })
.await; .await;
let _ = ret.send(result).await; let _ = ret.send(result).await;
}, }
} }
} }
@ -414,7 +415,7 @@ fn notify_views_changed<'a>(
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let repeated_view = read_belonging_views_on_local(belong_to_id, trash_controller.clone(), transaction)?; let repeated_view = read_belonging_views_on_local(belong_to_id, trash_controller.clone(), transaction)?;
tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str()); tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str());
send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged) send_dart_notification(belong_to_id, WorkspaceNotification::AppViewsChanged)
.payload(repeated_view) .payload(repeated_view)
.send(); .send();
Ok(()) Ok(())

View File

0
frontend/rust-lib/flowy-core/src/services/view/mod.rs Normal file → Executable file
View File

View File

View File

@ -4,8 +4,7 @@ use crate::{
module::{FolderCouldServiceV1, WorkspaceUser}, module::{FolderCouldServiceV1, WorkspaceUser},
services::{ services::{
persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset}, persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset},
read_local_workspace_apps, read_local_workspace_apps, TrashController,
TrashController,
}, },
}; };
use flowy_core_data_model::entities::{app::RepeatedApp, workspace::*}; use flowy_core_data_model::entities::{app::RepeatedApp, workspace::*};
@ -105,7 +104,7 @@ impl WorkspaceController {
set_current_workspace(&workspace.id); set_current_workspace(&workspace.id);
Ok(workspace) Ok(workspace)
} else { } else {
return Err(FlowyError::workspace_id().context("Opened workspace id should not be empty")); Err(FlowyError::workspace_id().context("Opened workspace id should not be empty"))
} }
} }
@ -162,11 +161,11 @@ impl WorkspaceController {
let (token, server) = (self.user.token()?, self.cloud_service.clone()); let (token, server) = (self.user.token()?, self.cloud_service.clone());
tokio::spawn(async move { tokio::spawn(async move {
match server.update_workspace(&token, params).await { match server.update_workspace(&token, params).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => { Err(e) => {
// TODO: retry? // TODO: retry?
log::error!("Update workspace failed: {:?}", e); log::error!("Update workspace failed: {:?}", e);
}, }
} }
}); });
Ok(()) Ok(())
@ -180,11 +179,11 @@ impl WorkspaceController {
let (token, server) = (self.user.token()?, self.cloud_service.clone()); let (token, server) = (self.user.token()?, self.cloud_service.clone());
tokio::spawn(async move { tokio::spawn(async move {
match server.delete_workspace(&token, params).await { match server.delete_workspace(&token, params).await {
Ok(_) => {}, Ok(_) => {}
Err(e) => { Err(e) => {
// TODO: retry? // TODO: retry?
log::error!("Delete workspace failed: {:?}", e); log::error!("Delete workspace failed: {:?}", e);
}, }
} }
}); });
Ok(()) Ok(())
@ -193,14 +192,16 @@ impl WorkspaceController {
const CURRENT_WORKSPACE_ID: &str = "current_workspace_id"; const CURRENT_WORKSPACE_ID: &str = "current_workspace_id";
pub fn set_current_workspace(workspace_id: &str) { KV::set_str(CURRENT_WORKSPACE_ID, workspace_id.to_owned()); } pub fn set_current_workspace(workspace_id: &str) {
KV::set_str(CURRENT_WORKSPACE_ID, workspace_id.to_owned());
}
pub fn get_current_workspace() -> Result<String, FlowyError> { pub fn get_current_workspace() -> Result<String, FlowyError> {
match KV::get_str(CURRENT_WORKSPACE_ID) { match KV::get_str(CURRENT_WORKSPACE_ID) {
None => { None => {
Err(FlowyError::record_not_found() Err(FlowyError::record_not_found()
.context("Current workspace not found or should call open workspace first")) .context("Current workspace not found or should call open workspace first"))
}, }
Some(workspace_id) => Ok(workspace_id), Some(workspace_id) => Ok(workspace_id),
} }
} }

View File

@ -116,14 +116,14 @@ fn read_workspaces_on_server(
for app in apps { for app in apps {
let views = app.belongings.clone().into_inner(); let views = app.belongings.clone().into_inner();
match transaction.create_app(app) { match transaction.create_app(app) {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("create app failed: {:?}", e), Err(e) => log::error!("create app failed: {:?}", e),
} }
tracing::debug!("Save {} views", views.len()); tracing::debug!("Save {} views", views.len());
for view in views { for view in views {
match transaction.create_view(view) { match transaction.create_view(view) {
Ok(_) => {}, Ok(_) => {}
Err(e) => log::error!("create view failed: {:?}", e), Err(e) => log::error!("create view failed: {:?}", e),
} }
} }

View File

0
frontend/rust-lib/flowy-core/src/util.rs Normal file → Executable file
View File

View File

0
frontend/rust-lib/flowy-core/tests/workspace/helper.rs Normal file → Executable file
View File

0
frontend/rust-lib/flowy-core/tests/workspace/main.rs Normal file → Executable file
View File

80
frontend/rust-lib/flowy-core/tests/workspace/script.rs Normal file → Executable file
View File

@ -103,11 +103,11 @@ impl FolderTest {
FolderScript::ReadAllWorkspaces => { FolderScript::ReadAllWorkspaces => {
let all_workspace = read_workspace(sdk, None).await; let all_workspace = read_workspace(sdk, None).await;
self.all_workspace = all_workspace; self.all_workspace = all_workspace;
}, }
FolderScript::CreateWorkspace { name, desc } => { FolderScript::CreateWorkspace { name, desc } => {
let workspace = create_workspace(sdk, &name, &desc).await; let workspace = create_workspace(sdk, &name, &desc).await;
self.workspace = workspace; self.workspace = workspace;
}, }
FolderScript::AssertWorkspaceJson(expected_json) => { FolderScript::AssertWorkspaceJson(expected_json) => {
let workspace = read_workspace(sdk, Some(self.workspace.id.clone())) let workspace = read_workspace(sdk, Some(self.workspace.id.clone()))
.await .await
@ -115,74 +115,74 @@ impl FolderTest {
.unwrap(); .unwrap();
let json = serde_json::to_string(&workspace).unwrap(); let json = serde_json::to_string(&workspace).unwrap();
assert_eq!(json, expected_json); assert_eq!(json, expected_json);
}, }
FolderScript::AssertWorkspace(workspace) => { FolderScript::AssertWorkspace(workspace) => {
assert_eq!(self.workspace, workspace); assert_eq!(self.workspace, workspace);
}, }
FolderScript::ReadWorkspace(workspace_id) => { FolderScript::ReadWorkspace(workspace_id) => {
let workspace = read_workspace(sdk, workspace_id).await.pop().unwrap(); let workspace = read_workspace(sdk, workspace_id).await.pop().unwrap();
self.workspace = workspace; self.workspace = workspace;
}, }
FolderScript::CreateApp { name, desc } => { FolderScript::CreateApp { name, desc } => {
let app = create_app(&sdk, &self.workspace.id, name, desc).await; let app = create_app(sdk, &self.workspace.id, name, desc).await;
self.app = app; self.app = app;
}, }
FolderScript::AssertAppJson(expected_json) => { FolderScript::AssertAppJson(expected_json) => {
let json = serde_json::to_string(&self.app).unwrap(); let json = serde_json::to_string(&self.app).unwrap();
assert_eq!(json, expected_json); assert_eq!(json, expected_json);
}, }
FolderScript::AssertApp(app) => { FolderScript::AssertApp(app) => {
assert_eq!(self.app, app); assert_eq!(self.app, app);
}, }
FolderScript::ReadApp(app_id) => { FolderScript::ReadApp(app_id) => {
let app = read_app(&sdk, &app_id).await; let app = read_app(sdk, &app_id).await;
self.app = app; self.app = app;
}, }
FolderScript::UpdateApp { name, desc } => { FolderScript::UpdateApp { name, desc } => {
update_app(&sdk, &self.app.id, name, desc).await; update_app(sdk, &self.app.id, name, desc).await;
}, }
FolderScript::DeleteApp => { FolderScript::DeleteApp => {
delete_app(&sdk, &self.app.id).await; delete_app(sdk, &self.app.id).await;
}, }
FolderScript::CreateView { name, desc } => { FolderScript::CreateView { name, desc } => {
let view = create_view(&sdk, &self.app.id, name, desc, ViewType::Doc).await; let view = create_view(sdk, &self.app.id, name, desc, ViewType::Doc).await;
self.view = view; self.view = view;
}, }
FolderScript::AssertView(view) => { FolderScript::AssertView(view) => {
assert_eq!(self.view, view); assert_eq!(self.view, view);
}, }
FolderScript::ReadView(view_id) => { FolderScript::ReadView(view_id) => {
let view = read_view(&sdk, vec![view_id]).await; let view = read_view(sdk, vec![view_id]).await;
self.view = view; self.view = view;
}, }
FolderScript::UpdateView { name, desc } => { FolderScript::UpdateView { name, desc } => {
update_view(&sdk, &self.view.id, name, desc).await; update_view(sdk, &self.view.id, name, desc).await;
}, }
FolderScript::DeleteView => { FolderScript::DeleteView => {
delete_view(&sdk, vec![self.view.id.clone()]).await; delete_view(sdk, vec![self.view.id.clone()]).await;
}, }
FolderScript::DeleteViews(view_ids) => { FolderScript::DeleteViews(view_ids) => {
delete_view(&sdk, view_ids).await; delete_view(sdk, view_ids).await;
}, }
FolderScript::RestoreAppFromTrash => { FolderScript::RestoreAppFromTrash => {
restore_app_from_trash(&sdk, &self.app.id).await; restore_app_from_trash(sdk, &self.app.id).await;
}, }
FolderScript::RestoreViewFromTrash => { FolderScript::RestoreViewFromTrash => {
restore_view_from_trash(&sdk, &self.view.id).await; restore_view_from_trash(sdk, &self.view.id).await;
}, }
FolderScript::ReadTrash => { FolderScript::ReadTrash => {
let trash = read_trash(&sdk).await; let trash = read_trash(sdk).await;
self.trash = trash.into_inner(); self.trash = trash.into_inner();
}, }
FolderScript::DeleteAllTrash => { FolderScript::DeleteAllTrash => {
delete_all_trash(&sdk).await; delete_all_trash(sdk).await;
self.trash = vec![]; self.trash = vec![];
}, }
FolderScript::OpenDocument => { FolderScript::OpenDocument => {
let document_info = open_document(&sdk, &self.view.id).await; let document_info = open_document(sdk, &self.view.id).await;
self.document_info = Some(document_info); self.document_info = Some(document_info);
}, }
FolderScript::AssertRevisionState { rev_id, state } => { FolderScript::AssertRevisionState { rev_id, state } => {
let record = cache.get(rev_id).await.unwrap(); let record = cache.get(rev_id).await.unwrap();
assert_eq!(record.state, state); assert_eq!(record.state, state);
@ -191,21 +191,21 @@ impl FolderTest {
// Make sure everything is written. // Make sure everything is written.
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
} }
}, }
FolderScript::AssertCurrentRevId(rev_id) => { FolderScript::AssertCurrentRevId(rev_id) => {
assert_eq!(rev_manager.rev_id(), rev_id); assert_eq!(rev_manager.rev_id(), rev_id);
}, }
FolderScript::AssertNextSyncRevId(rev_id) => { FolderScript::AssertNextSyncRevId(rev_id) => {
let next_revision = rev_manager.next_sync_revision().await.unwrap(); let next_revision = rev_manager.next_sync_revision().await.unwrap();
if rev_id.is_none() { if rev_id.is_none() {
assert_eq!(next_revision.is_none(), true, "Next revision should be None"); assert!(next_revision.is_none(), "Next revision should be None");
return; return;
} }
let next_revision = next_revision.unwrap(); let next_revision = next_revision.unwrap();
let mut receiver = rev_manager.revision_ack_receiver(); let mut receiver = rev_manager.revision_ack_receiver();
let _ = receiver.recv().await; let _ = receiver.recv().await;
assert_eq!(next_revision.rev_id, rev_id.unwrap()); assert_eq!(next_revision.rev_id, rev_id.unwrap());
}, }
} }
} }
} }

0
frontend/rust-lib/flowy-database/.env Normal file → Executable file
View File

0
frontend/rust-lib/flowy-database/Cargo.toml Normal file → Executable file
View File

0
frontend/rust-lib/flowy-database/diesel.toml Normal file → Executable file
View File

0
frontend/rust-lib/flowy-database/migrations/.gitkeep Normal file → Executable file
View File

2
frontend/rust-lib/flowy-database/src/kv/kv.rs Normal file → Executable file
View File

@ -216,7 +216,7 @@ mod tests {
assert_eq!(KV::get_str("2"), None); assert_eq!(KV::get_str("2"), None);
KV::set_bool("1", true); KV::set_bool("1", true);
assert_eq!(KV::get_bool("1").unwrap(), true); assert!(KV::get_bool("1").unwrap());
assert_eq!(KV::get_bool("2"), None); assert_eq!(KV::get_bool("2"), None);
} }

Some files were not shown because too many files have changed in this diff Show More