mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: billing error
This commit is contained in:
@ -73,7 +73,9 @@ Future<FlowyResult<Uint8List, Uint8List>> _extractPayload(
|
||||
case FFIStatusCode.Ok:
|
||||
return FlowySuccess(Uint8List.fromList(response.payload));
|
||||
case FFIStatusCode.Err:
|
||||
return FlowyFailure(Uint8List.fromList(response.payload));
|
||||
final errorBytes = Uint8List.fromList(response.payload);
|
||||
ErrorCodeNotifier.receiveErrorBytes(errorBytes);
|
||||
return FlowyFailure(errorBytes);
|
||||
case FFIStatusCode.Internal:
|
||||
final error = utf8.decode(response.payload);
|
||||
Log.error("Dispatch internal error: $error");
|
||||
|
@ -1,4 +1,8 @@
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/dart-ffi/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class FlowyInternalError {
|
||||
late FFIStatusCode _statusCode;
|
||||
@ -20,15 +24,13 @@ class FlowyInternalError {
|
||||
return "$_statusCode: $_error";
|
||||
}
|
||||
|
||||
FlowyInternalError(
|
||||
{required FFIStatusCode statusCode, required String error}) {
|
||||
FlowyInternalError({
|
||||
required FFIStatusCode statusCode,
|
||||
required String error,
|
||||
}) {
|
||||
_statusCode = statusCode;
|
||||
_error = error;
|
||||
}
|
||||
|
||||
factory FlowyInternalError.from(FFIResponse resp) {
|
||||
return FlowyInternalError(statusCode: resp.code, error: "");
|
||||
}
|
||||
}
|
||||
|
||||
class StackTraceError {
|
||||
@ -48,3 +50,48 @@ class StackTraceError {
|
||||
return '${error.runtimeType}. Stack trace: $trace';
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorCodeNotifier extends ChangeNotifier {
|
||||
// Static instance
|
||||
static final ErrorCodeNotifier _instance = ErrorCodeNotifier._();
|
||||
|
||||
// Factory constructor to return the same instance
|
||||
factory ErrorCodeNotifier() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
FlowyError? _error;
|
||||
|
||||
static void receiveError(FlowyError error) {
|
||||
if (_instance._error?.code != error.code) {
|
||||
_instance._error = error;
|
||||
_instance.notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
static void receiveErrorBytes(Uint8List bytes) {
|
||||
try {
|
||||
final error = FlowyError.fromBuffer(bytes);
|
||||
if (_instance._error?.code != error.code) {
|
||||
_instance._error = error;
|
||||
_instance.notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error("Can not parse error bytes: $e");
|
||||
}
|
||||
}
|
||||
|
||||
static void onError(
|
||||
void Function(FlowyError error) onError,
|
||||
bool Function(ErrorCode code)? onErrorIf,
|
||||
) {
|
||||
_instance.addListener(() {
|
||||
final error = _instance._error;
|
||||
if (error != null) {
|
||||
if (onErrorIf == null || onErrorIf(error.code)) {
|
||||
onError(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
1
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
1
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -2103,6 +2103,7 @@ dependencies = [
|
||||
"client-api",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
]
|
||||
|
||||
|
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -1918,6 +1918,7 @@ dependencies = [
|
||||
"client-api",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
]
|
||||
|
||||
|
@ -414,11 +414,11 @@ impl DatabaseCloudService for ServerProvider {
|
||||
}
|
||||
|
||||
fn summary_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, Error> {
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server();
|
||||
let object_id = object_id.to_string();
|
||||
@ -435,7 +435,7 @@ impl DatabaseCloudService for ServerProvider {
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, Error> {
|
||||
) -> FutureResult<TranslateRowResponse, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server();
|
||||
let language = language.to_string();
|
||||
|
@ -11,3 +11,4 @@ collab-entity = { workspace = true }
|
||||
collab = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
client-api = { workspace = true }
|
||||
flowy-error = { workspace = true }
|
@ -4,6 +4,7 @@ use collab::core::collab::DataSource;
|
||||
use collab_entity::CollabType;
|
||||
use lib_infra::future::FutureResult;
|
||||
use std::collections::HashMap;
|
||||
use flowy_error::FlowyError;
|
||||
|
||||
pub type CollabDocStateByOid = HashMap<String, DataSource>;
|
||||
pub type SummaryRowContent = HashMap<String, String>;
|
||||
@ -40,14 +41,14 @@ pub trait DatabaseCloudService: Send + Sync {
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, Error>;
|
||||
) -> FutureResult<String, FlowyError>;
|
||||
|
||||
fn translate_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, Error>;
|
||||
) -> FutureResult<TranslateRowResponse, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DatabaseSnapshot {
|
||||
|
@ -17,10 +17,11 @@ flowy-derive.workspace = true
|
||||
flowy-notification = { workspace = true }
|
||||
parking_lot.workspace = true
|
||||
protobuf.workspace = true
|
||||
flowy-error = { workspace = true, features = [
|
||||
flowy-error = { path = "../flowy-error", features = [
|
||||
"impl_from_dispatch_error",
|
||||
"impl_from_collab_database",
|
||||
] }
|
||||
]}
|
||||
|
||||
lib-dispatch = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
bytes.workspace = true
|
||||
|
@ -286,6 +286,12 @@ pub enum ErrorCode {
|
||||
|
||||
#[error("Local AI unavailable")]
|
||||
LocalAIUnavailable = 99,
|
||||
|
||||
#[error("File storage limit exceeded")]
|
||||
FileStorageLimitExceeded = 100,
|
||||
|
||||
#[error("AI Response limit exceeded")]
|
||||
AIResponseLimitExceeded = 101,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
|
@ -72,6 +72,14 @@ impl FlowyError {
|
||||
self.code == ErrorCode::LocalVersionNotSupport
|
||||
}
|
||||
|
||||
pub fn is_file_limit_exceeded(&self) -> bool {
|
||||
self.code == ErrorCode::FileStorageLimitExceeded
|
||||
}
|
||||
|
||||
pub fn is_ai_response_limit_exceeded(&self) -> bool {
|
||||
self.code == ErrorCode::AIResponseLimitExceeded
|
||||
}
|
||||
|
||||
static_flowy_error!(internal, ErrorCode::Internal);
|
||||
static_flowy_error!(record_not_found, ErrorCode::RecordNotFound);
|
||||
static_flowy_error!(workspace_initialize, ErrorCode::WorkspaceInitializeError);
|
||||
|
@ -24,6 +24,8 @@ impl From<AppResponseError> for FlowyError {
|
||||
AppErrorCode::UserUnAuthorized => ErrorCode::UserUnauthorized,
|
||||
AppErrorCode::WorkspaceLimitExceeded => ErrorCode::WorkspaceLimitExceeded,
|
||||
AppErrorCode::WorkspaceMemberLimitExceeded => ErrorCode::WorkspaceMemberLimitExceeded,
|
||||
AppErrorCode::AIResponseLimitExceeded => ErrorCode::AIResponseLimitExceeded,
|
||||
AppErrorCode::FileStorageLimitExceeded => ErrorCode::FileStorageLimitExceeded,
|
||||
_ => ErrorCode::Internal,
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@ pub mod reqwest;
|
||||
#[cfg(feature = "impl_from_sqlite")]
|
||||
pub mod database;
|
||||
|
||||
#[cfg(feature = "impl_from_collab_document")]
|
||||
#[cfg(any(feature = "impl_from_collab_document", feature = "impl_from_collab_folder", feature = "impl_from_collab_database"))]
|
||||
pub mod collab;
|
||||
|
||||
#[cfg(feature = "impl_from_collab_persistence")]
|
||||
|
@ -16,6 +16,7 @@ use flowy_database_pub::cloud::{
|
||||
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
|
||||
TranslateRowContent, TranslateRowResponse,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
@ -124,9 +125,9 @@ where
|
||||
fn summary_database_row(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
_object_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, Error> {
|
||||
) -> FutureResult<String, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
@ -148,7 +149,7 @@ where
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, Error> {
|
||||
) -> FutureResult<TranslateRowResponse, FlowyError> {
|
||||
let language = language.to_string();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
|
@ -8,16 +8,17 @@ use flowy_database_pub::cloud::{
|
||||
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
|
||||
TranslateRowContent, TranslateRowResponse,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub(crate) struct LocalServerDatabaseCloudServiceImpl();
|
||||
|
||||
impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
|
||||
fn get_database_object_doc_state(
|
||||
&self,
|
||||
object_id: &str,
|
||||
collab_type: CollabType,
|
||||
_workspace_id: &str,
|
||||
&self,
|
||||
object_id: &str,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<Vec<u8>>, Error> {
|
||||
let object_id = object_id.to_string();
|
||||
// create the minimal required data for the given collab type
|
||||
@ -62,9 +63,9 @@ impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
|
||||
|
||||
fn batch_get_database_object_doc_state(
|
||||
&self,
|
||||
_object_ids: Vec<String>,
|
||||
_object_ty: CollabType,
|
||||
_workspace_id: &str,
|
||||
object_ids: Vec<String>,
|
||||
object_ty: CollabType,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<CollabDocStateByOid, Error> {
|
||||
FutureResult::new(async move { Ok(CollabDocStateByOid::default()) })
|
||||
}
|
||||
@ -79,20 +80,20 @@ impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
|
||||
|
||||
fn summary_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_object_id: &str,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, Error> {
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, FlowyError> {
|
||||
// TODO(lucas): local ai
|
||||
FutureResult::new(async move { Ok("".to_string()) })
|
||||
}
|
||||
|
||||
fn translate_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, Error> {
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, FlowyError> {
|
||||
// TODO(lucas): local ai
|
||||
FutureResult::new(async move { Ok(TranslateRowResponse::default()) })
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use flowy_database_pub::cloud::{
|
||||
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
|
||||
TranslateRowContent, TranslateRowResponse,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
@ -29,10 +30,10 @@ where
|
||||
T: SupabaseServerService,
|
||||
{
|
||||
fn get_database_object_doc_state(
|
||||
&self,
|
||||
object_id: &str,
|
||||
collab_type: CollabType,
|
||||
_workspace_id: &str,
|
||||
&self,
|
||||
object_id: &str,
|
||||
collab_type: CollabType,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<Vec<u8>>, Error> {
|
||||
let try_get_postgrest = self.server.try_get_weak_postgrest();
|
||||
let object_id = object_id.to_string();
|
||||
@ -56,7 +57,7 @@ where
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ty: CollabType,
|
||||
_workspace_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<CollabDocStateByOid, Error> {
|
||||
let try_get_postgrest = self.server.try_get_weak_postgrest();
|
||||
let (tx, rx) = channel();
|
||||
@ -100,19 +101,19 @@ where
|
||||
|
||||
fn summary_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_object_id: &str,
|
||||
_summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, Error> {
|
||||
workspace_id: &str,
|
||||
object_id: &str,
|
||||
summary_row: SummaryRowContent,
|
||||
) -> FutureResult<String, FlowyError> {
|
||||
FutureResult::new(async move { Ok("".to_string()) })
|
||||
}
|
||||
|
||||
fn translate_database_row(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_translate_row: TranslateRowContent,
|
||||
_language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, Error> {
|
||||
workspace_id: &str,
|
||||
translate_row: TranslateRowContent,
|
||||
language: &str,
|
||||
) -> FutureResult<TranslateRowResponse, FlowyError> {
|
||||
FutureResult::new(async move { Ok(TranslateRowResponse::default()) })
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicBool, AtomicU8};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{watch, RwLock};
|
||||
use tracing::{info, trace};
|
||||
use tracing::{error, info, trace};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Signal {
|
||||
@ -128,6 +128,11 @@ impl FileUploader {
|
||||
} => {
|
||||
let record = BoxAny::new(record);
|
||||
if let Err(err) = self.storage_service.start_upload(&chunks, &record).await {
|
||||
if (err.is_file_limit_exceeded()) {
|
||||
error!("Failed to upload file: {}", err);
|
||||
self.pause();
|
||||
}
|
||||
|
||||
info!(
|
||||
"Failed to upload file: {}, retry_count:{}",
|
||||
err, retry_count
|
||||
@ -154,6 +159,11 @@ impl FileUploader {
|
||||
.resume_upload(&workspace_id, &parent_dir, &file_id)
|
||||
.await
|
||||
{
|
||||
if (err.is_file_limit_exceeded()) {
|
||||
error!("Failed to upload file: {}", err);
|
||||
self.pause();
|
||||
}
|
||||
|
||||
info!(
|
||||
"Failed to resume upload file: {}, retry_count:{}",
|
||||
err, retry_count
|
||||
|
Reference in New Issue
Block a user