chore: impl view data processor

This commit is contained in:
appflowy 2022-03-06 09:03:02 +08:00
parent 1b80934899
commit 264166fa29
20 changed files with 305 additions and 185 deletions

View File

@ -85,10 +85,10 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
});
listener.start();
final result = await service.openDocument(docId: view.id);
final result = await service.openDocument(docId: view.id, dataType: view.dataType);
result.fold(
(block) {
document = _decodeJsonToDocument(block.deltaJson);
document = _decodeJsonToDocument(block.deltaStr);
_subscription = document.changes.listen((event) {
final delta = event.item2;
final documentDelta = document.toDelta();
@ -115,7 +115,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
result.fold((rustDoc) {
// final json = utf8.decode(doc.data);
final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaJson));
final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaStr));
if (documentDelta != rustDelta) {
Log.error("Receive : $rustDelta");
Log.error("Expected : $documentDelta");

View File

@ -5,7 +5,10 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
class DocumentService {
Future<Either<BlockDelta, FlowyError>> openDocument({required String docId}) {
Future<Either<BlockDelta, FlowyError>> openDocument({
required String docId,
required ViewDataType dataType,
}) {
final request = ViewId(value: docId);
return FolderEventOpenView(request).send();
}
@ -13,7 +16,7 @@ class DocumentService {
Future<Either<BlockDelta, FlowyError>> composeDelta({required String docId, required String data}) {
final request = BlockDelta.create()
..blockId = docId
..deltaJson = data;
..deltaStr = data;
return FolderEventApplyDocDelta(request).send();
}

View File

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'src/grid_page.dart';
class GridPluginBuilder extends PluginBuilder {
class GridPluginBuilder implements PluginBuilder {
@override
Plugin build(dynamic data) {
if (data is View) {
@ -21,6 +21,9 @@ class GridPluginBuilder extends PluginBuilder {
@override
PluginType get pluginType => DefaultPlugin.grid.type();
@override
ViewDataType get dataType => ViewDataType.Grid;
}
class GridPluginConfig implements PluginConfig {

View File

@ -986,13 +986,13 @@ dependencies = [
name = "flowy-folder"
version = "0.1.0"
dependencies = [
"async-trait",
"bincode",
"bytes",
"chrono",
"crossbeam",
"crossbeam-utils",
"dart-notify",
"dashmap",
"derive_more",
"diesel",
"diesel_derives",
@ -1134,7 +1134,6 @@ dependencies = [
name = "flowy-sdk"
version = "0.1.0"
dependencies = [
"async-trait",
"bincode",
"bytes",
"claim 0.5.0",

View File

@ -42,7 +42,7 @@ bytes = { version = "1.0" }
crossbeam = "0.8"
crossbeam-utils = "0.8"
chrono = "0.4"
async-trait = "0.1.52"
dashmap = "4.0"
[dev-dependencies]
serial_test = "0.5.1"

View File

@ -8,17 +8,18 @@ use crate::{
TrashController, ViewController, WorkspaceController,
},
};
use async_trait::async_trait;
use bytes::Bytes;
use chrono::Utc;
use flowy_block::BlockManager;
use flowy_collaboration::client_document::default::{initial_quill_delta, initial_quill_delta_string, initial_read_me};
use flowy_collaboration::entities::revision::{RepeatedRevision, Revision};
use flowy_collaboration::client_document::default::{initial_quill_delta_string, initial_read_me};
use flowy_collaboration::entities::revision::RepeatedRevision;
use flowy_collaboration::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData};
use flowy_error::FlowyError;
use flowy_folder_data_model::entities::view::ViewDataType;
use flowy_folder_data_model::user_default;
use flowy_sync::RevisionWebSocket;
use lazy_static::lazy_static;
use lib_infra::future::FutureResult;
use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc};
use tokio::sync::RwLock as TokioRwLock;
lazy_static! {
@ -62,6 +63,7 @@ pub struct FolderManager {
pub(crate) trash_controller: Arc<TrashController>,
web_socket: Arc<dyn RevisionWebSocket>,
folder_editor: Arc<TokioRwLock<Option<Arc<ClientFolderEditor>>>>,
data_processors: ViewDataProcessorMap,
}
impl FolderManager {
@ -69,8 +71,7 @@ impl FolderManager {
user: Arc<dyn WorkspaceUser>,
cloud_service: Arc<dyn FolderCouldServiceV1>,
database: Arc<dyn WorkspaceDatabase>,
data_processors: DataProcessorMap,
block_manager: Arc<BlockManager>,
data_processors: ViewDataProcessorMap,
web_socket: Arc<dyn RevisionWebSocket>,
) -> Self {
if let Ok(user_id) = user.user_id() {
@ -93,8 +94,7 @@ impl FolderManager {
persistence.clone(),
cloud_service.clone(),
trash_controller.clone(),
data_processors,
block_manager,
data_processors.clone(),
));
let app_controller = Arc::new(AppController::new(
@ -121,6 +121,7 @@ impl FolderManager {
trash_controller,
web_socket,
folder_editor,
data_processors,
}
}
@ -167,6 +168,11 @@ impl FolderManager {
let _ = self.app_controller.initialize()?;
let _ = self.view_controller.initialize()?;
self.data_processors.iter().for_each(|(_, processor)| {
processor.initialize();
});
write_guard.insert(user_id.to_owned(), true);
Ok(())
}
@ -201,7 +207,9 @@ impl DefaultFolderBuilder {
initial_quill_delta_string()
};
view_controller.set_latest_view(view);
let _ = view_controller.create_view(&view.id, Bytes::from(view_data)).await?;
let _ = view_controller
.create_view(&view.id, ViewDataType::RichText, Bytes::from(view_data))
.await?;
}
}
let folder = FolderPad::new(vec![workspace.clone()], vec![])?;
@ -222,13 +230,20 @@ impl FolderManager {
}
}
#[async_trait]
pub trait ViewDataProcessor {
async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()>;
async fn delete_container(&self, view_id: &str) -> FlowyResult<()>;
async fn close_container(&self, view_id: &str) -> FlowyResult<()>;
async fn delta_str(&self, view_id: &str) -> FlowyResult<String>;
fn initialize(&self) -> FutureResult<(), FlowyError>;
fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError>;
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError>;
fn default_view_data(&self) -> String;
fn data_type(&self) -> ViewDataType;
}
pub type DataProcessorMap = Arc<HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>>>;
pub type ViewDataProcessorMap = Arc<HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>>>;

View File

@ -1,15 +1,4 @@
use bytes::Bytes;
use flowy_collaboration::entities::{
document_info::{BlockDelta, BlockId},
revision::{RepeatedRevision, Revision},
};
use flowy_collaboration::client_document::default::initial_quill_delta_string;
use futures::{FutureExt, StreamExt};
use std::collections::HashMap;
use std::{collections::HashSet, sync::Arc};
use crate::manager::DataProcessorMap;
use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
use crate::{
dart_notification::{send_dart_notification, FolderNotification},
entities::{
@ -23,10 +12,16 @@ use crate::{
TrashController, TrashEvent,
},
};
use flowy_block::BlockManager;
use bytes::Bytes;
use flowy_collaboration::entities::{
document_info::{BlockDelta, BlockId},
revision::{RepeatedRevision, Revision},
};
use flowy_database::kv::KV;
use flowy_folder_data_model::entities::view::ViewDataType;
use futures::{FutureExt, StreamExt};
use lib_infra::uuid;
use std::{collections::HashSet, sync::Arc};
const LATEST_VIEW_ID: &str = "latest_view_id";
@ -35,8 +30,7 @@ pub(crate) struct ViewController {
cloud_service: Arc<dyn FolderCouldServiceV1>,
persistence: Arc<FolderPersistence>,
trash_controller: Arc<TrashController>,
data_processors: DataProcessorMap,
block_manager: Arc<BlockManager>,
data_processors: ViewDataProcessorMap,
}
impl ViewController {
@ -45,8 +39,7 @@ impl ViewController {
persistence: Arc<FolderPersistence>,
cloud_service: Arc<dyn FolderCouldServiceV1>,
trash_controller: Arc<TrashController>,
data_processors: DataProcessorMap,
block_manager: Arc<BlockManager>,
data_processors: ViewDataProcessorMap,
) -> Self {
Self {
user,
@ -54,38 +47,48 @@ impl ViewController {
persistence,
trash_controller,
data_processors,
block_manager,
}
}
pub(crate) fn initialize(&self) -> Result<(), FlowyError> {
let _ = self.block_manager.init()?;
self.listen_trash_can_event();
Ok(())
}
#[tracing::instrument(level = "trace", skip(self, params), fields(name = %params.name), err)]
pub(crate) async fn create_view_from_params(&self, params: CreateViewParams) -> Result<View, FlowyError> {
let view_data = if params.data.is_empty() {
initial_quill_delta_string()
pub(crate) async fn create_view_from_params(&self, mut params: CreateViewParams) -> Result<View, FlowyError> {
let processor = self.get_data_processor(&params.data_type)?;
let content = if params.data.is_empty() {
let default_view_data = processor.default_view_data();
params.data = default_view_data.clone();
default_view_data
} else {
params.data.clone()
};
let _ = self.create_view(&params.view_id, Bytes::from(view_data)).await?;
let delta_data = Bytes::from(content);
let _ = self
.create_view(&params.view_id, params.data_type.clone(), delta_data)
.await?;
let view = self.create_view_on_server(params).await?;
let _ = self.create_view_on_local(view.clone()).await?;
Ok(view)
}
#[tracing::instrument(level = "debug", skip(self, view_id, delta_data), err)]
pub(crate) async fn create_view(&self, view_id: &str, delta_data: Bytes) -> Result<(), FlowyError> {
pub(crate) async fn create_view(
&self,
view_id: &str,
data_type: ViewDataType,
delta_data: Bytes,
) -> Result<(), FlowyError> {
if delta_data.is_empty() {
return Err(FlowyError::internal().context("The content of the view should not be empty"));
}
let user_id = self.user.user_id()?;
let repeated_revision: RepeatedRevision = Revision::initial_revision(&user_id, view_id, delta_data).into();
let _ = self.block_manager.create_block(view_id, repeated_revision).await?;
let processor = self.get_data_processor(&data_type)?;
let _ = processor.create_container(view_id, repeated_revision).await?;
Ok(())
}
@ -132,8 +135,8 @@ impl ViewController {
#[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn open_view(&self, view_id: &str) -> Result<BlockDelta, FlowyError> {
let editor = self.block_manager.open_block(view_id).await?;
let delta_str = editor.delta_str().await?;
let processor = self.get_data_processor_from_view_id(view_id).await?;
let delta_str = processor.delta_str(view_id).await?;
KV::set_str(LATEST_VIEW_ID, view_id.to_owned());
Ok(BlockDelta {
block_id: view_id.to_string(),
@ -142,8 +145,9 @@ impl ViewController {
}
#[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn close_view(&self, doc_id: &str) -> Result<(), FlowyError> {
let _ = self.block_manager.close_block(doc_id)?;
pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
let processor = self.get_data_processor_from_view_id(view_id).await?;
let _ = processor.close_container(view_id).await?;
Ok(())
}
@ -154,7 +158,8 @@ impl ViewController {
let _ = KV::remove(LATEST_VIEW_ID);
}
}
let _ = self.block_manager.close_block(&params.value)?;
let processor = self.get_data_processor_from_view_id(&params.value).await?;
let _ = processor.close_container(&params.value).await?;
Ok(())
}
@ -165,8 +170,8 @@ impl ViewController {
.begin_transaction(|transaction| transaction.read_view(view_id))
.await?;
let editor = self.block_manager.open_block(view_id).await?;
let delta_str = editor.delta_str().await?;
let processor = self.get_data_processor(&view.data_type)?;
let delta_str = processor.delta_str(view_id).await?;
let duplicate_params = CreateViewParams {
belong_to_id: view.belong_to_id.clone(),
name: format!("{} (copy)", &view.name),
@ -287,7 +292,7 @@ impl ViewController {
fn listen_trash_can_event(&self) {
let mut rx = self.trash_controller.subscribe();
let persistence = self.persistence.clone();
let block_manager = self.block_manager.clone();
let data_processors = self.data_processors.clone();
let trash_controller = self.trash_controller.clone();
let _ = tokio::spawn(async move {
loop {
@ -301,7 +306,7 @@ impl ViewController {
if let Some(event) = stream.next().await {
handle_trash_event(
persistence.clone(),
block_manager.clone(),
data_processors.clone(),
trash_controller.clone(),
event,
)
@ -310,12 +315,34 @@ impl ViewController {
}
});
}
async fn get_data_processor_from_view_id(
&self,
view_id: &str,
) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
let view = self
.persistence
.begin_transaction(|transaction| transaction.read_view(view_id))
.await?;
self.get_data_processor(&view.data_type)
}
#[inline]
fn get_data_processor(&self, data_type: &ViewDataType) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
match self.data_processors.get(data_type) {
None => Err(FlowyError::internal().context(format!(
"Get data processor failed. Unknown view data type: {:?}",
data_type
))),
Some(processor) => Ok(processor.clone()),
}
}
}
#[tracing::instrument(level = "trace", skip(persistence, block_manager, trash_can))]
#[tracing::instrument(level = "trace", skip(persistence, data_processors, trash_can))]
async fn handle_trash_event(
persistence: Arc<FolderPersistence>,
block_manager: Arc<BlockManager>,
data_processors: ViewDataProcessorMap,
trash_can: Arc<TrashController>,
event: TrashEvent,
) {
@ -347,28 +374,54 @@ async fn handle_trash_event(
let _ = ret.send(result).await;
}
TrashEvent::Delete(identifiers, ret) => {
let result = persistence
.begin_transaction(|transaction| {
let mut notify_ids = HashSet::new();
for identifier in identifiers.items {
let view = transaction.read_view(&identifier.id)?;
let _ = transaction.delete_view(&identifier.id)?;
let _ = block_manager.delete_block(&identifier.id)?;
notify_ids.insert(view.belong_to_id);
}
let result = || async {
let views = persistence
.begin_transaction(|transaction| {
let mut notify_ids = HashSet::new();
let mut views = vec![];
for identifier in identifiers.items {
let view = transaction.read_view(&identifier.id)?;
let _ = transaction.delete_view(&view.id)?;
notify_ids.insert(view.belong_to_id.clone());
views.push(view);
}
for notify_id in notify_ids {
let _ = notify_views_changed(&notify_id, trash_can.clone(), &transaction)?;
}
Ok(views)
})
.await?;
for notify_id in notify_ids {
let _ = notify_views_changed(&notify_id, trash_can.clone(), &transaction)?;
for view in views {
match get_data_processor(data_processors.clone(), &view.data_type) {
Ok(processor) => {
let _ = processor.close_container(&view.id).await?;
}
Err(e) => {
tracing::error!("{}", e)
}
}
Ok(())
})
.await;
let _ = ret.send(result).await;
}
Ok(())
};
let _ = ret.send(result().await).await;
}
}
}
fn get_data_processor(
data_processors: ViewDataProcessorMap,
data_type: &ViewDataType,
) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
match data_processors.get(data_type) {
None => Err(FlowyError::internal().context(format!(
"Get data processor failed. Unknown view data type: {:?}",
data_type
))),
Some(processor) => Ok(processor.clone()),
}
}
fn read_local_views_with_transaction<'a>(
identifiers: RepeatedTrashId,
transaction: &'a (dyn FolderPersistenceTransaction + 'a),

View File

@ -1,9 +1,6 @@
use crate::manager::GridManager;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{
CreateGridPayload, Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedFieldOrder,
RepeatedRow, RepeatedRowOrder,
};
use flowy_grid_data_model::entities::{Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow};
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use std::sync::Arc;

View File

@ -1,12 +1,10 @@
use crate::services::grid_editor::ClientGridEditor;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::kv_persistence::GridKVPersistence;
use dashmap::DashMap;
use flowy_collaboration::client_grid::{make_grid_delta, make_grid_revisions};
use flowy_collaboration::client_grid::make_grid_delta;
use flowy_collaboration::entities::revision::RepeatedRevision;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{
Field, FieldOrder, Grid, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowOrder,
};
use flowy_grid_data_model::entities::{Field, FieldOrder, FieldType, Grid, RawRow, RowOrder};
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
use lib_sqlite::ConnectionPool;
use parking_lot::RwLock;
@ -21,12 +19,11 @@ pub trait GridUser: Send + Sync {
pub struct GridManager {
grid_editors: Arc<GridEditors>,
grid_user: Arc<dyn GridUser>,
rev_web_socket: Arc<dyn RevisionWebSocket>,
kv_persistence: Arc<RwLock<Option<Arc<GridKVPersistence>>>>,
}
impl GridManager {
pub fn new(grid_user: Arc<dyn GridUser>, rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
pub fn new(grid_user: Arc<dyn GridUser>, _rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
let grid_editors = Arc::new(GridEditors::new());
// kv_persistence will be initialized after first access.
@ -35,7 +32,6 @@ impl GridManager {
Self {
grid_editors,
grid_user,
rev_web_socket,
kv_persistence,
}
}
@ -123,28 +119,57 @@ impl GridManager {
}
}
pub fn make_grid(
user_id: &str,
grid_id: &str,
fields: Option<Vec<Field>>,
rows: Option<Vec<RawRow>>,
) -> RepeatedRevision {
let mut field_orders = vec![];
let mut row_orders = vec![];
if let Some(fields) = fields {
field_orders = fields.iter().map(|field| FieldOrder::from(field)).collect::<Vec<_>>();
}
if let Some(rows) = rows {
row_orders = rows.iter().map(|row| RowOrder::from(row)).collect::<Vec<_>>();
}
use lib_infra::uuid;
pub fn default_grid() -> String {
let grid_id = uuid();
let fields = vec![
Field {
id: uuid(),
name: "".to_string(),
desc: "".to_string(),
field_type: FieldType::RichText,
frozen: false,
width: 100,
type_options: Default::default(),
},
Field {
id: uuid(),
name: "".to_string(),
desc: "".to_string(),
field_type: FieldType::RichText,
frozen: false,
width: 100,
type_options: Default::default(),
},
];
let rows = vec![
RawRow {
id: uuid(),
grid_id: grid_id.clone(),
cell_by_field_id: Default::default(),
},
RawRow {
id: uuid(),
grid_id: grid_id.clone(),
cell_by_field_id: Default::default(),
},
];
make_grid(&grid_id, fields, rows)
}
pub fn make_grid(grid_id: &str, fields: Vec<Field>, rows: Vec<RawRow>) -> String {
let field_orders = fields.iter().map(FieldOrder::from).collect::<Vec<_>>();
let row_orders = rows.iter().map(RowOrder::from).collect::<Vec<_>>();
let grid = Grid {
id: grid_id.to_owned(),
field_orders: field_orders.into(),
row_orders: row_orders.into(),
};
make_grid_revisions(user_id, &grid)
let delta = make_grid_delta(&grid);
delta.to_delta_str()
}
pub struct GridEditors {

View File

@ -1,3 +1,4 @@
#![allow(clippy::upper_case_acronyms)]
use crate::impl_any_data;
use crate::services::util::*;
use bytes::Bytes;
@ -12,8 +13,6 @@ use rusty_money::{
Money,
};
use std::str::FromStr;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
pub trait StringifyAnyData {
@ -77,7 +76,7 @@ impl DisplayCell for CheckboxDescription {
}
// Date
#[derive(Clone, Debug, ProtoBuf)]
#[derive(Clone, Debug, ProtoBuf, Default)]
pub struct DateDescription {
#[pb(index = 1)]
pub date_format: DateFormat,
@ -87,15 +86,6 @@ pub struct DateDescription {
}
impl_any_data!(DateDescription, FieldType::DateTime);
impl std::default::Default for DateDescription {
fn default() -> Self {
DateDescription {
date_format: DateFormat::default(),
time_format: TimeFormat::default(),
}
}
}
impl DateDescription {
fn date_time_format_str(&self) -> String {
format!("{} {}", self.date_format.format_str(), self.time_format.format_str())
@ -134,7 +124,7 @@ impl DisplayCell for DateDescription {
impl StringifyAnyData for DateDescription {
fn stringify_any_data(&self, data: AnyData) -> String {
match String::from_utf8(data.value.clone()) {
match String::from_utf8(data.value) {
Ok(s) => match s.parse::<i64>() {
Ok(timestamp) => {
let native = NaiveDateTime::from_timestamp(timestamp, 0);
@ -380,7 +370,7 @@ impl NumberDescription {
impl DisplayCell for NumberDescription {
fn display_content(&self, s: &str) -> String {
match self.money_from_str(&s) {
match self.money_from_str(s) {
Some(money_str) => money_str,
None => String::default(),
}
@ -389,7 +379,7 @@ impl DisplayCell for NumberDescription {
impl StringifyAnyData for NumberDescription {
fn stringify_any_data(&self, data: AnyData) -> String {
match String::from_utf8(data.value.clone()) {
match String::from_utf8(data.value) {
Ok(s) => match self.money_from_str(&s) {
Some(money_str) => money_str,
None => String::default(),

View File

@ -1,23 +1,20 @@
use crate::manager::GridUser;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::stringify::stringify_deserialize;
use dashmap::mapref::one::Ref;
use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridChange, GridPad};
use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{
Cell, Field, Grid, GridId, RawCell, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row,
};
use flowy_sync::{
RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
RevisionWebSocket, RevisionWebSocketManager,
Cell, Field, Grid, RawCell, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row,
};
use flowy_sync::{RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder};
use lib_infra::future::FutureResult;
use lib_infra::uuid;
use lib_ot::core::PlainTextAttributes;
use lib_sqlite::ConnectionPool;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap;
use std::sync::Arc;

View File

@ -6,9 +6,9 @@ use flowy_database::{
schema::{kv_table, kv_table::dsl},
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{Field, GridIdentifiable, RawRow};
use lib_infra::future::{BoxResultFuture, FutureResult};
use lib_sqlite::{ConnectionManager, ConnectionPool};
use flowy_grid_data_model::entities::GridIdentifiable;
use lib_sqlite::ConnectionPool;
use std::sync::Arc;
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]

View File

@ -3,6 +3,7 @@ use crate::services::util::*;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
#[allow(dead_code)]
pub fn stringify_serialize(field: &Field, s: &str) -> Result<AnyData, FlowyError> {
match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_to_any_data(s),

View File

@ -23,7 +23,6 @@ color-eyre = { version = "0.5", default-features = false }
bytes = "1.0"
tokio = { version = "1", features = ["rt"] }
parking_lot = "0.11"
async-trait = "0.1.52"
flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
lib-ws = { path = "../../../shared-lib/lib-ws" }

View File

@ -1,17 +1,17 @@
use async_trait::async_trait;
use bytes::Bytes;
use flowy_block::BlockManager;
use flowy_collaboration::client_document::default::initial_quill_delta_string;
use flowy_collaboration::entities::revision::RepeatedRevision;
use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
use flowy_database::ConnectionPool;
use flowy_folder::manager::{DataProcessorMap, ViewDataProcessor};
use flowy_folder::prelude::{FlowyResult, ViewDataType};
use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap};
use flowy_folder::prelude::ViewDataType;
use flowy_folder::{
errors::{internal_error, FlowyError},
event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
manager::FolderManager,
};
use flowy_grid::manager::GridManager;
use flowy_grid::manager::{default_grid, GridManager};
use flowy_net::ClientServerConfiguration;
use flowy_net::{
http_server::folder::FolderHttpCloudService, local_server::LocalServer, ws::connection::FlowyWebSocketConnect,
@ -19,7 +19,7 @@ use flowy_net::{
use flowy_sync::{RevisionWebSocket, WSStateReceiver};
use flowy_user::services::UserSession;
use futures_core::future::BoxFuture;
use lib_infra::future::BoxResultFuture;
use lib_infra::future::{BoxResultFuture, FutureResult};
use lib_ws::{WSChannel, WSMessageReceiver, WebSocketRawMessage};
use std::collections::HashMap;
use std::{convert::TryInto, sync::Arc};
@ -43,17 +43,8 @@ impl FolderDepsResolver {
};
let view_data_processor = make_view_data_processor(block_manager.clone(), grid_manager.clone());
let folder_manager = Arc::new(
FolderManager::new(
user.clone(),
cloud_service,
database,
view_data_processor,
block_manager.clone(),
web_socket,
)
.await,
);
let folder_manager =
Arc::new(FolderManager::new(user.clone(), cloud_service, database, view_data_processor, web_socket).await);
if let (Ok(user_id), Ok(token)) = (user.user_id(), user.token()) {
match folder_manager.initialize(&user_id, &token).await {
@ -64,12 +55,11 @@ impl FolderDepsResolver {
let receiver = Arc::new(FolderWSMessageReceiverImpl(folder_manager.clone()));
ws_conn.add_ws_message_receiver(receiver).unwrap();
folder_manager
}
}
fn make_view_data_processor(block_manager: Arc<BlockManager>, grid_manager: Arc<GridManager>) -> DataProcessorMap {
fn make_view_data_processor(block_manager: Arc<BlockManager>, grid_manager: Arc<GridManager>) -> ViewDataProcessorMap {
let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
let block_data_impl = BlockManagerViewDataImpl(block_manager);
@ -140,27 +130,51 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl {
}
struct BlockManagerViewDataImpl(Arc<BlockManager>);
#[async_trait]
impl ViewDataProcessor for BlockManagerViewDataImpl {
async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()> {
let _ = self.0.create_block(view_id, repeated_revision).await?;
Ok(())
fn initialize(&self) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
FutureResult::new(async move { block_manager.init() })
}
async fn delete_container(&self, view_id: &str) -> FlowyResult<()> {
let _ = self.0.delete_block(view_id)?;
Ok(())
fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.create_block(view_id, repeated_revision).await?;
Ok(())
})
}
async fn close_container(&self, view_id: &str) -> FlowyResult<()> {
let _ = self.0.close_block(view_id)?;
Ok(())
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.delete_block(view_id)?;
Ok(())
})
}
async fn delta_str(&self, view_id: &str) -> FlowyResult<String> {
let editor = self.0.open_block(view_id).await?;
let delta_str = editor.delta_str().await?;
Ok(delta_str)
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.close_block(view_id)?;
Ok(())
})
}
fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError> {
let view_id = view_id.to_string();
let block_manager = self.0.clone();
FutureResult::new(async move {
let editor = block_manager.open_block(view_id).await?;
let delta_str = editor.delta_str().await?;
Ok(delta_str)
})
}
fn default_view_data(&self) -> String {
initial_quill_delta_string()
}
fn data_type(&self) -> ViewDataType {
@ -169,27 +183,50 @@ impl ViewDataProcessor for BlockManagerViewDataImpl {
}
struct GridManagerViewDataImpl(Arc<GridManager>);
#[async_trait]
impl ViewDataProcessor for GridManagerViewDataImpl {
async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()> {
let _ = self.0.create_grid(view_id, repeated_revision).await?;
Ok(())
fn initialize(&self) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}
async fn delete_container(&self, view_id: &str) -> FlowyResult<()> {
let _ = self.0.delete_grid(view_id)?;
Ok(())
fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
let grid_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = grid_manager.create_grid(view_id, repeated_revision).await?;
Ok(())
})
}
async fn close_container(&self, view_id: &str) -> FlowyResult<()> {
let _ = self.0.close_grid(view_id)?;
Ok(())
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let grid_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = grid_manager.delete_grid(view_id)?;
Ok(())
})
}
async fn delta_str(&self, view_id: &str) -> FlowyResult<String> {
let editor = self.0.open_grid(view_id).await?;
let delta_str = editor.delta_str().await;
Ok(delta_str)
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let grid_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = grid_manager.close_grid(view_id)?;
Ok(())
})
}
fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError> {
let view_id = view_id.to_string();
let grid_manager = self.0.clone();
FutureResult::new(async move {
let editor = grid_manager.open_grid(view_id).await?;
let delta_str = editor.delta_str().await;
Ok(delta_str)
})
}
fn default_view_data(&self) -> String {
default_grid()
}
fn data_type(&self) -> ViewDataType {

View File

@ -17,9 +17,8 @@ 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
let rev_web_socket = Arc::new(GridWebSocket(ws_conn));
Arc::new(GridManager::new(user, rev_web_socket))
}
}

View File

@ -17,7 +17,8 @@ pub fn mk_modules(
let folder_module = mk_folder_module(folder_manager.clone());
let network_module = mk_network_module(ws_conn.clone());
let grid_module = mk_grid_module(grid_manager.clone());
vec![user_module, folder_module, network_module, grid_module]
let block_module = mk_block_module(block_manager.clone());
vec![user_module, folder_module, network_module, grid_module, block_module]
}
fn mk_user_module(user_session: Arc<UserSession>) -> Module {

View File

@ -9,7 +9,7 @@ use crate::{
};
use flowy_folder_data_model::entities::{app::App, trash::Trash, view::View, workspace::Workspace};
use lib_ot::core::*;
use lib_ot::rich_text::RichTextAttributes;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

View File

@ -1,9 +1,9 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{CellChangeset, Field, FieldOrder, Grid, RawRow, RepeatedFieldOrder, RowOrder};
use flowy_grid_data_model::entities::{Field, FieldOrder, Grid, RawRow, RepeatedFieldOrder, RowOrder};
use lib_infra::uuid;
use lib_ot::core::{FlowyStr, OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use std::sync::Arc;
pub type GridDelta = PlainTextDelta;
@ -54,7 +54,7 @@ impl GridPad {
})
}
pub fn delete_rows(&mut self, row_ids: &Vec<String>) -> CollaborateResult<Option<GridChange>> {
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.row_orders.retain(|row_order| !row_ids.contains(&row_order.row_id));
Ok(Some(()))
@ -99,7 +99,7 @@ impl GridPad {
F: FnOnce(&mut Grid) -> CollaborateResult<Option<()>>,
{
let cloned_grid = self.grid.clone();
match f(&mut Arc::make_mut(&mut self.grid))? {
match f(Arc::make_mut(&mut self.grid))? {
None => Ok(None),
Some(_) => {
let old = json_from_grid(&cloned_grid)?;

View File

@ -53,6 +53,7 @@ fn create_row_order(grid_id: &str, row_id: &str) -> RowOrder {
}
}
#[allow(dead_code)]
fn uuid() -> String {
uuid::Uuid::new_v4().to_string()
}