mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: show loading indicator when loading data from remote (#3120)
* chore: show circle indicator if fetch the data from remote * chore: fix the lb warnings * chore: create sdk-build for macOS
This commit is contained in:
@ -1,108 +0,0 @@
|
||||
# AppFlowy Cloud Architecture
|
||||
|
||||
AppFlowy supports multiple cloud solutions. Users can choose their preferred cloud provider, such as Supabase, Firebase,
|
||||
AWS, or our own AppFlowyCloud (Self-hosted server).
|
||||
|
||||

|
||||
|
||||
## Design
|
||||
|
||||
AppFlowy use the traits [AppFlowyServer] to abstract the cloud provider. Each cloud provider implements the [AppFlowyServer]
|
||||
trait. As the image below shows. Users can choose their preferred cloud provider or simply use the default option, which is the LocalServer. When using the
|
||||
LocalServer, data is stored on the local file system. Users can migrate to a cloud provider if needed. For instance, one
|
||||
could migrate from LocalServer to AppFlowyCloud. This migration would create a new user in the cloud and transfer all the
|
||||
data from the local database to the cloud.
|
||||
|
||||

|
||||
|
||||
## AppFlowy Cloud Implementation (WIP)
|
||||
|
||||
### Restful API
|
||||
|
||||
### Table schema
|
||||
|
||||
## Supabase Implementation
|
||||
|
||||
### Table schema
|
||||

|
||||
|
||||
1. `af_roles` table: This table contains a list of roles that are used in your application, such as 'Owner', 'Member', and 'Guest'.
|
||||
|
||||
2. `af_permissions` table: This table stores permissions that are used in your application. Each permission has a name, a description, and an access level.
|
||||
|
||||
3. `af_role_permissions` table: This is a many-to-many relation table between roles and permissions. It represents which permissions a role has.
|
||||
|
||||
4. `af_user` table: This stores the details of users like uuid, email, uid, name, created_at. Here, uid is an auto-incrementing integer that uniquely identifies a user.
|
||||
|
||||
5. `af_workspace` table: This table contains all the workspaces. Each workspace has an owner which is associated with the uid of a user in the `af_user` table.
|
||||
|
||||
6. `af_workspace_member` table: This table maintains a list of all the members associated with a workspace and their roles.
|
||||
|
||||
7. `af_collab` and `af_collab_member` tables: These tables store the collaborations and their members respectively. Each collaboration has an owner and a workspace associated with it.
|
||||
|
||||
8. `af_collab_update`, `af_collab_update_document`, `af_collab_update_database`, `af_collab_update_w_database`, `af_collab_update_folder`, `af_database_row_update` tables: These tables are used for handling updates to collaborations.
|
||||
|
||||
9. `af_collab_statistics`, `af_collab_snapshot`, `af_collab_state`: These tables and view are used for maintaining statistics and snapshots of collaborations.
|
||||
|
||||
10. `af_user_profile_view` view: This view is used to get the latest workspace_id for each user.
|
||||
|
||||

|
||||
Here's a detailed description for each of these triggers:
|
||||
|
||||
1. `create_af_workspace_trigger`:
|
||||
|
||||
This trigger is designed to automate the process of workspace creation in the `af_workspace` table after a new user is inserted into the `af_user` table. When a new user is added, this trigger fires and inserts a new record into the `af_workspace` table, setting the `owner_uid` to the UID of the new user.
|
||||
|
||||
2. `manage_af_workspace_member_role_trigger`:
|
||||
|
||||
This trigger helps to manage the roles of workspace members. After an insert operation on the `af_workspace` table, this trigger automatically fires and creates a new record in the `af_workspace_member` table. The new record identifies the user as a member of the workspace with the role 'Owner'. This ensures that every new workspace has an owner.
|
||||
|
||||
3. `insert_into_af_collab_trigger`:
|
||||
|
||||
The purpose of this trigger is to ensure consistency between the `af_collab_update` and `af_collab` tables. When an insert operation is about to be performed on the `af_collab_update` table, this trigger fires before the insert operation. It checks if a corresponding collaboration exists in the `af_collab` table using the oid and uid. If a corresponding collaboration does not exist, the trigger creates one, using the oid, uid, and current timestamp. This way, every collab update operation corresponds to a valid collaboration.
|
||||
|
||||
4. `insert_into_af_collab_member_trigger`:
|
||||
|
||||
This trigger helps to manage the membership of users in collaborations. After a new collaboration is inserted into the `af_collab` table, this trigger fires. It checks if a corresponding collaboration member exists in the `af_collab_member` table. If a corresponding member does not exist, the trigger creates one, using the collaboration id and user id. This ensures that every collaboration has at least one member.
|
||||
|
||||
5. `af_collab_snapshot_update_edit_count_trigger`:
|
||||
|
||||
This trigger is designed to keep track of the number of edits on each collaboration snapshot in the `af_collab_snapshot` table. When an update operation is performed on the `af_collab_snapshot` table, this trigger fires. It increments the `edit_count` of the corresponding record in the `af_collab_snapshot` table by one. This ensures that the application can keep track of how many times each collaboration snapshot has been edited.
|
||||
|
||||
|
||||
### Supabase configuration
|
||||
|
||||
#### Test
|
||||
In order to run the test, you need to set up the .env.test file.
|
||||
```dotenv
|
||||
# Supabase configuration
|
||||
SUPABASE_URL="your-supabase-url"
|
||||
SUPABASE_ANON_KEY="your-supabase-anonymous-key"
|
||||
SUPABASE_KEY="your-supabase-key"
|
||||
SUPABASE_JWT_SECRET="your-supabase-jwt-secret"
|
||||
|
||||
# Supabase Database configuration
|
||||
SUPABASE_DB="your-supabase-db-url"
|
||||
SUPABASE_DB_USER="your-db-username"
|
||||
SUPABASE_DB_PORT="your-db-port"
|
||||
SUPABASE_DB_PASSWORD="your-db-password"
|
||||
```
|
||||
|
||||
1. `SUPABASE_URL`: This is the URL of your Supabase server instance. Your application will use this URL to interact with the Supabase service.
|
||||
|
||||
2. `SUPABASE_ANON_KEY`: This is the anonymous API key from Supabase, used for operations that don't require user authentication. Operations performed with this key are done as the anonymous role in the database.
|
||||
|
||||
3. `SUPABASE_KEY`: This is the API key with higher privileges from Supabase. It is generally used for server-side operations that require more permissions than an anonymous user.
|
||||
|
||||
4. `SUPABASE_JWT_SECRET`: This is the secret used to verify JWT tokens generated by Supabase. JWT or JSON Web Token is a standard method for securely transferring data between parties as a JSON object.
|
||||
|
||||
5. `SUPABASE_DB`: This is the URL for the database your Supabase server instance is using.
|
||||
|
||||
6. `SUPABASE_DB_USER`: This is the username used to authenticate with the Supabase database, in this case, it's 'postgres', which is a common default for PostgreSQL.
|
||||
|
||||
7. `SUPABASE_DB_PORT`: This is the port number where your Supabase database service is accessible. The default PostgreSQL port is 5432, and you are using this default port.
|
||||
|
||||
8. `SUPABASE_DB_PASSWORD`: This is the password used to authenticate the `SUPABASE_DB_USER` with the Supabase database.
|
||||
|
||||
For example, if you want to run the supabase tests located in flowy-test crate. You need to put the `.env.test` file under
|
||||
the flowy-test folder.
|
Binary file not shown.
Before Width: | Height: | Size: 61 KiB |
@ -1,78 +0,0 @@
|
||||
@startuml
|
||||
title "Application"
|
||||
left to right direction
|
||||
package "AppFlowy Application" {
|
||||
[User]
|
||||
}
|
||||
|
||||
cloud "Supabase Server" {
|
||||
[RESTful Component]
|
||||
[Realtime Component]
|
||||
[Postgres DB]
|
||||
}
|
||||
|
||||
database "LocalServer" {
|
||||
[Local Server Component]
|
||||
}
|
||||
|
||||
|
||||
cloud "AppFlowy Cloud Server" {
|
||||
[RESTful Component] as [AppFlowy RESTful Component]
|
||||
[Realtime Component] as [AppFlowy Realtime Component]
|
||||
[Postgres DB] as [AppFlowy Postgres DB]
|
||||
}
|
||||
|
||||
User --> [AppFlowy Application]
|
||||
[AppFlowy Application] --> [Local Server Component] : Connect
|
||||
|
||||
[AppFlowy Application] --> [RESTful Component] : RESTful API Communication
|
||||
[AppFlowy Application] <..> [Realtime Component] : WebSocket Communication
|
||||
|
||||
[AppFlowy Application] --> [AppFlowy RESTful Component] : RESTful API Communication
|
||||
[AppFlowy Application] <..> [AppFlowy Realtime Component] : WebSocket Communication
|
||||
|
||||
@enduml
|
||||
|
||||
|
||||
@startuml
|
||||
left to right direction
|
||||
|
||||
interface AppFlowyServer {
|
||||
+ enable_sync(_enable: bool)
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class SupabaseServer {
|
||||
+ enable_sync(_enable: bool)
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class SelfHostServer {
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class LocalServer {
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
SupabaseServer -u-|> AppFlowyServer
|
||||
SelfHostServer -u-|> AppFlowyServer
|
||||
LocalServer -u-|> AppFlowyServer
|
||||
|
||||
@enduml
|
Binary file not shown.
Before Width: | Height: | Size: 59 KiB |
Binary file not shown.
Before Width: | Height: | Size: 75 KiB |
@ -1,203 +0,0 @@
|
||||
@startuml
|
||||
left to right direction
|
||||
|
||||
entity "af_roles" as roles {
|
||||
id : SERIAL (PK)
|
||||
name : TEXT
|
||||
}
|
||||
|
||||
entity "af_permissions" as permissions {
|
||||
id : SERIAL (PK)
|
||||
name : VARCHAR(255)
|
||||
access_level : INTEGER
|
||||
description : TEXT
|
||||
}
|
||||
|
||||
entity "af_role_permissions" as role_permissions {
|
||||
role_id : INT (FK af_roles.id)
|
||||
permission_id : INT (FK af_permissions.id)
|
||||
--
|
||||
(role_id, permission_id) : PK
|
||||
}
|
||||
|
||||
entity "af_user" as user {
|
||||
uuid : UUID (PK)
|
||||
email : TEXT
|
||||
uid : BIGSERIAL
|
||||
name : TEXT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
entity "af_workspace" as workspace {
|
||||
workspace_id : UUID (PK)
|
||||
database_storage_id : UUID
|
||||
owner_uid : BIGINT (FK af_user.uid)
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
workspace_type : INTEGER
|
||||
workspace_name : TEXT
|
||||
}
|
||||
|
||||
entity "af_workspace_member" as workspace_member {
|
||||
uid : BIGINT
|
||||
role_id : INT (FK af_roles.id)
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
updated_at : TIMESTAMP WITH TIME ZONE
|
||||
--
|
||||
(uid, workspace_id) : PK
|
||||
}
|
||||
|
||||
entity "af_collab" as collab {
|
||||
oid : TEXT (PK)
|
||||
owner_uid : BIGINT
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
access_level : INTEGER
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
entity "af_collab_update" as collab_update {
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
key : BIGSERIAL
|
||||
value : BYTEA
|
||||
value_size : INTEGER
|
||||
partition_key : INTEGER
|
||||
uid : BIGINT
|
||||
md5 : TEXT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
--
|
||||
(oid, key, partition_key) : PK
|
||||
}
|
||||
|
||||
|
||||
entity "af_collab_update_document" as af_collab_update_document {
|
||||
Inherits af_collab_update (partition_key = 0)
|
||||
}
|
||||
|
||||
entity "af_collab_update_database" as af_collab_update_database {
|
||||
Inherits af_collab_update (partition_key = 1)
|
||||
}
|
||||
|
||||
entity "af_collab_update_w_database" as af_collab_update_w_database {
|
||||
Inherits af_collab_update (partition_key = 2)
|
||||
}
|
||||
|
||||
entity "af_collab_update_folder" as af_collab_update_folder {
|
||||
Inherits af_collab_update (partition_key = 3)
|
||||
}
|
||||
|
||||
af_collab_update_document -u-|> collab_update
|
||||
af_collab_update_database -u-|> collab_update
|
||||
af_collab_update_w_database -u-|> collab_update
|
||||
af_collab_update_folder -u-|> collab_update
|
||||
|
||||
entity "af_database_row_update" as database_row_update {
|
||||
oid : TEXT
|
||||
key : BIGSERIAL
|
||||
value : BYTEA
|
||||
value_size : INTEGER
|
||||
partition_key : INTEGER
|
||||
uid : BIGINT
|
||||
md5 : TEXT
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
--
|
||||
(oid, key) : PK
|
||||
}
|
||||
|
||||
entity "af_collab_member" as collab_member {
|
||||
uid : BIGINT (FK af_user.uid)
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
role_id : INTEGER (FK af_roles.id)
|
||||
--
|
||||
(uid, oid) : PK
|
||||
}
|
||||
|
||||
entity "af_collab_statistics" as collab_statistics {
|
||||
oid : TEXT (PK)
|
||||
edit_count : BIGINT
|
||||
}
|
||||
|
||||
entity "af_collab_snapshot" as collab_snapshot {
|
||||
sid : BIGSERIAL (PK)
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
name : TEXT
|
||||
blob : BYTEA
|
||||
blob_size : INTEGER
|
||||
edit_count : BIGINT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
|
||||
roles <-- role_permissions : FK
|
||||
permissions <-u- role_permissions : FK
|
||||
user <-- collab : FK
|
||||
user <-- workspace : FK
|
||||
user <-- collab_member : FK
|
||||
roles <-- workspace_member : FK
|
||||
workspace <-- workspace_member : FK
|
||||
workspace <-- collab : FK
|
||||
workspace <-- database_row_update : FK
|
||||
collab <-- collab_update : FK
|
||||
collab <-- collab_snapshot: FK
|
||||
collab <-u- collab_member : FK
|
||||
collab <-- collab_statistics : PK
|
||||
roles <-- collab_member : FK
|
||||
|
||||
|
||||
@enduml
|
||||
|
||||
@startuml
|
||||
title Triggers in Database Schema
|
||||
|
||||
participant "af_user" as A
|
||||
participant "af_workspace" as B
|
||||
participant "af_workspace_member" as C
|
||||
participant "af_collab" as D
|
||||
participant "af_collab_update" as E
|
||||
participant "af_collab_member" as F
|
||||
participant "af_collab_statistics" as G
|
||||
participant "af_collab_snapshot" as H
|
||||
|
||||
A -> B: create_af_workspace_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_user. It automatically creates a workspace
|
||||
with the uid of the new user as the owner_uid.
|
||||
end note
|
||||
|
||||
B -> C: manage_af_workspace_member_role_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_workspace. It automatically
|
||||
creates a workspace member in the af_workspace_member table with the
|
||||
role 'Owner'.
|
||||
end note
|
||||
|
||||
E -> D: insert_into_af_collab_trigger
|
||||
note right
|
||||
This trigger fires before an insert on af_collab_update.
|
||||
It checks if a corresponding collab exists in the af_collab table.
|
||||
If not, it creates one with the oid, uid, and current timestamp.
|
||||
end note
|
||||
|
||||
D -> F: insert_into_af_collab_member_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab.
|
||||
It automatically adds the collab's owner to the af_collab_member
|
||||
table with the role 'Owner'.
|
||||
end note
|
||||
|
||||
E -> G: af_collab_update_edit_count_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab_update.
|
||||
It increments the edit_count of the corresponding collab in
|
||||
the af_collab_statistics table.
|
||||
end note
|
||||
|
||||
H -> G: af_collab_snapshot_update_edit_count_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab_snapshot.
|
||||
It sets the edit_count of the new snapshot to the current
|
||||
edit_count of the collab in the af_collab_statistics table.
|
||||
end note
|
||||
|
||||
@enduml
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 192 KiB |
@ -21,16 +21,16 @@ use crate::supabase::api::util::{ExtendedResponse, InsertParamsBuilder};
|
||||
use crate::supabase::api::{PostgresWrapper, SupabaseServerService};
|
||||
use crate::supabase::define::*;
|
||||
|
||||
pub struct RESTfulSupabaseCollabStorageImpl<T>(T);
|
||||
pub struct SupabaseCollabStorageImpl<T>(T);
|
||||
|
||||
impl<T> RESTfulSupabaseCollabStorageImpl<T> {
|
||||
impl<T> SupabaseCollabStorageImpl<T> {
|
||||
pub fn new(server: T) -> Self {
|
||||
Self(server)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> RemoteCollabStorage for RESTfulSupabaseCollabStorageImpl<T>
|
||||
impl<T> RemoteCollabStorage for SupabaseCollabStorageImpl<T>
|
||||
where
|
||||
T: SupabaseServerService,
|
||||
{
|
||||
|
@ -12,17 +12,17 @@ use crate::supabase::api::request::{
|
||||
};
|
||||
use crate::supabase::api::SupabaseServerService;
|
||||
|
||||
pub struct RESTfulSupabaseDatabaseServiceImpl<T> {
|
||||
pub struct SupabaseDatabaseServiceImpl<T> {
|
||||
server: T,
|
||||
}
|
||||
|
||||
impl<T> RESTfulSupabaseDatabaseServiceImpl<T> {
|
||||
impl<T> SupabaseDatabaseServiceImpl<T> {
|
||||
pub fn new(server: T) -> Self {
|
||||
Self { server }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DatabaseCloudService for RESTfulSupabaseDatabaseServiceImpl<T>
|
||||
impl<T> DatabaseCloudService for SupabaseDatabaseServiceImpl<T>
|
||||
where
|
||||
T: SupabaseServerService,
|
||||
{
|
||||
|
@ -11,14 +11,14 @@ use lib_infra::future::FutureResult;
|
||||
use crate::supabase::api::request::{get_latest_snapshot_from_server, FetchObjectUpdateAction};
|
||||
use crate::supabase::api::SupabaseServerService;
|
||||
|
||||
pub struct RESTfulSupabaseDocumentServiceImpl<T>(T);
|
||||
impl<T> RESTfulSupabaseDocumentServiceImpl<T> {
|
||||
pub struct SupabaseDocumentServiceImpl<T>(T);
|
||||
impl<T> SupabaseDocumentServiceImpl<T> {
|
||||
pub fn new(server: T) -> Self {
|
||||
Self(server)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DocumentCloudService for RESTfulSupabaseDocumentServiceImpl<T>
|
||||
impl<T> DocumentCloudService for SupabaseDocumentServiceImpl<T>
|
||||
where
|
||||
T: SupabaseServerService,
|
||||
{
|
||||
@ -31,7 +31,7 @@ where
|
||||
async move {
|
||||
let postgrest = try_get_postgrest?;
|
||||
let action = FetchObjectUpdateAction::new(document_id, CollabType::Document, postgrest);
|
||||
action.run_with_fix_interval(5, 5).await
|
||||
action.run_with_fix_interval(5, 10).await
|
||||
}
|
||||
.await,
|
||||
)
|
||||
|
@ -19,15 +19,15 @@ use crate::supabase::api::util::{ExtendedResponse, InsertParamsBuilder};
|
||||
use crate::supabase::api::SupabaseServerService;
|
||||
use crate::supabase::define::*;
|
||||
|
||||
pub struct RESTfulSupabaseFolderServiceImpl<T>(T);
|
||||
pub struct SupabaseFolderServiceImpl<T>(T);
|
||||
|
||||
impl<T> RESTfulSupabaseFolderServiceImpl<T> {
|
||||
impl<T> SupabaseFolderServiceImpl<T> {
|
||||
pub fn new(server: T) -> Self {
|
||||
Self(server)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FolderCloudService for RESTfulSupabaseFolderServiceImpl<T>
|
||||
impl<T> FolderCloudService for SupabaseFolderServiceImpl<T>
|
||||
where
|
||||
T: SupabaseServerService,
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ use chrono::{DateTime, Utc};
|
||||
use collab_plugins::cloud_storage::{CollabObject, CollabType, RemoteCollabSnapshot};
|
||||
use serde_json::Value;
|
||||
use tokio_retry::strategy::FixedInterval;
|
||||
use tokio_retry::{Action, Retry};
|
||||
use tokio_retry::{Action, Condition, RetryIf};
|
||||
|
||||
use flowy_database_deps::cloud::{CollabObjectUpdate, CollabObjectUpdateByOid};
|
||||
use lib_infra::util::md5;
|
||||
@ -34,18 +34,20 @@ impl FetchObjectUpdateAction {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(self) -> Retry<Take<FixedInterval>, FetchObjectUpdateAction> {
|
||||
pub fn run(self) -> RetryIf<Take<FixedInterval>, FetchObjectUpdateAction, RetryCondition> {
|
||||
let postgrest = self.postgrest.clone();
|
||||
let retry_strategy = FixedInterval::new(Duration::from_secs(5)).take(3);
|
||||
Retry::spawn(retry_strategy, self)
|
||||
RetryIf::spawn(retry_strategy, self, RetryCondition(postgrest))
|
||||
}
|
||||
|
||||
pub fn run_with_fix_interval(
|
||||
self,
|
||||
secs: u64,
|
||||
times: usize,
|
||||
) -> Retry<Take<FixedInterval>, FetchObjectUpdateAction> {
|
||||
) -> RetryIf<Take<FixedInterval>, FetchObjectUpdateAction, RetryCondition> {
|
||||
let postgrest = self.postgrest.clone();
|
||||
let retry_strategy = FixedInterval::new(Duration::from_secs(secs)).take(times);
|
||||
Retry::spawn(retry_strategy, self)
|
||||
RetryIf::spawn(retry_strategy, self, RetryCondition(postgrest))
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +91,10 @@ impl BatchFetchObjectUpdateAction {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(self) -> Retry<Take<FixedInterval>, BatchFetchObjectUpdateAction> {
|
||||
pub fn run(self) -> RetryIf<Take<FixedInterval>, BatchFetchObjectUpdateAction, RetryCondition> {
|
||||
let postgrest = self.postgrest.clone();
|
||||
let retry_strategy = FixedInterval::new(Duration::from_secs(5)).take(3);
|
||||
Retry::spawn(retry_strategy, self)
|
||||
RetryIf::spawn(retry_strategy, self, RetryCondition(postgrest))
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,3 +305,10 @@ fn decode_hex_string(s: &str) -> Option<Vec<u8>> {
|
||||
let s = s.strip_prefix("\\x")?;
|
||||
hex::decode(s).ok()
|
||||
}
|
||||
|
||||
pub struct RetryCondition(Weak<PostgresWrapper>);
|
||||
impl Condition<anyhow::Error> for RetryCondition {
|
||||
fn should_retry(&mut self, _error: &anyhow::Error) -> bool {
|
||||
self.0.upgrade().is_some()
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||
use flowy_user_deps::cloud::UserService;
|
||||
|
||||
use crate::supabase::api::{
|
||||
RESTfulPostgresServer, RESTfulSupabaseCollabStorageImpl, RESTfulSupabaseDatabaseServiceImpl,
|
||||
RESTfulSupabaseDocumentServiceImpl, RESTfulSupabaseFolderServiceImpl,
|
||||
RESTfulSupabaseUserAuthServiceImpl, SupabaseServerServiceImpl,
|
||||
RESTfulPostgresServer, RESTfulSupabaseUserAuthServiceImpl, SupabaseCollabStorageImpl,
|
||||
SupabaseDatabaseServiceImpl, SupabaseDocumentServiceImpl, SupabaseFolderServiceImpl,
|
||||
SupabaseServerServiceImpl,
|
||||
};
|
||||
use crate::AppFlowyServer;
|
||||
|
||||
@ -96,25 +96,25 @@ impl AppFlowyServer for SupabaseServer {
|
||||
}
|
||||
|
||||
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
||||
Arc::new(RESTfulSupabaseFolderServiceImpl::new(
|
||||
SupabaseServerServiceImpl(self.restful_postgres.clone()),
|
||||
))
|
||||
Arc::new(SupabaseFolderServiceImpl::new(SupabaseServerServiceImpl(
|
||||
self.restful_postgres.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
||||
Arc::new(RESTfulSupabaseDatabaseServiceImpl::new(
|
||||
SupabaseServerServiceImpl(self.restful_postgres.clone()),
|
||||
))
|
||||
Arc::new(SupabaseDatabaseServiceImpl::new(SupabaseServerServiceImpl(
|
||||
self.restful_postgres.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
|
||||
Arc::new(RESTfulSupabaseDocumentServiceImpl::new(
|
||||
SupabaseServerServiceImpl(self.restful_postgres.clone()),
|
||||
))
|
||||
Arc::new(SupabaseDocumentServiceImpl::new(SupabaseServerServiceImpl(
|
||||
self.restful_postgres.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn collab_storage(&self) -> Option<Arc<dyn RemoteCollabStorage>> {
|
||||
Some(Arc::new(RESTfulSupabaseCollabStorageImpl::new(
|
||||
Some(Arc::new(SupabaseCollabStorageImpl::new(
|
||||
SupabaseServerServiceImpl(self.restful_postgres.clone()),
|
||||
)))
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ use uuid::Uuid;
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_folder_deps::cloud::FolderCloudService;
|
||||
use flowy_server::supabase::api::{
|
||||
RESTfulPostgresServer, RESTfulSupabaseCollabStorageImpl, RESTfulSupabaseDatabaseServiceImpl,
|
||||
RESTfulSupabaseFolderServiceImpl, RESTfulSupabaseUserAuthServiceImpl, SupabaseServerServiceImpl,
|
||||
RESTfulPostgresServer, RESTfulSupabaseUserAuthServiceImpl, SupabaseCollabStorageImpl,
|
||||
SupabaseDatabaseServiceImpl, SupabaseFolderServiceImpl, SupabaseServerServiceImpl,
|
||||
};
|
||||
use flowy_server::supabase::define::{USER_EMAIL, USER_UUID};
|
||||
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||
@ -25,7 +25,7 @@ pub fn get_supabase_config() -> Option<SupabaseConfiguration> {
|
||||
pub fn collab_service() -> Arc<dyn RemoteCollabStorage> {
|
||||
let config = SupabaseConfiguration::from_env().unwrap();
|
||||
let server = Arc::new(RESTfulPostgresServer::new(config));
|
||||
Arc::new(RESTfulSupabaseCollabStorageImpl::new(
|
||||
Arc::new(SupabaseCollabStorageImpl::new(
|
||||
SupabaseServerServiceImpl::new(server),
|
||||
))
|
||||
}
|
||||
@ -33,7 +33,7 @@ pub fn collab_service() -> Arc<dyn RemoteCollabStorage> {
|
||||
pub fn database_service() -> Arc<dyn DatabaseCloudService> {
|
||||
let config = SupabaseConfiguration::from_env().unwrap();
|
||||
let server = Arc::new(RESTfulPostgresServer::new(config));
|
||||
Arc::new(RESTfulSupabaseDatabaseServiceImpl::new(
|
||||
Arc::new(SupabaseDatabaseServiceImpl::new(
|
||||
SupabaseServerServiceImpl::new(server),
|
||||
))
|
||||
}
|
||||
@ -49,7 +49,7 @@ pub fn user_auth_service() -> Arc<dyn UserService> {
|
||||
pub fn folder_service() -> Arc<dyn FolderCloudService> {
|
||||
let config = SupabaseConfiguration::from_env().unwrap();
|
||||
let server = Arc::new(RESTfulPostgresServer::new(config));
|
||||
Arc::new(RESTfulSupabaseFolderServiceImpl::new(
|
||||
Arc::new(SupabaseFolderServiceImpl::new(
|
||||
SupabaseServerServiceImpl::new(server),
|
||||
))
|
||||
}
|
||||
|
Reference in New Issue
Block a user