Refactor/crate directory (#1621)

* chore: fix wanrings

* chore: remove protobuf ref in flowy-error-code

* chore: remove protobuf ref in lib-ws

* refactor: remove protobuf trait in flowy http model

* refactor: remove flowy-error-code crate

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Nathan.fooo 2022-12-30 11:16:47 +08:00 committed by GitHub
parent aae8259f63
commit aa5f052ecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
167 changed files with 655 additions and 923 deletions

View File

@ -43,7 +43,6 @@ CRATE_TYPE = "staticlib"
LIB_EXT = "a"
APP_ENVIRONMENT = "local"
FLUTTER_FLOWY_SDK_PATH = "app_flowy/packages/flowy_sdk"
PROTOBUF_DERIVE_CACHE = "../shared-lib/flowy-derive/src/derive_cache/derive_cache.rs"
# Test default config
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dylib"

View File

@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/field/field_service.dart';
import 'package:easy_localization/easy_localization.dart'
show StringTranslateExtension;
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';

View File

@ -1,6 +1,6 @@
import 'package:app_flowy/user/application/auth_service.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
import 'package:freezed_annotation/freezed_annotation.dart';
@ -20,24 +20,34 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
);
},
emailChanged: (EmailChanged value) async {
emit(state.copyWith(email: value.email, emailError: none(), successOrFail: none()));
emit(state.copyWith(
email: value.email, emailError: none(), successOrFail: none()));
},
passwordChanged: (PasswordChanged value) async {
emit(state.copyWith(password: value.password, passwordError: none(), successOrFail: none()));
emit(state.copyWith(
password: value.password,
passwordError: none(),
successOrFail: none()));
},
);
});
}
Future<void> _performActionOnSignIn(SignInState state, Emitter<SignInState> emit) async {
emit(state.copyWith(isSubmitting: true, emailError: none(), passwordError: none(), successOrFail: none()));
Future<void> _performActionOnSignIn(
SignInState state, Emitter<SignInState> emit) async {
emit(state.copyWith(
isSubmitting: true,
emailError: none(),
passwordError: none(),
successOrFail: none()));
final result = await authService.signIn(
email: state.email,
password: state.password,
);
emit(result.fold(
(userProfile) => state.copyWith(isSubmitting: false, successOrFail: some(left(userProfile))),
(userProfile) => state.copyWith(
isSubmitting: false, successOrFail: some(left(userProfile))),
(error) => stateFromCode(error),
));
}
@ -45,18 +55,26 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
SignInState stateFromCode(FlowyError error) {
switch (ErrorCode.valueOf(error.code)!) {
case ErrorCode.EmailFormatInvalid:
return state.copyWith(isSubmitting: false, emailError: some(error.msg), passwordError: none());
return state.copyWith(
isSubmitting: false,
emailError: some(error.msg),
passwordError: none());
case ErrorCode.PasswordFormatInvalid:
return state.copyWith(isSubmitting: false, passwordError: some(error.msg), emailError: none());
return state.copyWith(
isSubmitting: false,
passwordError: some(error.msg),
emailError: none());
default:
return state.copyWith(isSubmitting: false, successOrFail: some(right(error)));
return state.copyWith(
isSubmitting: false, successOrFail: some(right(error)));
}
}
}
@freezed
class SignInEvent with _$SignInEvent {
const factory SignInEvent.signedInWithUserEmailAndPassword() = SignedInWithUserEmailAndPassword;
const factory SignInEvent.signedInWithUserEmailAndPassword() =
SignedInWithUserEmailAndPassword;
const factory SignInEvent.emailChanged(String email) = EmailChanged;
const factory SignInEvent.passwordChanged(String password) = PasswordChanged;
}

View File

@ -1,7 +1,7 @@
import 'package:app_flowy/user/application/auth_service.dart';
import 'package:dartz/dartz.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -17,11 +17,18 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
await event.map(signUpWithUserEmailAndPassword: (e) async {
await _performActionOnSignUp(emit);
}, emailChanged: (_EmailChanged value) async {
emit(state.copyWith(email: value.email, emailError: none(), successOrFail: none()));
emit(state.copyWith(
email: value.email, emailError: none(), successOrFail: none()));
}, passwordChanged: (_PasswordChanged value) async {
emit(state.copyWith(password: value.password, passwordError: none(), successOrFail: none()));
emit(state.copyWith(
password: value.password,
passwordError: none(),
successOrFail: none()));
}, repeatPasswordChanged: (_RepeatPasswordChanged value) async {
emit(state.copyWith(repeatedPassword: value.password, repeatPasswordError: none(), successOrFail: none()));
emit(state.copyWith(
repeatedPassword: value.password,
repeatPasswordError: none(),
successOrFail: none()));
});
});
}
@ -45,7 +52,8 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
if (repeatedPassword == null) {
emit(state.copyWith(
isSubmitting: false,
repeatPasswordError: some(LocaleKeys.signUp_repeatPasswordEmptyError.tr()),
repeatPasswordError:
some(LocaleKeys.signUp_repeatPasswordEmptyError.tr()),
));
return;
}
@ -53,7 +61,8 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
if (password != repeatedPassword) {
emit(state.copyWith(
isSubmitting: false,
repeatPasswordError: some(LocaleKeys.signUp_unmatchedPasswordError.tr()),
repeatPasswordError:
some(LocaleKeys.signUp_unmatchedPasswordError.tr()),
));
return;
}
@ -97,17 +106,20 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
successOrFail: none(),
);
default:
return state.copyWith(isSubmitting: false, successOrFail: some(right(error)));
return state.copyWith(
isSubmitting: false, successOrFail: some(right(error)));
}
}
}
@freezed
class SignUpEvent with _$SignUpEvent {
const factory SignUpEvent.signUpWithUserEmailAndPassword() = SignUpWithUserEmailAndPassword;
const factory SignUpEvent.signUpWithUserEmailAndPassword() =
SignUpWithUserEmailAndPassword;
const factory SignUpEvent.emailChanged(String email) = _EmailChanged;
const factory SignUpEvent.passwordChanged(String password) = _PasswordChanged;
const factory SignUpEvent.repeatPasswordChanged(String password) = _RepeatPasswordChanged;
const factory SignUpEvent.repeatPasswordChanged(String password) =
_RepeatPasswordChanged;
}
@freezed

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:app_flowy/core/folder_notification.dart';
import 'package:app_flowy/core/user_notification.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'dart:typed_data';

View File

@ -1,6 +1,6 @@
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -1,7 +1,7 @@
import 'package:app_flowy/user/application/user_listener.dart';
import 'package:flowy_infra/time/duration.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/code.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'

View File

