mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
aae8259f63
commit
aa5f052ecf
@ -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"
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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'
|
||||
|
50
frontend/rust-lib/Cargo.lock
generated
50
frontend/rust-lib/Cargo.lock
generated
@ -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"
|
||||
|
@ -16,6 +16,10 @@ members = [
|
||||
"flowy-revision",
|
||||
"flowy-grid",
|
||||
"flowy-task",
|
||||
"flowy-sync",
|
||||
"flowy-derive",
|
||||
"flowy-ast",
|
||||
"flowy-codegen",
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
|
@ -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",
|
||||
]}
|
||||
|
||||
|
@ -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"}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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!(
|
||||
|
@ -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!(
|
||||
|
@ -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"}
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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 => {}
|
||||
|
@ -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!(
|
||||
|
@ -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 {
|
||||
|
@ -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> {
|
||||
|
@ -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)
|
||||
|
@ -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 = []
|
||||
|
@ -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};
|
||||
|
@ -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::*;
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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!(
|
||||
|
@ -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!(
|
||||
|
@ -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"}
|
||||
|
@ -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(())
|
||||
|
@ -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(()) })
|
||||
}
|
||||
}
|
||||
|
@ -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) })
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user