mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: integrate grid into flowy-sdk
This commit is contained in:
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -1052,6 +1052,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"dart-notify",
|
||||
"dashmap",
|
||||
"diesel",
|
||||
"flowy-collaboration",
|
||||
"flowy-database",
|
||||
|
@ -32,11 +32,11 @@ impl BlockManager {
|
||||
block_user: Arc<dyn BlockUser>,
|
||||
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
) -> Self {
|
||||
let block_handlers = Arc::new(BlockEditors::new());
|
||||
let block_editors = Arc::new(BlockEditors::new());
|
||||
Self {
|
||||
cloud_service,
|
||||
rev_web_socket,
|
||||
block_editors: block_handlers,
|
||||
block_editors,
|
||||
block_user,
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ chrono = "0.4.19"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
bytes = { version = "1.0" }
|
||||
diesel = {version = "1.4.8", features = ["sqlite"]}
|
||||
#diesel_derives = {version = "1.4.1", features = ["sqlite"]}
|
||||
dashmap = "4.0"
|
||||
|
||||
|
||||
parking_lot = "0.11"
|
||||
|
@ -1 +0,0 @@
|
||||
pub struct GridManager {}
|
@ -1,4 +1,4 @@
|
||||
use crate::controller::GridManager;
|
||||
use crate::manager::GridManager;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_grid_data_model::entities::{
|
||||
CreateGridPayload, Grid, GridId, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::controller::GridManager;
|
||||
use crate::event_handler::*;
|
||||
use crate::manager::GridManager;
|
||||
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||
use lib_dispatch::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod controller;
|
||||
mod event_handler;
|
||||
mod event_map;
|
||||
pub mod event_map;
|
||||
pub mod manager;
|
||||
|
||||
mod protobuf;
|
||||
mod services;
|
||||
|
107
frontend/rust-lib/flowy-grid/src/manager.rs
Normal file
107
frontend/rust-lib/flowy-grid/src/manager.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use crate::services::grid_editor::ClientGridEditor;
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
|
||||
use lib_sqlite::ConnectionPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait GridUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<String, FlowyError>;
|
||||
fn token(&self) -> Result<String, FlowyError>;
|
||||
fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct GridManager {
|
||||
grid_editors: Arc<GridEditors>,
|
||||
grid_user: Arc<dyn GridUser>,
|
||||
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
}
|
||||
|
||||
impl GridManager {
|
||||
pub fn new(grid_user: Arc<dyn GridUser>, rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
|
||||
let grid_editors = Arc::new(GridEditors::new());
|
||||
Self {
|
||||
grid_editors,
|
||||
grid_user,
|
||||
rev_web_socket,
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(grid_id), err)]
|
||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.get_grid_editor(grid_id).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self, grid_id), fields(grid_id), err)]
|
||||
pub fn close_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.grid_editors.remove(grid_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)]
|
||||
pub fn delete_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.grid_editors.remove(grid_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
||||
match self.grid_editors.get(grid_id) {
|
||||
None => {
|
||||
let db_pool = self.grid_user.db_pool()?;
|
||||
self.make_grid_editor(grid_id, db_pool).await
|
||||
}
|
||||
Some(editor) => Ok(editor),
|
||||
}
|
||||
}
|
||||
|
||||
async fn make_grid_editor(
|
||||
&self,
|
||||
grid_id: &str,
|
||||
pool: Arc<ConnectionPool>,
|
||||
) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
||||
let token = self.grid_user.token()?;
|
||||
let user_id = self.grid_user.user_id()?;
|
||||
let grid_editor = ClientGridEditor::new(&user_id, grid_id, &token, pool, self.rev_web_socket.clone()).await?;
|
||||
self.grid_editors.insert(grid_id, &grid_editor);
|
||||
Ok(grid_editor)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GridEditors {
|
||||
inner: DashMap<String, Arc<ClientGridEditor>>,
|
||||
}
|
||||
|
||||
impl GridEditors {
|
||||
fn new() -> Self {
|
||||
Self { inner: DashMap::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&self, grid_id: &str, grid_editor: &Arc<ClientGridEditor>) {
|
||||
if self.inner.contains_key(grid_id) {
|
||||
tracing::warn!("Grid:{} already exists in cache", grid_id);
|
||||
}
|
||||
self.inner.insert(grid_id.to_string(), grid_editor.clone());
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, grid_id: &str) -> bool {
|
||||
self.inner.get(grid_id).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, grid_id: &str) -> Option<Arc<ClientGridEditor>> {
|
||||
if !self.contains(grid_id) {
|
||||
return None;
|
||||
}
|
||||
let opened_grid = self.inner.get(grid_id).unwrap();
|
||||
Some(opened_grid.clone())
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&self, grid_id: &str) {
|
||||
self.inner.remove(grid_id);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ use std::sync::Arc;
|
||||
|
||||
pub struct ClientGridEditor {
|
||||
user_id: String,
|
||||
grid_id: GridId,
|
||||
grid_id: String,
|
||||
grid: Arc<RwLock<GridPad>>,
|
||||
rev_manager: Arc<RevisionManager>,
|
||||
kv: Arc<GridKVPersistence>,
|
||||
@ -25,13 +25,13 @@ pub struct ClientGridEditor {
|
||||
impl ClientGridEditor {
|
||||
pub async fn new(
|
||||
user_id: &str,
|
||||
grid_id: &GridId,
|
||||
grid_id: &str,
|
||||
token: &str,
|
||||
pool: Arc<ConnectionPool>,
|
||||
_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
) -> FlowyResult<Self> {
|
||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, grid_id.as_ref(), pool.clone()));
|
||||
let mut rev_manager = RevisionManager::new(user_id, grid_id.as_ref(), rev_persistence);
|
||||
) -> FlowyResult<Arc<Self>> {
|
||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, grid_id, pool.clone()));
|
||||
let mut rev_manager = RevisionManager::new(user_id, grid_id, rev_persistence);
|
||||
let cloud = Arc::new(GridRevisionCloudService {
|
||||
token: token.to_string(),
|
||||
});
|
||||
@ -43,13 +43,13 @@ impl ClientGridEditor {
|
||||
|
||||
let user_id = user_id.to_owned();
|
||||
let grid_id = grid_id.to_owned();
|
||||
Ok(Self {
|
||||
Ok(Arc::new(Self {
|
||||
user_id,
|
||||
grid_id,
|
||||
grid,
|
||||
rev_manager,
|
||||
kv,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
||||
|
@ -122,6 +122,9 @@ impl LocalWebSocketRunner {
|
||||
let _ = self.handle_folder_client_data(client_data, "".to_owned()).await?;
|
||||
Ok(())
|
||||
}
|
||||
WSChannel::Grid => {
|
||||
todo!("Implement grid web socket channel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,13 @@ impl BlockDepsResolver {
|
||||
server_config: &ClientServerConfiguration,
|
||||
) -> Arc<BlockManager> {
|
||||
let user = Arc::new(BlockUserImpl(user_session));
|
||||
let ws_sender = Arc::new(BlockWebSocket(ws_conn.clone()));
|
||||
let rev_web_socket = Arc::new(BlockWebSocket(ws_conn.clone()));
|
||||
let cloud_service: Arc<dyn BlockCloudService> = match local_server {
|
||||
None => Arc::new(BlockHttpCloudService::new(server_config.clone())),
|
||||
Some(local_server) => local_server,
|
||||
};
|
||||
|
||||
let manager = Arc::new(BlockManager::new(cloud_service, user, ws_sender));
|
||||
let manager = Arc::new(BlockManager::new(cloud_service, user, rev_web_socket));
|
||||
let receiver = Arc::new(DocumentWSMessageReceiverImpl(manager.clone()));
|
||||
ws_conn.add_ws_message_receiver(receiver).unwrap();
|
||||
|
||||
|
66
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs
Normal file
66
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::FlowyError;
|
||||
use bytes::Bytes;
|
||||
use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
|
||||
use flowy_database::ConnectionPool;
|
||||
use flowy_grid::manager::{GridManager, GridUser};
|
||||
use flowy_net::ws::connection::FlowyWebSocketConnect;
|
||||
use flowy_sync::{RevisionWebSocket, WSStateReceiver};
|
||||
use flowy_user::services::UserSession;
|
||||
use futures_core::future::BoxFuture;
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
use lib_ws::{WSChannel, WebSocketRawMessage};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct GridDepsResolver();
|
||||
|
||||
impl GridDepsResolver {
|
||||
pub fn resolve(ws_conn: Arc<FlowyWebSocketConnect>, user_session: Arc<UserSession>) -> Arc<GridManager> {
|
||||
let user = Arc::new(GridUserImpl(user_session));
|
||||
let rev_web_socket = Arc::new(GridWebSocket(ws_conn.clone()));
|
||||
let manager = Arc::new(GridManager::new(user, rev_web_socket));
|
||||
manager
|
||||
}
|
||||
}
|
||||
|
||||
struct GridUserImpl(Arc<UserSession>);
|
||||
impl GridUser for GridUserImpl {
|
||||
fn user_id(&self) -> Result<String, FlowyError> {
|
||||
self.0.user_id()
|
||||
}
|
||||
|
||||
fn token(&self) -> Result<String, FlowyError> {
|
||||
self.0.token()
|
||||
}
|
||||
|
||||
fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError> {
|
||||
self.0.db_pool()
|
||||
}
|
||||
}
|
||||
|
||||
struct GridWebSocket(Arc<FlowyWebSocketConnect>);
|
||||
impl RevisionWebSocket for GridWebSocket {
|
||||
fn send(&self, data: ClientRevisionWSData) -> BoxResultFuture<(), FlowyError> {
|
||||
let bytes: Bytes = data.try_into().unwrap();
|
||||
let msg = WebSocketRawMessage {
|
||||
channel: WSChannel::Grid,
|
||||
data: bytes.to_vec(),
|
||||
};
|
||||
|
||||
let ws_conn = self.0.clone();
|
||||
Box::pin(async move {
|
||||
match ws_conn.web_socket().await? {
|
||||
None => {}
|
||||
Some(sender) => {
|
||||
sender.send(msg).map_err(|e| FlowyError::internal().context(e))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn subscribe_state_changed(&self) -> BoxFuture<WSStateReceiver> {
|
||||
let ws_conn = self.0.clone();
|
||||
Box::pin(async move { ws_conn.subscribe_websocket_state().await })
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
mod block_deps;
|
||||
mod folder_deps;
|
||||
mod grid_deps;
|
||||
mod user_deps;
|
||||
mod util;
|
||||
|
||||
pub use block_deps::*;
|
||||
pub use folder_deps::*;
|
||||
pub use grid_deps::*;
|
||||
pub use user_deps::*;
|
||||
|
@ -5,6 +5,7 @@ pub use flowy_net::get_client_server_configuration;
|
||||
use crate::deps_resolve::*;
|
||||
use flowy_block::BlockManager;
|
||||
use flowy_folder::{controller::FolderManager, errors::FlowyError};
|
||||
use flowy_grid::manager::GridManager;
|
||||
use flowy_net::ClientServerConfiguration;
|
||||
use flowy_net::{
|
||||
entities::NetworkType,
|
||||
@ -88,6 +89,7 @@ pub struct FlowySDK {
|
||||
pub user_session: Arc<UserSession>,
|
||||
pub document_manager: Arc<BlockManager>,
|
||||
pub folder_manager: Arc<FolderManager>,
|
||||
pub grid_manager: Arc<GridManager>,
|
||||
pub dispatcher: Arc<EventDispatcher>,
|
||||
pub ws_conn: Arc<FlowyWebSocketConnect>,
|
||||
pub local_server: Option<Arc<LocalServer>>,
|
||||
@ -100,7 +102,7 @@ impl FlowySDK {
|
||||
tracing::debug!("🔥 {:?}", config);
|
||||
let runtime = tokio_default_runtime().unwrap();
|
||||
let (local_server, ws_conn) = mk_local_server(&config.server_config);
|
||||
let (user_session, document_manager, folder_manager, local_server) = runtime.block_on(async {
|
||||
let (user_session, document_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
|
||||
let user_session = mk_user_session(&config, &local_server, &config.server_config);
|
||||
let document_manager = BlockDepsResolver::resolve(
|
||||
local_server.clone(),
|
||||
@ -118,15 +120,23 @@ impl FlowySDK {
|
||||
)
|
||||
.await;
|
||||
|
||||
let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone());
|
||||
|
||||
if let Some(local_server) = local_server.as_ref() {
|
||||
local_server.run();
|
||||
}
|
||||
ws_conn.init().await;
|
||||
(user_session, document_manager, folder_manager, local_server)
|
||||
(
|
||||
user_session,
|
||||
document_manager,
|
||||
folder_manager,
|
||||
local_server,
|
||||
grid_manager,
|
||||
)
|
||||
});
|
||||
|
||||
let dispatcher = Arc::new(EventDispatcher::construct(runtime, || {
|
||||
mk_modules(&ws_conn, &folder_manager, &user_session)
|
||||
mk_modules(&ws_conn, &folder_manager, &grid_manager, &user_session)
|
||||
}));
|
||||
|
||||
_start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager);
|
||||
@ -136,6 +146,7 @@ impl FlowySDK {
|
||||
user_session,
|
||||
document_manager,
|
||||
folder_manager,
|
||||
grid_manager,
|
||||
dispatcher,
|
||||
ws_conn,
|
||||
local_server,
|
||||
|
@ -1,4 +1,5 @@
|
||||
use flowy_folder::controller::FolderManager;
|
||||
use flowy_grid::manager::GridManager;
|
||||
use flowy_net::ws::connection::FlowyWebSocketConnect;
|
||||
use flowy_user::services::UserSession;
|
||||
use lib_dispatch::prelude::Module;
|
||||
@ -7,22 +8,28 @@ use std::sync::Arc;
|
||||
pub fn mk_modules(
|
||||
ws_conn: &Arc<FlowyWebSocketConnect>,
|
||||
folder_manager: &Arc<FolderManager>,
|
||||
grid_manager: &Arc<GridManager>,
|
||||
user_session: &Arc<UserSession>,
|
||||
) -> Vec<Module> {
|
||||
let user_module = mk_user_module(user_session.clone());
|
||||
let folder_module = mk_folder_module(folder_manager.clone());
|
||||
let network_module = mk_network_module(ws_conn.clone());
|
||||
vec![user_module, folder_module, network_module]
|
||||
let grid_module = mk_grid_module(grid_manager.clone());
|
||||
vec![user_module, folder_module, network_module, grid_module]
|
||||
}
|
||||
|
||||
fn mk_user_module(user_session: Arc<UserSession>) -> Module {
|
||||
flowy_user::event_map::create(user_session)
|
||||
}
|
||||
|
||||
fn mk_folder_module(core: Arc<FolderManager>) -> Module {
|
||||
flowy_folder::event_map::create(core)
|
||||
fn mk_folder_module(folder_manager: Arc<FolderManager>) -> Module {
|
||||
flowy_folder::event_map::create(folder_manager)
|
||||
}
|
||||
|
||||
fn mk_network_module(ws_conn: Arc<FlowyWebSocketConnect>) -> Module {
|
||||
flowy_net::event_map::create(ws_conn)
|
||||
}
|
||||
|
||||
fn mk_grid_module(grid_manager: Arc<GridManager>) -> Module {
|
||||
flowy_grid::event_map::create(grid_manager)
|
||||
}
|
||||
|
Reference in New Issue
Block a user