@ -872,10 +872,13 @@ dependencies = [
"flowy-ast",
"flowy-codegen",
"lazy_static",
"log",
"proc-macro2",
"quote",
"serde_json",
"syn",
"tokio",
"trybuild",
"walkdir",
]
@ -927,11 +930,11 @@ dependencies = [
name = "flowy-error"
version = "0.1.0"
dependencies = [
"anyhow",
"bytes",
"flowy-codegen",
"flowy-database",
"flowy-derive",
"flowy-error-code",
"flowy-sync",
"http-flowy",
"lib-dispatch",
@ -940,16 +943,7 @@ dependencies = [
"protobuf",
"r2d2",
"serde_json",
]
[[package]]
name = "flowy-error-code"
version = "0.1.0"
dependencies = [
"derive_more",
"flowy-codegen",
"flowy-derive",
"protobuf",
"thiserror",
]
[[package]]
@ -1042,11 +1036,10 @@ name = "flowy-http-model"
version = "0.1.0"
dependencies = [
"bytes",
"flowy-codegen",
"flowy-derive",
"lib-infra",
"md5",
"protobuf",
"serde",
"serde_json",
"serde_repr",
]
[[package]]
@ -1441,6 +1434,12 @@ version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "globset"
version = "0.4.8"
@ -1470,7 +1469,6 @@ name = "grid-rev-model"
version = "0.1.0"
dependencies = [
"bytes",
"flowy-error-code",
"indexmap",
"nanoid",
"serde",
@ -1855,8 +1853,6 @@ version = "0.1.0"
dependencies = [
"bytes",
"dashmap",
"flowy-codegen",
"flowy-derive",
"futures",
"futures-channel",
"futures-core",
@ -1867,6 +1863,9 @@ dependencies = [
"paste",
"pin-project",
"protobuf",
"serde",
"serde_json",
"serde_repr",
"strum",
"strum_macros",
"tokio",
@ -3521,6 +3520,21 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "trybuild"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f408301c7480f9e6294eb779cfc907f54bd901a9660ef24d7f233ed5376485"
dependencies = [
"glob",
"once_cell",
"serde",
"serde_derive",
"serde_json",
"termcolor",
"toml",
]
[[package]]
name = "tungstenite"
version = "0.14.0"

View File

@ -16,6 +16,10 @@ members = [
"flowy-revision",
"flowy-grid",
"flowy-task",
"flowy-sync",
"flowy-derive",
"flowy-ast",
"flowy-codegen",
]
[profile.dev]

View File

@ -28,7 +28,7 @@ parking_lot = "0.12.1"
lib-dispatch = { path = "../lib-dispatch" }
flowy-sdk = { path = "../flowy-sdk" }
dart-notify = { path = "../dart-notify" }
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-derive = { path = "../flowy-derive" }
[features]
default = ["flowy-sdk/dart", "dart-notify/dart", "flutter"]
@ -37,7 +37,7 @@ http_sync = ["flowy-sdk/http_sync", "flowy-sdk/use_bunyan"]
openssl_vendored = ["flowy-sdk/openssl_vendored"]
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen", features = [
flowy-codegen = { path = "../flowy-codegen", features = [
"dart",
]}

View File

@ -12,11 +12,11 @@ allo-isolate = {version = "^0.1", features = ["catch-unwind",]}
log = "0.4.14"
bytes = { version = "1.0" }
flowy-derive = {path = "../../../shared-lib/flowy-derive" }
flowy-derive = {path = "../flowy-derive" }
lib-dispatch = {path = "../lib-dispatch" }
[features]
dart = ["flowy-codegen/dart"]
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}

View File

@ -20,7 +20,7 @@ proc-macro2 = "1.0"
flowy-ast = { path = "../flowy-ast" }
lazy_static = {version = "1.4.0"}
dashmap = "5"
flowy-codegen= { path = "../flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}
serde_json = "1.0"
walkdir = "2.3.1"

View File

@ -7,9 +7,9 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
flowy-sync = { path = "../../../shared-lib/flowy-sync"}
flowy-sync = { path = "../flowy-sync"}
flowy-http-model = { path = "../../../shared-lib/flowy-http-model"}
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-derive = { path = "../flowy-derive" }
lib-ot = { path = "../../../shared-lib/lib-ot" }
lib-ws = { path = "../../../shared-lib/lib-ws" }
lib-infra = { path = "../../../shared-lib/lib-infra" }
@ -52,7 +52,7 @@ criterion = "0.3"
rand = "0.8.5"
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}
[features]

View File

@ -3,7 +3,6 @@ use crate::DocumentUser;
use async_stream::stream;
use bytes::Bytes;
use flowy_error::FlowyError;
use flowy_http_model::revision::RevId;
use flowy_revision::RevisionManager;
use futures::stream::StreamExt;
use lib_ot::core::Transaction;
@ -76,10 +75,10 @@ impl DocumentQueue {
}
#[tracing::instrument(level = "trace", skip(self, transaction, md5), err)]
async fn save_local_operations(&self, transaction: Transaction, md5: String) -> Result<RevId, FlowyError> {
async fn save_local_operations(&self, transaction: Transaction, md5: String) -> Result<i64, FlowyError> {
let bytes = Bytes::from(transaction.to_bytes()?);
let rev_id = self.rev_manager.add_local_revision(bytes, md5).await?;
Ok(rev_id.into())
Ok(rev_id)
}
}

View File

@ -16,13 +16,13 @@ pub mod errors {
pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000;
use crate::errors::FlowyError;
use flowy_http_model::document::{CreateDocumentParams, DocumentIdPB, DocumentPayloadPB, ResetDocumentParams};
use flowy_http_model::document::{CreateDocumentParams, DocumentId, DocumentPayload, ResetDocumentParams};
use lib_infra::future::FutureResult;
pub trait DocumentCloudService: Send + Sync {
fn create_document(&self, token: &str, params: CreateDocumentParams) -> FutureResult<(), FlowyError>;
fn fetch_document(&self, token: &str, params: DocumentIdPB) -> FutureResult<Option<DocumentPayloadPB>, FlowyError>;
fn fetch_document(&self, token: &str, params: DocumentId) -> FutureResult<Option<DocumentPayload>, FlowyError>;
fn update_document_content(&self, token: &str, params: ResetDocumentParams) -> FutureResult<(), FlowyError>;
}

View File

@ -8,7 +8,8 @@ use bytes::Bytes;
use flowy_database::ConnectionPool;
use flowy_error::FlowyResult;
use flowy_http_model::util::md5;
use flowy_http_model::{document::DocumentIdPB, revision::Revision, ws_data::ServerRevisionWSData};
use flowy_http_model::ws_data::ServerRevisionWSData;
use flowy_http_model::{document::DocumentId, revision::Revision};
use flowy_revision::{
PhantomSnapshotPersistence, RevisionCloudService, RevisionManager, RevisionPersistence,
RevisionPersistenceConfiguration, RevisionWebSocket,
@ -19,7 +20,8 @@ use lib_infra::future::FutureResult;
use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
use lib_ws::WSConnectState;
use std::any::Any;
use std::{convert::TryInto, sync::Arc};
use std::convert::TryFrom;
use std::sync::Arc;
use tokio::sync::RwLock;
pub trait DocumentUser: Send + Sync {
@ -150,10 +152,14 @@ impl DocumentManager {
}
pub async fn receive_ws_data(&self, data: Bytes) {
let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into();
let result: Result<ServerRevisionWSData, serde_json::Error> = ServerRevisionWSData::try_from(data);
match result {
Ok(data) => match self.editor_map.read().await.get(&data.object_id) {
None => tracing::error!("Can't find any source handler for {:?}-{:?}", data.object_id, data.ty),
None => tracing::error!(
"Can't find any source handler for {:?}-{:?}",
data.object_id,
data.payload
),
Some(handler) => match handler.0.receive_ws_data(data).await {
Ok(_) => {}
Err(e) => tracing::error!("{}", e),
@ -294,7 +300,7 @@ struct DocumentRevisionCloudService {
impl RevisionCloudService for DocumentRevisionCloudService {
#[tracing::instrument(level = "trace", skip(self))]
fn fetch_object(&self, user_id: &str, object_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
let params: DocumentIdPB = object_id.to_string().into();
let params: DocumentId = object_id.to_string().into();
let server = self.server.clone();
let token = self.token.clone();

View File

@ -5,7 +5,7 @@ use crate::{errors::FlowyError, DocumentEditor, DocumentUser};
use bytes::Bytes;
use flowy_database::ConnectionPool;
use flowy_error::{internal_error, FlowyResult};
use flowy_http_model::document::DocumentPayloadPB;
use flowy_http_model::document::DocumentPayload;
use flowy_http_model::revision::Revision;
use flowy_http_model::ws_data::ServerRevisionWSData;
use flowy_revision::{
@ -246,14 +246,14 @@ impl DeltaDocumentEditor {
pub struct DeltaDocumentRevisionSerde();
impl RevisionObjectDeserializer for DeltaDocumentRevisionSerde {
type Output = DocumentPayloadPB;
type Output = DocumentPayload;
fn deserialize_revisions(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id();
let mut delta = make_operations_from_revisions(revisions)?;
correct_delta(&mut delta);
Result::<DocumentPayloadPB, FlowyError>::Ok(DocumentPayloadPB {
Result::<DocumentPayload, FlowyError>::Ok(DocumentPayload {
doc_id: object_id.to_owned(),
data: delta.json_bytes().to_vec(),
rev_id,

View File

@ -3,7 +3,6 @@ use crate::DocumentUser;
use async_stream::stream;
use flowy_database::ConnectionPool;
use flowy_error::FlowyError;
use flowy_http_model::revision::RevId;
use flowy_revision::{RevisionMD5, RevisionManager, TransformOperations};
use flowy_sync::{
client_document::{history::UndoResult, ClientDocument},
@ -176,10 +175,10 @@ impl EditDocumentQueue {
Ok(())
}
async fn save_local_operations(&self, operations: DeltaTextOperations, md5: String) -> Result<RevId, FlowyError> {
async fn save_local_operations(&self, operations: DeltaTextOperations, md5: String) -> Result<i64, FlowyError> {
let bytes = operations.json_bytes();
let rev_id = self.rev_manager.add_local_revision(bytes, md5).await?;
Ok(rev_id.into())
Ok(rev_id)
}
}

View File

@ -3,10 +3,8 @@ use crate::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS;
use bytes::Bytes;
use flowy_database::ConnectionPool;
use flowy_error::{internal_error, FlowyError, FlowyResult};
use flowy_http_model::{
revision::{Revision, RevisionRange},
ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSDataType},
};
use flowy_http_model::revision::{Revision, RevisionRange};
use flowy_http_model::ws_data::{ClientRevisionWSData, NewDocumentUser};
use flowy_revision::*;
use flowy_sync::errors::CollaborateResult;
use flowy_sync::util::make_operations_from_revisions;
@ -96,14 +94,14 @@ impl DocumentRevisionWSDataStream {
}
impl RevisionWSDataStream for DocumentRevisionWSDataStream {
fn receive_push_revision(&self, bytes: Bytes) -> BoxResultFuture<(), FlowyError> {
fn receive_push_revision(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), FlowyError> {
let resolver = self.conflict_controller.clone();
Box::pin(async move { resolver.receive_bytes(bytes).await })
Box::pin(async move { resolver.receive_revisions(revisions).await })
}
fn receive_ack(&self, id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError> {
fn receive_ack(&self, rev_id: i64) -> BoxResultFuture<(), FlowyError> {
let resolver = self.conflict_controller.clone();
Box::pin(async move { resolver.ack_revision(id, ty).await })
Box::pin(async move { resolver.ack_revision(rev_id).await })
}
fn receive_new_user_connect(&self, _new_user: NewDocumentUser) -> BoxResultFuture<(), FlowyError> {

View File

@ -126,7 +126,7 @@ impl DeltaRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: TextRevisionState = changeset.state.clone().into();
let filter = dsl::rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::doc_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -126,7 +126,7 @@ impl DocumentRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: DocumentRevisionState = changeset.state.clone().into();
let filter = dsl::document_rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::document_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -6,8 +6,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-error-code = { path = "../../../shared-lib/flowy-error-code"}
flowy-derive = { path = "../flowy-derive" }
lib-dispatch = { path = "../lib-dispatch" }
protobuf = {version = "2.20.0"}
bytes = "1.0"
@ -15,7 +14,7 @@ anyhow = "1.0"
thiserror = "1.0"
flowy-sync = { path = "../../../shared-lib/flowy-sync", optional = true}
flowy-sync = { path = "../flowy-sync", optional = true}
lib-ot = { path = "../../../shared-lib/lib-ot", optional = true}
serde_json = {version = "1.0", optional = true}
http-flowy = { git = "https://github.com/AppFlowy-IO/AppFlowy-Server", optional = true}
@ -29,7 +28,7 @@ ot = ["lib-ot"]
serde = ["serde_json"]
http_server = ["http-flowy"]
db = ["flowy-database", "lib-sqlite", "r2d2"]
dart = ["flowy-error-code/dart", "flowy-codegen/dart"]
dart = ["flowy-codegen/dart"]
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}

View File

@ -1,3 +1,3 @@
# Check out the FlowyConfig (located in flowy_toml.rs) for more details.
proto_input = ["src/errors.rs",]
proto_input = ["src/errors.rs","src/code.rs"]

View File

@ -1,155 +1,166 @@
use crate::protobuf::ErrorCode as ProtoBufErrorCode;
use flowy_derive::ProtoBuf_Enum;
use protobuf::ProtobufEnum;
use std::convert::{TryFrom, TryInto};
use thiserror::Error;
#[derive(Debug, Clone, ProtoBuf_Enum, PartialEq, Eq, Error)]
#[derive(Debug, Clone, PartialEq, Eq, Error, ProtoBuf_Enum)]
pub enum ErrorCode {
#[error("Internal error")]
Internal = 0,
#[error("UserUnauthorized")]
#[error("Unauthorized user")]
UserUnauthorized = 2,
#[error("RecordNotFound")]
#[error("Record not found")]
RecordNotFound = 3,
#[error("User id is empty")]
UserIdIsEmpty = 4,
#[error("Workspace name can not be empty or whitespace")]
WorkspaceNameInvalid = 100,
WorkspaceNameInvalid = 5,
#[error("Workspace id can not be empty or whitespace")]
WorkspaceIdInvalid = 101,
WorkspaceIdInvalid = 6,
#[error("Color style of the App is invalid")]
AppColorStyleInvalid = 102,
AppColorStyleInvalid = 7,
#[error("Workspace desc is invalid")]
WorkspaceDescTooLong = 103,
WorkspaceDescTooLong = 8,
#[error("Workspace description too long")]
WorkspaceNameTooLong = 104,
WorkspaceNameTooLong = 9,
#[error("App id can not be empty or whitespace")]
AppIdInvalid = 110,
AppIdInvalid = 10,
#[error("App name can not be empty or whitespace")]
AppNameInvalid = 111,
AppNameInvalid = 11,
#[error("View name can not be empty or whitespace")]
ViewNameInvalid = 120,
ViewNameInvalid = 12,
#[error("Thumbnail of the view is invalid")]
ViewThumbnailInvalid = 121,
ViewThumbnailInvalid = 13,
#[error("View id can not be empty or whitespace")]
ViewIdInvalid = 122,
ViewIdInvalid = 14,
#[error("View desc too long")]
ViewDescTooLong = 123,
ViewDescTooLong = 15,
#[error("View data is invalid")]
ViewDataInvalid = 124,
ViewDataInvalid = 16,
#[error("View name too long")]
ViewNameTooLong = 125,
ViewNameTooLong = 17,
#[error("Connection error")]
ConnectError = 200,
#[error("Http server connection error")]
HttpServerConnectError = 18,
#[error("Email can not be empty or whitespace")]
EmailIsEmpty = 300,
EmailIsEmpty = 19,
#[error("Email format is not valid")]
EmailFormatInvalid = 301,
EmailFormatInvalid = 20,
#[error("Email already exists")]
EmailAlreadyExists = 302,
EmailAlreadyExists = 21,
#[error("Password can not be empty or whitespace")]
PasswordIsEmpty = 303,
PasswordIsEmpty = 22,
#[error("Password format too long")]
PasswordTooLong = 304,
PasswordTooLong = 23,
#[error("Password contains forbidden characters.")]
PasswordContainsForbidCharacters = 305,
PasswordContainsForbidCharacters = 24,
#[error("Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric")]
PasswordFormatInvalid = 306,
PasswordFormatInvalid = 25,
#[error("Password not match")]
PasswordNotMatch = 307,
PasswordNotMatch = 26,
#[error("User name is too long")]
UserNameTooLong = 308,
UserNameTooLong = 27,
#[error("User name contain forbidden characters")]
UserNameContainForbiddenCharacters = 309,
UserNameContainForbiddenCharacters = 28,
#[error("User name can not be empty or whitespace")]
UserNameIsEmpty = 310,
UserNameIsEmpty = 29,
#[error("user id is empty or whitespace")]
UserIdInvalid = 311,
UserIdInvalid = 30,
#[error("User not exist")]
UserNotExist = 312,
UserNotExist = 31,
#[error("Text is too long")]
TextTooLong = 400,
TextTooLong = 32,
#[error("Grid id is empty")]
GridIdIsEmpty = 410,
GridIdIsEmpty = 33,
#[error("Grid view id is empty")]
GridViewIdIsEmpty = 411,
GridViewIdIsEmpty = 34,
#[error("Grid block id is empty")]
BlockIdIsEmpty = 420,
BlockIdIsEmpty = 35,
#[error("Row id is empty")]
RowIdIsEmpty = 430,
RowIdIsEmpty = 36,
#[error("Select option id is empty")]
OptionIdIsEmpty = 431,
OptionIdIsEmpty = 37,
#[error("Field id is empty")]
FieldIdIsEmpty = 440,
FieldIdIsEmpty = 38,
#[error("Field doesn't exist")]
FieldDoesNotExist = 441,
FieldDoesNotExist = 39,
#[error("The name of the option should not be empty")]
SelectOptionNameIsEmpty = 442,
SelectOptionNameIsEmpty = 40,
#[error("Field not exists")]
FieldNotExists = 443,
FieldNotExists = 41,
#[error("The operation in this field is invalid")]
FieldInvalidOperation = 444,
FieldInvalidOperation = 42,
#[error("Filter id is empty")]
FilterIdIsEmpty = 445,
FilterIdIsEmpty = 43,
#[error("Field is not exist")]
FieldRecordNotFound = 446,
FieldRecordNotFound = 44,
#[error("Field's type-option data should not be empty")]
TypeOptionDataIsEmpty = 450,
TypeOptionDataIsEmpty = 45,
#[error("Group id is empty")]
GroupIdIsEmpty = 460,
GroupIdIsEmpty = 46,
#[error("Invalid date time format")]
InvalidDateTimeFormat = 500,
InvalidDateTimeFormat = 47,
#[error("The input string is empty or contains invalid characters")]
UnexpectedEmptyString = 999,
UnexpectedEmptyString = 48,
#[error("Invalid data")]
InvalidData = 1000,
InvalidData = 49,
#[error("Serde")]
Serde = 1001,
Serde = 50,
#[error("Protobuf serde")]
ProtobufSerde = 1002,
ProtobufSerde = 51,
#[error("Out of bounds")]
OutOfBounds = 10001,
OutOfBounds = 52,
}
impl ErrorCode {
pub fn value(&self) -> i32 {
let code: ProtoBufErrorCode = self.clone().try_into().unwrap();
code.value()
}
pub fn from_i32(value: i32) -> Self {
match ProtoBufErrorCode::from_i32(value) {
None => ErrorCode::Internal,
Some(code) => ErrorCode::try_from(&code).unwrap(),
}
self.clone() as i32
}
}

View File

@ -1,7 +1,7 @@
use crate::ErrorCode;
use anyhow::Result;
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error_code::ErrorCode;
use lib_dispatch::prelude::{AFPluginEventResponse, ResponseBuilder};
use std::{convert::TryInto, fmt::Debug};
use thiserror::Error;
@ -30,7 +30,7 @@ macro_rules! static_flowy_error {
impl FlowyError {
pub fn new(code: ErrorCode, msg: &str) -> Self {
Self {
code: code.value(),
code: code.value() as i32,
msg: msg.to_owned(),
}
}
@ -53,7 +53,7 @@ impl FlowyError {
static_flowy_error!(view_desc, ErrorCode::ViewDescTooLong);
static_flowy_error!(view_data, ErrorCode::ViewDataInvalid);
static_flowy_error!(unauthorized, ErrorCode::UserUnauthorized);
static_flowy_error!(connection, ErrorCode::ConnectError);
static_flowy_error!(connection, ErrorCode::HttpServerConnectError);
static_flowy_error!(email_empty, ErrorCode::EmailIsEmpty);
static_flowy_error!(email_format, ErrorCode::EmailFormatInvalid);
static_flowy_error!(email_exist, ErrorCode::EmailAlreadyExists);
@ -77,7 +77,7 @@ impl FlowyError {
impl std::convert::From<ErrorCode> for FlowyError {
fn from(code: ErrorCode) -> Self {
FlowyError {
code: code.value(),
code: code.value() as i32,
msg: format!("{}", code),
}
}

View File

@ -1,5 +1,4 @@
use crate::FlowyError;
use flowy_error_code::ErrorCode;
use crate::{ErrorCode, FlowyError};
use http_flowy::errors::{ErrorCode as ServerErrorCode, ServerError};
impl std::convert::From<ServerError> for FlowyError {
@ -15,7 +14,7 @@ fn server_error_to_flowy_error(code: ServerErrorCode) -> ErrorCode {
ServerErrorCode::PasswordNotMatch => ErrorCode::PasswordNotMatch,
ServerErrorCode::RecordNotFound => ErrorCode::RecordNotFound,
ServerErrorCode::ConnectRefused | ServerErrorCode::ConnectTimeout | ServerErrorCode::ConnectClose => {
ErrorCode::ConnectError
ErrorCode::HttpServerConnectError
}
_ => ErrorCode::Internal,
}

View File

@ -1,6 +1,7 @@
mod code;
mod errors;
mod ext;
pub mod protobuf;
pub use code::*;
pub use errors::*;
pub use flowy_error_code::ErrorCode;

View File

@ -7,9 +7,9 @@ edition = "2018"
[dependencies]
folder-rev-model = { path = "../../../shared-lib/folder-rev-model" }
flowy-sync = { path = "../../../shared-lib/flowy-sync" }
flowy-sync = { path = "../flowy-sync"}
flowy-http-model = { path = "../../../shared-lib/flowy-http-model" }
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-derive = { path = "../flowy-derive" }
lib-ot = { path = "../../../shared-lib/lib-ot" }
lib-infra = { path = "../../../shared-lib/lib-infra" }
@ -35,14 +35,14 @@ serde = { version = "1.0", features = ["derive"] }
tracing = { version = "0.1", features = ["log"] }
bytes = { version = "1.0" }
unicode-segmentation = "1.8"
serde_json = "1.0"
[dev-dependencies]
serde_json = "1.0"
flowy-folder = { path = "../flowy-folder", features = ["flowy_unit_test"]}
flowy-test = { path = "../flowy-test" }
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}
[features]

View File

@ -26,7 +26,8 @@ use crate::services::clear_current_workspace;
use crate::services::persistence::rev_sqlite::SQLiteFolderRevisionPersistence;
use flowy_http_model::ws_data::ServerRevisionWSData;
use flowy_sync::client_folder::FolderPad;
use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc};
use std::convert::TryFrom;
use std::{collections::HashMap, fmt::Formatter, sync::Arc};
use tokio::sync::RwLock as TokioRwLock;
lazy_static! {
static ref INIT_FOLDER_FLAG: TokioRwLock<HashMap<String, bool>> = TokioRwLock::new(HashMap::new());
@ -139,7 +140,7 @@ impl FolderManager {
// }
pub async fn did_receive_ws_data(&self, data: Bytes) {
let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into();
let result = ServerRevisionWSData::try_from(data);
match result {
Ok(data) => match self.folder_editor.read().await.clone() {
None => {}

View File

@ -124,7 +124,7 @@ impl FolderRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: TextRevisionState = changeset.state.clone().into();
let filter = dsl::rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::doc_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -16,7 +16,7 @@ use crate::{
};
use bytes::Bytes;
use flowy_database::kv::KV;
use flowy_http_model::document::DocumentIdPB;
use flowy_http_model::document::DocumentId;
use folder_rev_model::{gen_view_id, ViewRevision};
use futures::{FutureExt, StreamExt};
use std::{collections::HashSet, sync::Arc};
@ -201,7 +201,7 @@ impl ViewController {
}
#[tracing::instrument(level = "debug", skip(self,params), fields(doc_id = %params.value), err)]
pub(crate) async fn move_view_to_trash(&self, params: DocumentIdPB) -> Result<(), FlowyError> {
pub(crate) async fn move_view_to_trash(&self, params: DocumentId) -> Result<(), FlowyError> {
let view_id = params.value;
if let Some(latest_view_id) = KV::get_str(LATEST_VIEW_ID) {
if latest_view_id == view_id {

View File

@ -3,7 +3,7 @@ use bytes::Bytes;
use flowy_database::ConnectionPool;
use flowy_error::{FlowyError, FlowyResult};
use flowy_http_model::revision::{Revision, RevisionRange};
use flowy_http_model::ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSDataType};
use flowy_http_model::ws_data::{ClientRevisionWSData, NewDocumentUser};
use flowy_revision::*;
use flowy_sync::client_folder::FolderPad;
use flowy_sync::server_folder::FolderOperations;
@ -130,14 +130,14 @@ impl FolderRevisionWSDataStream {
}
impl RevisionWSDataStream for FolderRevisionWSDataStream {
fn receive_push_revision(&self, bytes: Bytes) -> BoxResultFuture<(), FlowyError> {
fn receive_push_revision(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), FlowyError> {
let resolver = self.conflict_controller.clone();
Box::pin(async move { resolver.receive_bytes(bytes).await })
Box::pin(async move { resolver.receive_revisions(revisions).await })
}
fn receive_ack(&self, id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError> {
fn receive_ack(&self, rev_id: i64) -> BoxResultFuture<(), FlowyError> {
let resolver = self.conflict_controller.clone();
Box::pin(async move { resolver.ack_revision(id, ty).await })
Box::pin(async move { resolver.ack_revision(rev_id).await })
}
fn receive_new_user_connect(&self, _new_user: NewDocumentUser) -> BoxResultFuture<(), FlowyError> {

View File

@ -15,8 +15,6 @@ use flowy_folder::entities::{
};
use flowy_folder::event_map::FolderEvent::*;
use flowy_folder::{errors::ErrorCode, services::folder_editor::FolderEditor};
use flowy_http_model::document::DocumentPayloadPB;
use flowy_revision::disk::RevisionState;
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_test::{event_builder::*, FlowySDKTest};
@ -413,17 +411,6 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec<String>) {
.await;
}
#[allow(dead_code)]
pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> DocumentPayloadPB {
let view_id: ViewIdPB = view_id.into();
FolderEventBuilder::new(sdk.clone())
.event(SetLatestView)
.payload(view_id)
.async_send()
.await
.parse::<DocumentPayloadPB>()
}
pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrashPB {
FolderEventBuilder::new(sdk.clone())
.event(ReadTrash)

View File

@ -11,11 +11,11 @@ dart-notify = { path = "../dart-notify" }
flowy-revision = { path = "../flowy-revision" }
flowy-task= { path = "../flowy-task" }
flowy-error = { path = "../flowy-error", features = ["db"]}
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-derive = { path = "../flowy-derive" }
lib-ot = { path = "../../../shared-lib/lib-ot" }
lib-infra = { path = "../../../shared-lib/lib-infra" }
grid-rev-model = { path = "../../../shared-lib/grid-rev-model" }
flowy-sync = { path = "../../../shared-lib/flowy-sync" }
flowy-sync = { path = "../flowy-sync"}
flowy-http-model = { path = "../../../shared-lib/flowy-http-model" }
flowy-database = { path = "../flowy-database" }
anyhow = "1.0"
@ -52,9 +52,7 @@ flowy-test = { path = "../flowy-test" }
flowy-grid = { path = "../flowy-grid", features = ["flowy_unit_test"]}
[build-dependencies]
flowy-codegen= { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}
[features]
default = []

View File

@ -7,8 +7,8 @@ use crate::services::cell::{
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
use crate::services::field::{
CheckboxCellData, ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB, StrCellData,
TypeOption, TypeOptionCellData, TypeOptionTransform,
CheckboxCellData, ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB, TypeOption,
TypeOptionCellData, TypeOptionTransform,
};
use bytes::Bytes;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};

View File

@ -2,7 +2,7 @@
mod tests {
use crate::entities::FieldType;
use crate::services::cell::stringify_cell_data;
use crate::services::cell::CellDataDecoder;
use crate::services::field::FieldBuilder;
use crate::services::field::*;

View File

@ -124,7 +124,7 @@ impl GridMetaRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: GridBlockRevisionState = changeset.state.clone().into();
let filter = dsl::grid_meta_rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::object_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -123,7 +123,7 @@ impl GridRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: GridRevisionState = changeset.state.clone().into();
let filter = dsl::grid_rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::object_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -123,7 +123,7 @@ impl GridViewRevisionSql {
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: GridViewRevisionState = changeset.state.clone().into();
let filter = dsl::grid_view_rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::rev_id.eq(changeset.rev_id))
.filter(dsl::object_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(

View File

@ -8,8 +8,8 @@ edition = "2018"
[dependencies]
lib-dispatch = { path = "../lib-dispatch" }
flowy-error = { path = "../flowy-error", features = ["collaboration", "http_server"] }
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
flowy-sync = { path = "../../../shared-lib/flowy-sync"}
flowy-derive = { path = "../flowy-derive" }
flowy-sync = { path = "../flowy-sync"}
flowy-http-model = { path = "../../../shared-lib/flowy-http-model"}
folder-rev-model = { path = "../../../shared-lib/folder-rev-model"}
flowy-folder = { path = "../flowy-folder" }
@ -48,4 +48,4 @@ dart = [
]
[build-dependencies]
flowy-codegen = { path = "../../../shared-lib/flowy-codegen"}
flowy-codegen = { path = "../flowy-codegen"}

View File

@ -4,7 +4,7 @@ use crate::{
};
use flowy_document::DocumentCloudService;
use flowy_error::FlowyError;
use flowy_http_model::document::{CreateDocumentParams, DocumentIdPB, DocumentPayloadPB, ResetDocumentParams};
use flowy_http_model::document::{CreateDocumentParams, DocumentId, DocumentPayload, ResetDocumentParams};
use http_flowy::response::FlowyResponse;
use lazy_static::lazy_static;
use lib_infra::future::FutureResult;
@ -27,7 +27,7 @@ impl DocumentCloudService for DocumentCloudServiceImpl {
FutureResult::new(async move { create_document_request(&token, params, &url).await })
}
fn fetch_document(&self, token: &str, params: DocumentIdPB) -> FutureResult<Option<DocumentPayloadPB>, FlowyError> {
fn fetch_document(&self, token: &str, params: DocumentId) -> FutureResult<Option<DocumentPayload>, FlowyError> {
let token = token.to_owned();
let url = self.config.doc_url();
FutureResult::new(async move { read_document_request(&token, params, &url).await })
@ -44,7 +44,7 @@ pub async fn create_document_request(token: &str, params: CreateDocumentParams,
let _ = request_builder()
.post(url)
.header(HEADER_TOKEN, token)
.protobuf(params)?
.json(params)?
.send()
.await?;
Ok(())
@ -52,14 +52,14 @@ pub async fn create_document_request(token: &str, params: CreateDocumentParams,
pub async fn read_document_request(
token: &str,
params: DocumentIdPB,
params: DocumentId,
url: &str,
) -> Result<Option<DocumentPayloadPB>, FlowyError> {
) -> Result<Option<DocumentPayload>, FlowyError> {
let doc = request_builder()
.get(url)
.header(HEADER_TOKEN, token)
.protobuf(params)?
.option_response()
.json(params)?
.option_json_response()
.await?;
Ok(doc)
@ -69,7 +69,7 @@ pub async fn reset_doc_request(token: &str, params: ResetDocumentParams, url: &s
let _ = request_builder()
.patch(url)
.header(HEADER_TOKEN, token)
.protobuf(params)?
.json(params)?
.send()
.await?;
Ok(())

View File

@ -1,6 +1,6 @@
use flowy_http_model::document::DocumentPayloadPB;
use flowy_http_model::document::DocumentPayload;
use flowy_http_model::folder::FolderInfo;
use flowy_http_model::revision::{RepeatedRevision, Revision};
use flowy_http_model::revision::Revision;
use flowy_sync::{
errors::CollaborateError,
server_document::*,
@ -16,18 +16,14 @@ use std::{
// For the moment, we use memory to cache the data, it will be implemented with
// other storage. Like the Firestore,Dropbox.etc.
pub trait RevisionCloudStorage: Send + Sync {
fn set_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError>;
fn set_revisions(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError>;
fn get_revisions(
&self,
object_id: &str,
rev_ids: Option<Vec<i64>>,
) -> BoxResultFuture<RepeatedRevision, CollaborateError>;
) -> BoxResultFuture<Vec<Revision>, CollaborateError>;
fn reset_object(
&self,
object_id: &str,
repeated_revision: RepeatedRevision,
) -> BoxResultFuture<(), CollaborateError>;
fn reset_object(&self, object_id: &str, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError>;
}
pub(crate) struct LocalDocumentCloudPersistence {
@ -53,8 +49,8 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence {
let storage = self.storage.clone();
let folder_id = folder_id.to_owned();
Box::pin(async move {
let repeated_revision = storage.get_revisions(&folder_id, None).await?;
match make_folder_from_revisions_pb(&folder_id, repeated_revision)? {
let revisions = storage.get_revisions(&folder_id, None).await?;
match make_folder_from_revisions_pb(&folder_id, revisions)? {
Some(folder_info) => Ok(folder_info),
None => Err(CollaborateError::record_not_found()),
}
@ -65,20 +61,20 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence {
&self,
_user_id: &str,
folder_id: &str,
repeated_revision: RepeatedRevision,
revisions: Vec<Revision>,
) -> BoxResultFuture<Option<FolderInfo>, CollaborateError> {
let folder_id = folder_id.to_owned();
let storage = self.storage.clone();
Box::pin(async move {
let _ = storage.set_revisions(repeated_revision.clone()).await?;
make_folder_from_revisions_pb(&folder_id, repeated_revision)
let _ = storage.set_revisions(revisions.clone()).await?;
make_folder_from_revisions_pb(&folder_id, revisions)
})
}
fn save_folder_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> {
fn save_folder_revisions(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
let storage = self.storage.clone();
Box::pin(async move {
let _ = storage.set_revisions(repeated_revision).await?;
let _ = storage.set_revisions(revisions).await?;
Ok(())
})
}
@ -90,28 +86,21 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence {
) -> BoxResultFuture<Vec<Revision>, CollaborateError> {
let folder_id = folder_id.to_owned();
let storage = self.storage.clone();
Box::pin(async move {
let repeated_revision = storage.get_revisions(&folder_id, rev_ids).await?;
Ok(repeated_revision.into_inner())
})
Box::pin(async move { storage.get_revisions(&folder_id, rev_ids).await })
}
fn reset_folder(
&self,
folder_id: &str,
repeated_revision: RepeatedRevision,
) -> BoxResultFuture<(), CollaborateError> {
fn reset_folder(&self, folder_id: &str, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
let storage = self.storage.clone();
let folder_id = folder_id.to_owned();
Box::pin(async move {
let _ = storage.reset_object(&folder_id, repeated_revision).await?;
let _ = storage.reset_object(&folder_id, revisions).await?;
Ok(())
})
}
}
impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
fn read_document(&self, doc_id: &str) -> BoxResultFuture<DocumentPayloadPB, CollaborateError> {
fn read_document(&self, doc_id: &str) -> BoxResultFuture<DocumentPayload, CollaborateError> {
let storage = self.storage.clone();
let doc_id = doc_id.to_owned();
Box::pin(async move {
@ -126,13 +115,13 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
fn create_document(
&self,
doc_id: &str,
repeated_revision: RepeatedRevision,
) -> BoxResultFuture<Option<DocumentPayloadPB>, CollaborateError> {
revisions: Vec<Revision>,
) -> BoxResultFuture<Option<DocumentPayload>, CollaborateError> {
let doc_id = doc_id.to_owned();
let storage = self.storage.clone();
Box::pin(async move {
let _ = storage.set_revisions(repeated_revision.clone()).await?;
make_document_from_revision_pbs(&doc_id, repeated_revision)
let _ = storage.set_revisions(revisions.clone()).await?;
make_document_from_revision_pbs(&doc_id, revisions)
})
}
@ -143,21 +132,18 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
) -> BoxResultFuture<Vec<Revision>, CollaborateError> {
let doc_id = doc_id.to_owned();
let storage = self.storage.clone();
Box::pin(async move {
let repeated_revision = storage.get_revisions(&doc_id, rev_ids).await?;
Ok(repeated_revision.into_inner())
})
Box::pin(async move { storage.get_revisions(&doc_id, rev_ids).await })
}
fn save_document_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> {
fn save_document_revisions(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
let storage = self.storage.clone();
Box::pin(async move {
let _ = storage.set_revisions(repeated_revision).await?;
let _ = storage.set_revisions(revisions).await?;
Ok(())
})
}
fn reset_document(&self, doc_id: &str, revisions: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> {
fn reset_document(&self, doc_id: &str, revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
let storage = self.storage.clone();
let doc_id = doc_id.to_owned();
Box::pin(async move {
@ -170,26 +156,19 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
#[derive(Default)]
struct MemoryDocumentCloudStorage {}
impl RevisionCloudStorage for MemoryDocumentCloudStorage {
fn set_revisions(&self, _repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> {
fn set_revisions(&self, _revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
Box::pin(async move { Ok(()) })
}
fn get_revisions(
&self,
_doc_id: &str,
_object_id: &str,
_rev_ids: Option<Vec<i64>>,
) -> BoxResultFuture<RepeatedRevision, CollaborateError> {
Box::pin(async move {
let repeated_revisions = RepeatedRevision::default();
Ok(repeated_revisions)
})
) -> BoxResultFuture<Vec<Revision>, CollaborateError> {
Box::pin(async move { Ok(vec![]) })
}
fn reset_object(
&self,
_doc_id: &str,
_repeated_revision: RepeatedRevision,
) -> BoxResultFuture<(), CollaborateError> {
fn reset_object(&self, _object_id: &str, _revisions: Vec<Revision>) -> BoxResultFuture<(), CollaborateError> {
Box::pin(async move { Ok(()) })
}
}

View File

@ -131,7 +131,7 @@ impl LocalWebSocketRunner {
tracing::trace!(
"[LocalFolderServer] receive: {}:{}-{:?} ",
client_data.object_id,
client_data.id(),
client_data.rev_id,
client_data.ty,
);
let client_ws_sender = self.client_ws_sender.clone();
@ -141,19 +141,12 @@ impl LocalWebSocketRunner {
channel: WSChannel::Folder,
});
let ty = client_data.ty.clone();
let document_client_data: ClientRevisionWSDataPB = client_data.try_into().unwrap();
match ty {
ClientRevisionWSDataType::ClientPushRev => {
let _ = self
.folder_manager
.handle_client_revisions(user, document_client_data)
.await?;
let _ = self.folder_manager.handle_client_revisions(user, client_data).await?;
}
ClientRevisionWSDataType::ClientPing => {
let _ = self
.folder_manager
.handle_client_ping(user, document_client_data)
.await?;
let _ = self.folder_manager.handle_client_ping(user, client_data).await?;
}
}
Ok(())
@ -167,7 +160,7 @@ impl LocalWebSocketRunner {
tracing::trace!(
"[LocalDocumentServer] receive: {}:{}-{:?} ",
client_data.object_id,
client_data.id(),
client_data.rev_id,
client_data.ty,
);
let client_ws_sender = self.client_ws_sender.clone();
@ -177,16 +170,12 @@ impl LocalWebSocketRunner {
channel: WSChannel::Document,
});
let ty = client_data.ty.clone();
let document_client_data: ClientRevisionWSDataPB = client_data.try_into().unwrap();
match ty {
ClientRevisionWSDataType::ClientPushRev => {
let _ = self
.doc_manager
.handle_client_revisions(user, document_client_data)
.await?;
let _ = self.doc_manager.handle_client_revisions(user, client_data).await?;
}
ClientRevisionWSDataType::ClientPing => {
let _ = self.doc_manager.handle_client_ping(user, document_client_data).await?;
let _ = self.doc_manager.handle_client_ping(user, client_data).await?;
}
}
Ok(())
@ -253,8 +242,7 @@ use flowy_folder::entities::{
view::{CreateViewParams, RepeatedViewIdPB, UpdateViewParams, ViewIdPB},
workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdPB},
};
use flowy_http_model::document::{CreateDocumentParams, DocumentIdPB, DocumentPayloadPB, ResetDocumentParams};
use flowy_http_model::protobuf::ClientRevisionWSData as ClientRevisionWSDataPB;
use flowy_http_model::document::{CreateDocumentParams, DocumentId, DocumentPayload, ResetDocumentParams};
use flowy_http_model::ws_data::{ClientRevisionWSData, ClientRevisionWSDataType};
use flowy_user::entities::{
SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfilePB,
@ -414,11 +402,7 @@ impl DocumentCloudService for LocalServer {
FutureResult::new(async { Ok(()) })
}
fn fetch_document(
&self,
_token: &str,
_params: DocumentIdPB,
) -> FutureResult<Option<DocumentPayloadPB>, FlowyError> {
fn fetch_document(&self, _token: &str, _params: DocumentId) -> FutureResult<Option<DocumentPayload>, FlowyError> {
FutureResult::new(async { Ok(None) })
}

View File

@ -88,6 +88,14 @@ impl HttpRequestBuilder {
self.bytes(body)
}
pub fn json<T>(self, body: T) -> Result<Self, ServerError>
where
T: serde::Serialize,
{
let bytes = Bytes::from(serde_json::to_vec(&body)?);
self.bytes(bytes)
}
pub fn bytes(mut self, body: Bytes) -> Result<Self, ServerError> {
self.body = Some(body);
Ok(self)
@ -109,7 +117,8 @@ impl HttpRequestBuilder {
}
}
pub async fn option_response<T>(self) -> Result<Option<T>, ServerError>
#[allow(dead_code)]
pub async fn option_protobuf_response<T>(self) -> Result<Option<T>, ServerError>
where
T: TryFrom<Bytes, Error = ProtobufError>,
{
@ -126,6 +135,23 @@ impl HttpRequestBuilder {
}
}
pub async fn option_json_response<T>(self) -> Result<Option<T>, ServerError>
where
T: serde::de::DeserializeOwned + 'static,
{
let result = self.inner_send().await;
match result {
Ok(builder) => match builder.response {
None => Err(unexpected_empty_payload(&builder.url)),
Some(data) => Ok(Some(serde_json::from_slice(&data)?)),
},
Err(error) => match error.is_record_not_found() {
true => Ok(None),
false => Err(error),
},
}
}
fn token(&self) -> Option<String> {
match self.headers.get(HEADER_TOKEN) {
None => None,

View File

@ -1,5 +1,5 @@
use flowy_error::{FlowyError, FlowyResult};
use flowy_http_model::revision::{RevId, Revision, RevisionRange};
use flowy_http_model::revision::{Revision, RevisionRange};
use std::fmt::Debug;
use std::sync::Arc;
@ -106,7 +106,7 @@ impl SyncRecord {
pub struct RevisionChangeset {
pub object_id: String,
pub rev_id: RevId,
pub rev_id: i64,
pub state: RevisionState,
}

View File

@ -1,12 +1,9 @@
use crate::{RevisionMD5, RevisionManager};
use bytes::Bytes;
use flowy_error::{FlowyError, FlowyResult};
use flowy_http_model::{
revision::{RepeatedRevision, Revision, RevisionRange},
ws_data::ServerRevisionWSDataType,
};
use flowy_http_model::revision::{Revision, RevisionRange};
use lib_infra::future::BoxResultFuture;
use std::{convert::TryFrom, sync::Arc};
use std::sync::Arc;
pub struct TransformOperations<Operations> {
pub client_operations: Operations,
@ -36,7 +33,7 @@ where
pub trait ConflictRevisionSink: Send + Sync + 'static {
fn send(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), FlowyError>;
fn ack(&self, rev_id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError>;
fn ack(&self, rev_id: i64) -> BoxResultFuture<(), FlowyError>;
}
pub struct ConflictController<Operations, Connection>
@ -75,13 +72,12 @@ where
Operations: OperationsSerializer + OperationsDeserializer<Operations> + Clone + Send + Sync,
Connection: Send + Sync + 'static,
{
pub async fn receive_bytes(&self, bytes: Bytes) -> FlowyResult<()> {
let repeated_revision = RepeatedRevision::try_from(bytes)?;
if repeated_revision.is_empty() {
pub async fn receive_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<()> {
if revisions.is_empty() {
return Ok(());
}
match self.handle_revision(repeated_revision).await? {
match self.handle_revision(revisions).await? {
None => {}
Some(server_revision) => {
self.rev_sink.send(vec![server_revision]).await?;
@ -90,8 +86,8 @@ where
Ok(())
}
pub async fn ack_revision(&self, rev_id: String, ty: ServerRevisionWSDataType) -> FlowyResult<()> {
let _ = self.rev_sink.ack(rev_id, ty).await?;
pub async fn ack_revision(&self, rev_id: i64) -> FlowyResult<()> {
let _ = self.rev_sink.ack(rev_id).await?;
Ok(())
}
@ -101,8 +97,7 @@ where
Ok(())
}
async fn handle_revision(&self, repeated_revision: RepeatedRevision) -> FlowyResult<Option<Revision>> {
let mut revisions = repeated_revision.into_inner();
async fn handle_revision(&self, mut revisions: Vec<Revision>) -> FlowyResult<Option<Revision>> {
let first_revision = revisions.first().unwrap();
if let Some(local_revision) = self.rev_manager.get_revision(first_revision.rev_id).await {
if local_revision.md5 == first_revision.md5 {

View File

@ -1,15 +1,13 @@
use crate::ConflictRevisionSink;
use async_stream::stream;
use bytes::Bytes;
use flowy_error::{FlowyError, FlowyResult};
use flowy_http_model::{
revision::{RevId, Revision, RevisionRange},
ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSData, ServerRevisionWSDataType},
};
use flowy_http_model::revision::{Revision, RevisionRange};
use flowy_http_model::ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSData, WSRevisionPayload};
use futures_util::{future::BoxFuture, stream::StreamExt};
use lib_infra::future::{BoxResultFuture, FutureResult};
use lib_ws::WSConnectState;
use std::{collections::VecDeque, convert::TryFrom, fmt::Formatter, sync::Arc};
use std::{collections::VecDeque, fmt::Formatter, sync::Arc};
use tokio::{
sync::{
broadcast, mpsc,
@ -21,8 +19,8 @@ use tokio::{
// The consumer consumes the messages pushed by the web socket.
pub trait RevisionWSDataStream: Send + Sync {
fn receive_push_revision(&self, bytes: Bytes) -> BoxResultFuture<(), FlowyError>;
fn receive_ack(&self, id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError>;
fn receive_push_revision(&self, revisions: Vec<Revision>) -> BoxResultFuture<(), FlowyError>;
fn receive_ack(&self, rev_id: i64) -> BoxResultFuture<(), FlowyError>;
fn receive_new_user_connect(&self, new_user: NewDocumentUser) -> BoxResultFuture<(), FlowyError>;
fn pull_revisions_in_range(&self, range: RevisionRange) -> BoxResultFuture<(), FlowyError>;
}
@ -214,26 +212,22 @@ impl RevisionWSStream {
}
async fn handle_message(&self, msg: ServerRevisionWSData) -> FlowyResult<()> {
let ServerRevisionWSData { object_id, ty, data } = msg;
let bytes = Bytes::from(data);
match ty {
ServerRevisionWSDataType::ServerPushRev => {
tracing::trace!("[{}]: new push revision: {}:{:?}", self, object_id, ty);
let _ = self.consumer.receive_push_revision(bytes).await?;
let ServerRevisionWSData { object_id, payload } = msg;
match payload {
WSRevisionPayload::ServerPushRev { revisions } => {
tracing::trace!("[{}]: new push revision: {}", self, object_id);
let _ = self.consumer.receive_push_revision(revisions).await?;
}
ServerRevisionWSDataType::ServerPullRev => {
let range = RevisionRange::try_from(bytes)?;
tracing::trace!("[{}]: new pull: {}:{}-{:?}", self, object_id, range, ty);
WSRevisionPayload::ServerPullRev { range } => {
tracing::trace!("[{}]: new pull: {}:{:?}", self, object_id, range);
let _ = self.consumer.pull_revisions_in_range(range).await?;
}
ServerRevisionWSDataType::ServerAck => {
let rev_id = RevId::try_from(bytes).unwrap().value;
tracing::trace!("[{}]: new ack: {}:{}-{:?}", self, object_id, rev_id, ty);
let _ = self.consumer.receive_ack(rev_id.to_string(), ty).await;
WSRevisionPayload::ServerAck { rev_id } => {
tracing::trace!("[{}]: new ack: {}:{}", self, object_id, rev_id);
let _ = self.consumer.receive_ack(rev_id).await;
}
ServerRevisionWSDataType::UserConnect => {
let new_user = NewDocumentUser::try_from(bytes)?;
let _ = self.consumer.receive_new_user_connect(new_user).await;
WSRevisionPayload::UserConnect { user } => {
let _ = self.consumer.receive_new_user_connect(user).await;
}
}
Ok(())
@ -309,7 +303,7 @@ impl RevisionWSSink {
Ok(())
}
Some(data) => {
tracing::trace!("[{}]: send {}:{}-{:?}", self, data.object_id, data.id(), data.ty);
tracing::trace!("[{}]: send {}:{}-{:?}", self, data.object_id, data.rev_id, data.ty);
self.rev_web_socket.send(data).await
}
}
@ -397,18 +391,17 @@ impl WSDataProvider {
data
}
pub async fn ack_data(&self, id: String, _ty: ServerRevisionWSDataType) -> FlowyResult<()> {
pub async fn ack_data(&self, rev_id: i64) -> FlowyResult<()> {
let source = self.current_source.read().await.clone();
match source {
Source::Custom => {
let should_pop = match self.rev_ws_data_list.read().await.front() {
None => false,
Some(val) => {
let expected_id = val.id();
if expected_id == id {
if val.rev_id == rev_id {
true
} else {
tracing::error!("The front element's {} is not equal to the {}", expected_id, id);
tracing::error!("The front element's {} is not equal to the {}", val.rev_id, rev_id);
false
}
}
@ -419,9 +412,6 @@ impl WSDataProvider {
Ok(())
}
Source::Revision => {
let rev_id = id.parse::<i64>().map_err(|e| {
FlowyError::internal().context(format!("Parse {} rev_id from {} failed. {}", self.object_id, id, e))
})?;
let _ = self.data_source.ack_revision(rev_id).await?;
Ok::<(), FlowyError>(())
}
@ -439,8 +429,8 @@ impl ConflictRevisionSink for Arc<WSDataProvider> {
})
}
fn ack(&self, rev_id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError> {
fn ack(&self, rev_id: i64) -> BoxResultFuture<(), FlowyError> {
let sink = self.clone();
Box::pin(async move { sink.ack_data(rev_id, ty).await })
Box::pin(async move { sink.ack_data(rev_id).await })
}
}

View File

@ -205,7 +205,7 @@ impl RevisionDiskCache<RevisionConnectionMock> for RevisionDiskCacheMock {
.records
.write()
.iter_mut()
.find(|record| record.revision.rev_id == *changeset.rev_id.as_ref())
.find(|record| record.revision.rev_id == changeset.rev_id)
{
record.state = changeset.state;
}

View File

@ -6,12 +6,12 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lib-ot = { path = "../lib-ot" }
lib-infra = { path = "../lib-infra" }
lib-ot = { path = "../../../shared-lib/lib-ot" }
lib-infra = { path = "../../../shared-lib/lib-infra" }
flowy-derive = { path = "../flowy-derive" }
folder-rev-model = { path = "../folder-rev-model" }
grid-rev-model = { path = "../grid-rev-model" }
flowy-http-model= { path = "../flowy-http-model" }
folder-rev-model = { path = "../../../shared-lib/folder-rev-model" }
grid-rev-model = { path = "../../../shared-lib/grid-rev-model" }
flowy-http-model = { path = "../../../shared-lib/flowy-http-model" }
protobuf = {version = "2.18.0"}
bytes = "1.0"
log = "0.4.14"

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