From 7f44b181bdc560d10c901758ca216a5a30c2ef86 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:22:22 +0800 Subject: [PATCH] feat: integrate client-api (#3430) * chore: update client-api rev * chore: update collab rev id * feat: add sign_in_request and import shared entity * feat: added to userworkspace from af_workspace * chore: add script to update the client-api rev id * chore: update client-api rev * feat: add workspaces api * feat: added check user * chore: config * chore: update client_api version * chore: ws connect * chore: ws connect * chore: update crate versions * chore: rename event * chore: update client-appi * chore: set appflowy cloud env * chore: add env template * chore: update env name * docs: update docs * fix: check_user * feat: impl sign_in_with_url * feat: add file storage placeholders * chore: update client-api * chore: disable test * feat: impl workspace add and remove * chore: sign up test * feat: select cover image on upload (#3488) * fix: close popover after item selection in settings view (#3362) * fix: close popover after item selection in settings view * fix: add missing await before closing popover * fix: find popover container by context instead of passing controllers around * fix: add requested changes * feat: close text direction settings popups after selection * fix: clean up * fix: restore theme value dropdown as StatefulWidget * feat: openai and stabilityai integration (#3439) * chore: create trait * test: add tests * chore: remove log * chore: disable log * chore: checklist ux flow redesign (#3418) * chore: ux flow redesign * chore: remove unused imports * fix: allow creation of tasks of the same name * chore: apply code suggestions from Mathias * fix: add padding below field title text field (#3440) * Fixed Issue no #3426 * Reversed the pubspec.lock mistaken update * FIXED PADDING * Fixed Padding issue on calender field edit popup * chore: rename package name (#3501) * fix: right icon size sam as left one (#3494) * feat: enable removing user icon (#3487) * feat: enable removing user icon * fix: generate to true * fix: review comments * fix: more review comments * fix: integration test and final changes * fix: made cursor grab and background color when hovering on Appearance Options Buttons (#3498) * chore: calendar UI polish (#3484) * chore: update calendar theming * feat: add event popup editor * chore: new event button redesign and add card shadows * chore: unscheduled events button * chore: event title text field * fix: focus node double dispose * chore: show popover when create new event * test: integrate some tests for integration testing purposes * fix: some fixes and more integration tests * chore: add more space between font item and font menu * feat: add reset font button in toolbar * feat: only show text direction toolbar item when RTL is enabled * fix: unable to change RTL of heading block * test: add integration test for ltr/rtl mode * chore: update inlang project settings (#3441) * feat: using script to update the collab source. (#3508) * chore: add script * chore: update script * chore: update bytes version * chore: submit lock file * chore: update test * chore: update test * chore: bump version * chore: update * ci: fix * ci: fix * chore: update commit id * chore: update commit id * chore: update commit id * fix: is cloud enable --------- Co-authored-by: Fu Zi Xiang Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Co-authored-by: Vincenzo De Petris <37916223+vincendep@users.noreply.github.com> Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com> Co-authored-by: Aryan More <61151896+aryan-more@users.noreply.github.com> Co-authored-by: Lucas.Xu Co-authored-by: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com> Co-authored-by: Nitin-Poojary <70025277+Nitin-Poojary@users.noreply.github.com> Co-authored-by: Jannes Blobel <72493222+jannesblobel@users.noreply.github.com> --- frontend/appflowy_flutter/.gitignore | 4 +- frontend/appflowy_flutter/dev.env | 21 + .../integration_test/runner.dart | 2 +- frontend/appflowy_flutter/lib/env/env.dart | 59 +- .../lib/startup/deps_resolver.dart | 31 +- .../lib/startup/tasks/rust_sdk.dart | 6 + .../lib/startup/tasks/supabase_task.dart | 2 +- .../auth/af_cloud_auth_service.dart | 69 ++ .../user/application/auth/auth_service.dart | 9 - ...service.dart => backend_auth_service.dart} | 10 +- .../auth/supabase_auth_service.dart | 33 +- ...e.dart => supabase_mock_auth_service.dart} | 24 +- .../lib/user/application/prelude.dart | 2 +- .../presentation/screens/splash_screen.dart | 4 +- .../settings/widgets/settings_menu.dart | 2 +- .../settings/widgets/settings_user_view.dart | 4 +- .../appflowy_backend/lib/env_serde.dart | 20 +- .../appflowy_backend/lib/env_serde.i.dart | 33 - .../lib/colorscheme/colorscheme.dart | 1 - frontend/appflowy_tauri/src-tauri/Cargo.lock | 602 ++++++++++++--- frontend/appflowy_tauri/src-tauri/Cargo.toml | 47 +- frontend/rust-lib/Cargo.lock | 724 ++++++++++++++++-- frontend/rust-lib/Cargo.toml | 26 +- .../collab-integrate/src/collab_builder.rs | 12 +- frontend/rust-lib/dart-ffi/src/env_serde.rs | 3 + frontend/rust-lib/flowy-core/Cargo.toml | 2 + .../rust-lib/flowy-core/src/integrate/log.rs | 4 +- .../flowy-core/src/integrate/server.rs | 24 +- .../flowy-core/src/integrate/trait_impls.rs | 26 +- frontend/rust-lib/flowy-core/src/lib.rs | 2 +- .../rust-lib/flowy-database-deps/src/cloud.rs | 2 +- frontend/rust-lib/flowy-database2/Cargo.toml | 4 +- .../rust-lib/flowy-document2/src/document.rs | 5 +- frontend/rust-lib/flowy-error/src/code.rs | 3 + .../flowy-error/src/impl_from/cloud.rs | 3 + frontend/rust-lib/flowy-folder2/Cargo.toml | 2 +- .../src/af_cloud_config.rs | 40 + .../rust-lib/flowy-server-config/src/lib.rs | 1 + frontend/rust-lib/flowy-server/Cargo.toml | 7 +- .../src/af_cloud/configuration.rs | 79 -- .../src/af_cloud/configuration/base.yaml | 5 - .../src/af_cloud/configuration/local.yaml | 3 - .../af_cloud/configuration/production.yaml | 2 - .../src/af_cloud/impls/database.rs | 25 +- .../src/af_cloud/impls/document.rs | 31 +- .../src/af_cloud/impls/file_storage.rs | 43 ++ .../flowy-server/src/af_cloud/impls/folder.rs | 39 +- .../flowy-server/src/af_cloud/impls/mod.rs | 2 + .../flowy-server/src/af_cloud/impls/user.rs | 269 +++++-- .../rust-lib/flowy-server/src/af_cloud/mod.rs | 1 - .../flowy-server/src/af_cloud/server.rs | 77 +- .../src/local_server/impls/database.rs | 2 +- .../src/local_server/impls/user.rs | 17 +- frontend/rust-lib/flowy-server/src/server.rs | 4 +- .../flowy-server/src/supabase/api/database.rs | 4 +- .../flowy-server/src/supabase/api/user.rs | 34 +- .../flowy-server/src/supabase/define.rs | 1 + .../flowy-server/tests/af_cloud_test/mod.rs | 2 + .../tests/af_cloud_test/user_test.rs | 21 + .../flowy-server/tests/af_cloud_test/util.rs | 57 ++ frontend/rust-lib/flowy-server/tests/main.rs | 1 + .../tests/supabase_test/database_test.rs | 4 +- .../tests/supabase_test/folder_test.rs | 8 +- .../tests/supabase_test/user_test.rs | 12 +- .../flowy-server/tests/supabase_test/util.rs | 14 +- frontend/rust-lib/flowy-test/Cargo.toml | 14 +- frontend/rust-lib/flowy-test/src/lib.rs | 111 ++- .../rust-lib/flowy-test/tests/database/mod.rs | 2 +- .../tests/database/supabase_test/helper.rs | 10 +- .../tests/document/af_cloud_test/edit_test.rs | 34 + .../tests/document/af_cloud_test/mod.rs | 2 + .../tests/document/af_cloud_test/util.rs | 37 + .../rust-lib/flowy-test/tests/document/mod.rs | 3 +- .../tests/document/supabase_test/edit_test.rs | 61 ++ .../tests/document/supabase_test/helper.rs | 60 +- .../tests/document/supabase_test/mod.rs | 2 +- .../tests/document/supabase_test/test.rs | 86 --- .../rust-lib/flowy-test/tests/folder/mod.rs | 2 +- .../tests/folder/supabase_test/helper.rs | 2 +- .../tests/user/af_cloud_test/mod.rs | 1 + .../tests/user/af_cloud_test/test.rs | 13 + .../rust-lib/flowy-test/tests/user/mod.rs | 3 +- .../tests/user/supabase_test/auth_test.rs | 43 +- .../user/supabase_test/workspace_test.rs | 6 +- frontend/rust-lib/flowy-test/tests/util.rs | 34 + frontend/rust-lib/flowy-user-deps/Cargo.toml | 2 +- .../rust-lib/flowy-user-deps/src/cloud.rs | 22 +- .../rust-lib/flowy-user-deps/src/entities.rs | 17 +- frontend/rust-lib/flowy-user/Cargo.toml | 2 +- .../rust-lib/flowy-user/src/entities/auth.rs | 19 +- .../rust-lib/flowy-user/src/event_handler.rs | 19 +- frontend/rust-lib/flowy-user/src/event_map.rs | 12 +- frontend/rust-lib/flowy-user/src/manager.rs | 18 +- .../flowy-user/src/services/entities.rs | 8 +- .../scripts/tool/update_client_api_rev.sh | 30 + frontend/scripts/tool/update_collab_rev.sh | 9 +- shared-lib/Cargo.lock | 18 +- shared-lib/lib-infra/Cargo.toml | 6 +- 98 files changed, 2495 insertions(+), 845 deletions(-) create mode 100644 frontend/appflowy_flutter/dev.env create mode 100644 frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart rename frontend/appflowy_flutter/lib/user/application/auth/{appflowy_auth_service.dart => backend_auth_service.dart} (92%) rename frontend/appflowy_flutter/lib/user/application/auth/{mock_auth_service.dart => supabase_mock_auth_service.dart} (79%) delete mode 100644 frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.i.dart create mode 100644 frontend/rust-lib/flowy-server-config/src/af_cloud_config.rs delete mode 100644 frontend/rust-lib/flowy-server/src/af_cloud/configuration.rs delete mode 100644 frontend/rust-lib/flowy-server/src/af_cloud/configuration/base.yaml delete mode 100644 frontend/rust-lib/flowy-server/src/af_cloud/configuration/local.yaml delete mode 100644 frontend/rust-lib/flowy-server/src/af_cloud/configuration/production.yaml create mode 100644 frontend/rust-lib/flowy-server/src/af_cloud/impls/file_storage.rs create mode 100644 frontend/rust-lib/flowy-server/tests/af_cloud_test/mod.rs create mode 100644 frontend/rust-lib/flowy-server/tests/af_cloud_test/user_test.rs create mode 100644 frontend/rust-lib/flowy-server/tests/af_cloud_test/util.rs create mode 100644 frontend/rust-lib/flowy-test/tests/document/af_cloud_test/edit_test.rs create mode 100644 frontend/rust-lib/flowy-test/tests/document/af_cloud_test/mod.rs create mode 100644 frontend/rust-lib/flowy-test/tests/document/af_cloud_test/util.rs create mode 100644 frontend/rust-lib/flowy-test/tests/document/supabase_test/edit_test.rs delete mode 100644 frontend/rust-lib/flowy-test/tests/document/supabase_test/test.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/af_cloud_test/mod.rs create mode 100644 frontend/rust-lib/flowy-test/tests/user/af_cloud_test/test.rs create mode 100755 frontend/scripts/tool/update_client_api_rev.sh diff --git a/frontend/appflowy_flutter/.gitignore b/frontend/appflowy_flutter/.gitignore index e60f0bd4e8..9c3bb46d62 100644 --- a/frontend/appflowy_flutter/.gitignore +++ b/frontend/appflowy_flutter/.gitignore @@ -69,8 +69,8 @@ windows/flutter/dart_ffi/ **/.sandbox **/.vscode/ -*.env -*.env.* +.env +.env.* coverage/ diff --git a/frontend/appflowy_flutter/dev.env b/frontend/appflowy_flutter/dev.env new file mode 100644 index 0000000000..ff5a4825d8 --- /dev/null +++ b/frontend/appflowy_flutter/dev.env @@ -0,0 +1,21 @@ +# Initial Setup +# 1. Copy the dev.env file to .env: +# cp dev.env .env +# 2. Alternatively, you can generate the .env file using the "Generate Env File" task in VSCode. + +# Configuring Cloud Type +# This configuration file is used to specify the cloud type and the necessary configurations for each cloud type. The available options are: +# Supabase: Set CLOUD_TYPE to 1 +# AppFlowy Cloud: Set CLOUD_TYPE to 2 + +CLOUD_TYPE=1 + +# Supabase Configuration +# If you're using Supabase (CLOUD_TYPE=1), you need to provide the following configurations: +SUPABASE_URL=replace-with-your-supabase-url +SUPABASE_ANON_KEY=replace-with-your-supabase-key + +# AppFlowy Cloud Configuration +# If you're using AppFlowy Cloud (CLOUD_TYPE=2), you need to provide the following configurations: +APPFLOWY_CLOUD_BASE_URL=replace-with-your-appflowy-cloud-url +APPFLOWY_CLOUD_BASE_WS_URL=replace-with-your-appflowy-cloud-ws-url \ No newline at end of file diff --git a/frontend/appflowy_flutter/integration_test/runner.dart b/frontend/appflowy_flutter/integration_test/runner.dart index 7336e9ed6c..5e5f029087 100644 --- a/frontend/appflowy_flutter/integration_test/runner.dart +++ b/frontend/appflowy_flutter/integration_test/runner.dart @@ -73,7 +73,7 @@ void main() { user_icon_test.main(); user_language_test.main(); - if (isSupabaseEnabled) { + if (isCloudEnabled) { auth_test_runner.main(); } diff --git a/frontend/appflowy_flutter/lib/env/env.dart b/frontend/appflowy_flutter/lib/env/env.dart index 5f6a5d6ec5..dc71b488fa 100644 --- a/frontend/appflowy_flutter/lib/env/env.dart +++ b/frontend/appflowy_flutter/lib/env/env.dart @@ -1,5 +1,6 @@ // lib/env/env.dart import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy_backend/log.dart'; import 'package:envied/envied.dart'; part 'env.g.dart'; @@ -17,6 +18,29 @@ part 'env.g.dart'; /// @Envied(path: '.env') abstract class Env { + @EnviedField( + obfuscate: true, + varName: 'CLOUD_TYPE', + defaultValue: '0', + ) + static final int cloudType = _Env.cloudType; + + /// AppFlowy Cloud Configuration + @EnviedField( + obfuscate: true, + varName: 'APPFLOWY_CLOUD_BASE_URL', + defaultValue: '', + ) + static final String afCloudBaseUrl = _Env.afCloudBaseUrl; + + @EnviedField( + obfuscate: true, + varName: 'APPFLOWY_CLOUD_BASE_WS_URL', + defaultValue: '', + ) + static final String afCloudBaseWSUrl = _Env.afCloudBaseWSUrl; + + // Supabase Configuration: @EnviedField( obfuscate: true, varName: 'SUPABASE_URL', @@ -31,11 +55,42 @@ abstract class Env { static final String supabaseAnonKey = _Env.supabaseAnonKey; } -bool get isSupabaseEnabled { +bool get isCloudEnabled { // Only enable supabase in release and develop mode. if (integrationMode().isRelease || integrationMode().isDevelop) { - return Env.supabaseUrl.isNotEmpty && Env.supabaseAnonKey.isNotEmpty; + return currentCloudType().isEnabled; } else { return false; } } + +enum CloudType { + unknown, + supabase, + appflowyCloud; + + bool get isEnabled => this != CloudType.unknown; +} + +CloudType currentCloudType() { + final value = Env.cloudType; + if (value == 1) { + if (Env.supabaseUrl.isEmpty || Env.supabaseAnonKey.isEmpty) { + Log.error("Supabase is not configured"); + return CloudType.unknown; + } else { + return CloudType.supabase; + } + } + + if (value == 2) { + if (Env.afCloudBaseUrl.isEmpty || Env.afCloudBaseWSUrl.isEmpty) { + Log.error("AppFlowy cloud is not configured"); + return CloudType.unknown; + } else { + return CloudType.appflowyCloud; + } + } + + return CloudType.unknown; +} diff --git a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart index 22de7bb050..2d76751455 100644 --- a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart +++ b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart @@ -11,8 +11,9 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_p import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart'; import 'package:appflowy/plugins/trash/application/prelude.dart'; import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/user/application/auth/af_cloud_auth_service.dart'; import 'package:appflowy/user/application/auth/auth_service.dart'; -import 'package:appflowy/user/application/auth/mock_auth_service.dart'; +import 'package:appflowy/user/application/auth/supabase_mock_auth_service.dart'; import 'package:appflowy/user/application/auth/supabase_auth_service.dart'; import 'package:appflowy/user/application/prelude.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; @@ -29,7 +30,7 @@ import 'package:appflowy/workspace/application/view/prelude.dart'; import 'package:appflowy/workspace/application/workspace/prelude.dart'; import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; -import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:flowy_infra/file_picker/file_picker_impl.dart'; import 'package:flowy_infra/file_picker/file_picker_service.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -90,14 +91,24 @@ void _resolveCommonService( } void _resolveUserDeps(GetIt getIt, IntegrationMode mode) { - if (isSupabaseEnabled) { - if (mode.isIntegrationTest) { - getIt.registerFactory(() => MockAuthService()); - } else { - getIt.registerFactory(() => SupabaseAuthService()); - } - } else { - getIt.registerFactory(() => AppFlowyAuthService()); + switch (currentCloudType()) { + case CloudType.unknown: + getIt.registerFactory( + () => BackendAuthService( + AuthTypePB.Local, + ), + ); + break; + case CloudType.supabase: + if (mode.isIntegrationTest) { + getIt.registerFactory(() => MockAuthService()); + } else { + getIt.registerFactory(() => SupabaseAuthService()); + } + break; + case CloudType.appflowyCloud: + getIt.registerFactory(() => AFCloudAuthService()); + break; } getIt.registerFactory(() => AuthRouter()); diff --git a/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart b/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart index 42d1360aa9..7da3160229 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/rust_sdk.dart @@ -36,8 +36,14 @@ AppFlowyEnv getAppFlowyEnv() { anon_key: Env.supabaseAnonKey, ); + final appflowyCloudConfig = AppFlowyCloudConfiguration( + base_url: Env.afCloudBaseUrl, + base_ws_url: Env.afCloudBaseWSUrl, + ); + return AppFlowyEnv( supabase_config: supabaseConfig, + appflowy_cloud_config: appflowyCloudConfig, ); } diff --git a/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart b/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart index 8def3d5848..40fecd02a8 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/supabase_task.dart @@ -28,7 +28,7 @@ SupbaseRealtimeService? realtimeService; class InitSupabaseTask extends LaunchTask { @override Future initialize(LaunchContext context) async { - if (!isSupabaseEnabled) { + if (!isCloudEnabled) { return; } diff --git a/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart new file mode 100644 index 0000000000..88177dc1b4 --- /dev/null +++ b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart @@ -0,0 +1,69 @@ +import 'dart:async'; + +import 'package:appflowy/user/application/auth/backend_auth_service.dart'; +import 'package:appflowy/user/application/auth/auth_service.dart'; +import 'package:appflowy/user/application/user_service.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; +import 'package:dartz/dartz.dart'; + +class AFCloudAuthService implements AuthService { + AFCloudAuthService(); + + final BackendAuthService _backendAuthService = BackendAuthService( + AuthTypePB.AFCloud, + ); + + @override + Future> signUp({ + required String name, + required String email, + required String password, + Map params = const {}, + }) async { + throw UnimplementedError(); + } + + @override + Future> signIn({ + required String email, + required String password, + Map params = const {}, + }) async { + throw UnimplementedError(); + } + + @override + Future> signUpWithOAuth({ + required String platform, + Map params = const {}, + }) async { + // + throw UnimplementedError(); + } + + @override + Future signOut() async { + await _backendAuthService.signOut(); + } + + @override + Future> signUpAsGuest({ + Map params = const {}, + }) async { + return _backendAuthService.signUpAsGuest(); + } + + @override + Future> signInWithMagicLink({ + required String email, + Map params = const {}, + }) async { + throw UnimplementedError(); + } + + @override + Future> getUser() async { + return UserBackendService.getCurrentUserProfile(); + } +} diff --git a/frontend/appflowy_flutter/lib/user/application/auth/auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/auth_service.dart index 6cfcff4557..2f56e54fdf 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/auth_service.dart @@ -1,5 +1,4 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; -import 'package:appflowy_backend/protobuf/flowy-user/auth.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pbserver.dart'; import 'package:dartz/dartz.dart'; @@ -21,7 +20,6 @@ abstract class AuthService { /// /// - `email`: The email address of the user. /// - `password`: The password of the user. - /// - `authType`: The type of authentication (optional). /// - `params`: Additional parameters for authentication (optional). /// /// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError]. @@ -29,7 +27,6 @@ abstract class AuthService { Future> signIn({ required String email, required String password, - AuthTypePB authType, Map params, }); @@ -38,7 +35,6 @@ abstract class AuthService { /// - `name`: The name of the user. /// - `email`: The email address of the user. /// - `password`: The password of the user. - /// - `authType`: The type of authentication (optional). /// - `params`: Additional parameters for registration (optional). /// /// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError]. @@ -46,31 +42,26 @@ abstract class AuthService { required String name, required String email, required String password, - AuthTypePB authType, Map params, }); /// Registers a new user with an OAuth platform. /// /// - `platform`: The OAuth platform name. - /// - `authType`: The type of authentication (optional). /// - `params`: Additional parameters for OAuth registration (optional). /// /// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError]. Future> signUpWithOAuth({ required String platform, - AuthTypePB authType, Map params, }); /// Registers a user as a guest. /// - /// - `authType`: The type of authentication (optional). /// - `params`: Additional parameters for guest registration (optional). /// /// Returns a default [UserProfilePB]. Future> signUpAsGuest({ - AuthTypePB authType, Map params, }); diff --git a/frontend/appflowy_flutter/lib/user/application/auth/appflowy_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart similarity index 92% rename from frontend/appflowy_flutter/lib/user/application/auth/appflowy_auth_service.dart rename to frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart index 867db532c9..b6c287145b 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/appflowy_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart @@ -13,12 +13,15 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' import '../../../generated/locale_keys.g.dart'; import 'device_id.dart'; -class AppFlowyAuthService implements AuthService { +class BackendAuthService implements AuthService { + final AuthTypePB authType; + + BackendAuthService(this.authType); + @override Future> signIn({ required String email, required String password, - AuthTypePB authType = AuthTypePB.Local, Map params = const {}, }) async { final request = SignInPayloadPB.create() @@ -35,7 +38,6 @@ class AppFlowyAuthService implements AuthService { required String name, required String email, required String password, - AuthTypePB authType = AuthTypePB.Local, Map params = const {}, }) async { final request = SignUpPayloadPB.create() @@ -52,7 +54,6 @@ class AppFlowyAuthService implements AuthService { @override Future signOut({ - AuthTypePB authType = AuthTypePB.Local, Map params = const {}, }) async { await UserEventSignOut().send(); @@ -61,7 +62,6 @@ class AppFlowyAuthService implements AuthService { @override Future> signUpAsGuest({ - AuthTypePB authType = AuthTypePB.Local, Map params = const {}, }) { const password = "Guest!@123456"; diff --git a/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart index 937c1558fb..79f0f22f36 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:appflowy/startup/tasks/prelude.dart'; -import 'package:appflowy/user/application/auth/appflowy_auth_service.dart'; +import 'package:appflowy/user/application/auth/backend_auth_service.dart'; import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/user/application/auth/device_id.dart'; import 'package:appflowy/user/application/user_service.dart'; @@ -20,14 +20,15 @@ class SupabaseAuthService implements AuthService { SupabaseClient get _client => Supabase.instance.client; GoTrueClient get _auth => _client.auth; - final AppFlowyAuthService _appFlowyAuthService = AppFlowyAuthService(); + final BackendAuthService _backendAuthService = BackendAuthService( + AuthTypePB.Supabase, + ); @override Future> signUp({ required String name, required String email, required String password, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { // fetch the uuid from supabase. @@ -41,11 +42,10 @@ class SupabaseAuthService implements AuthService { } // assign the uuid to our backend service. // and will transfer this logic to backend later. - return _appFlowyAuthService.signUp( + return _backendAuthService.signUp( name: name, email: email, password: password, - authType: authType, params: { AuthServiceMapKeys.uuid: uuid, }, @@ -56,7 +56,6 @@ class SupabaseAuthService implements AuthService { Future> signIn({ required String email, required String password, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { try { @@ -68,10 +67,9 @@ class SupabaseAuthService implements AuthService { if (uuid == null) { return Left(AuthError.supabaseSignInError); } - return _appFlowyAuthService.signIn( + return _backendAuthService.signIn( email: email, password: password, - authType: authType, params: { AuthServiceMapKeys.uuid: uuid, }, @@ -85,7 +83,6 @@ class SupabaseAuthService implements AuthService { @override Future> signUpWithOAuth({ required String platform, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { // Before signing in, sign out any existing users. Otherwise, the callback will be triggered even if the user doesn't click the 'Sign In' button on the website @@ -118,23 +115,18 @@ class SupabaseAuthService implements AuthService { } @override - Future signOut({ - AuthTypePB authType = AuthTypePB.Supabase, - }) async { + Future signOut() async { await _auth.signOut(); - await _appFlowyAuthService.signOut( - authType: authType, - ); + await _backendAuthService.signOut(); } @override Future> signUpAsGuest({ - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { // supabase don't support guest login. // so, just forward to our backend. - return _appFlowyAuthService.signUpAsGuest(); + return _backendAuthService.signUpAsGuest(); } @override @@ -177,13 +169,12 @@ class SupabaseAuthService implements AuthService { Future> _setupAuth({ required Map map, }) async { - final payload = ThirdPartyAuthPB( + final payload = OAuthPB( authType: AuthTypePB.Supabase, map: map, ); - return UserEventThirdPartyAuth(payload) - .send() - .then((value) => value.swap()); + + return UserEventOAuth(payload).send().then((value) => value.swap()); } } diff --git a/frontend/appflowy_flutter/lib/user/application/auth/mock_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart similarity index 79% rename from frontend/appflowy_flutter/lib/user/application/auth/mock_auth_service.dart rename to frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart index 5286bcd86b..0951867f15 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/mock_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:appflowy/user/application/auth/appflowy_auth_service.dart'; +import 'package:appflowy/user/application/auth/backend_auth_service.dart'; import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/user/application/user_service.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart'; @@ -20,14 +20,14 @@ class MockAuthService implements AuthService { SupabaseClient get _client => Supabase.instance.client; GoTrueClient get _auth => _client.auth; - final AppFlowyAuthService _appFlowyAuthService = AppFlowyAuthService(); + final BackendAuthService _appFlowyAuthService = + BackendAuthService(AuthTypePB.Supabase); @override Future> signUp({ required String name, required String email, required String password, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { throw UnimplementedError(); @@ -37,7 +37,6 @@ class MockAuthService implements AuthService { Future> signIn({ required String email, required String password, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { throw UnimplementedError(); @@ -46,7 +45,6 @@ class MockAuthService implements AuthService { @override Future> signUpWithOAuth({ required String platform, - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { try { @@ -58,7 +56,7 @@ class MockAuthService implements AuthService { final uuid = response.user!.id; final email = response.user!.email!; - final payload = ThirdPartyAuthPB( + final payload = OAuthPB( authType: AuthTypePB.Supabase, map: { AuthServiceMapKeys.uuid: uuid, @@ -66,9 +64,8 @@ class MockAuthService implements AuthService { AuthServiceMapKeys.deviceId: 'MockDeviceId' }, ); - return UserEventThirdPartyAuth(payload) - .send() - .then((value) => value.swap()); + + return UserEventOAuth(payload).send().then((value) => value.swap()); } on AuthException catch (e) { Log.error(e); return Left(AuthError.supabaseSignInError); @@ -76,18 +73,13 @@ class MockAuthService implements AuthService { } @override - Future signOut({ - AuthTypePB authType = AuthTypePB.Supabase, - }) async { + Future signOut() async { await _auth.signOut(); - await _appFlowyAuthService.signOut( - authType: authType, - ); + await _appFlowyAuthService.signOut(); } @override Future> signUpAsGuest({ - AuthTypePB authType = AuthTypePB.Supabase, Map params = const {}, }) async { // supabase don't support guest login. diff --git a/frontend/appflowy_flutter/lib/user/application/prelude.dart b/frontend/appflowy_flutter/lib/user/application/prelude.dart index ddacb654d3..2bd1c18cb7 100644 --- a/frontend/appflowy_flutter/lib/user/application/prelude.dart +++ b/frontend/appflowy_flutter/lib/user/application/prelude.dart @@ -1,4 +1,4 @@ -export 'auth/appflowy_auth_service.dart'; +export 'auth/backend_auth_service.dart'; export './sign_in_bloc.dart'; export './sign_up_bloc.dart'; export './splash_bloc.dart'; diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/splash_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/splash_screen.dart index 6395f0fb82..1b53d80bdf 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/splash_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/splash_screen.dart @@ -105,10 +105,10 @@ class SplashScreen extends StatelessWidget { void _handleUnauthenticated(BuildContext context, Unauthenticated result) { Log.trace( - '_handleUnauthenticated -> Supabase is enabled: $isSupabaseEnabled', + '_handleUnauthenticated -> cloud is enabled: $isCloudEnabled', ); // replace Splash screen as root page - if (isSupabaseEnabled) { + if (isCloudEnabled) { context.go(SignInScreen.routeName); } else { // if the env is not configured, we will skip to the 'skip login screen'. diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart index 2490a47577..ef44f41393 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart @@ -60,7 +60,7 @@ class SettingsMenu extends StatelessWidget { ), // Only show supabase setting if supabase is enabled and the current auth type is not local - if (isSupabaseEnabled && + if (isCloudEnabled && context.read().state.userProfile.authType != AuthTypePB.Local) SettingsMenuElement( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 8bd91b6b21..c4c08883fb 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -54,7 +54,7 @@ class SettingsUserView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ _buildUserIconSetting(context), - if (isSupabaseEnabled) ...[ + if (isCloudEnabled) ...[ const VSpace(12), UserEmailInput(user.email) ], @@ -188,7 +188,7 @@ class SettingsUserView extends StatelessWidget { BuildContext context, SettingsUserState state, ) { - if (!isSupabaseEnabled) { + if (!isCloudEnabled) { return const SizedBox.shrink(); } diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart index a34d7fbaef..f71e89ee16 100644 --- a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart +++ b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.dart @@ -5,14 +5,16 @@ import 'package:json_annotation/json_annotation.dart'; // // the file `env_serde.g.dart` will be generated in the same directory. Rename // the file to `env_serde.i.dart` because the file is ignored by default. -part 'env_serde.i.dart'; +part 'env_serde.g.dart'; @JsonSerializable() class AppFlowyEnv { final SupabaseConfiguration supabase_config; + final AppFlowyCloudConfiguration appflowy_cloud_config; AppFlowyEnv({ required this.supabase_config, + required this.appflowy_cloud_config, }); factory AppFlowyEnv.fromJson(Map json) => @@ -39,3 +41,19 @@ class SupabaseConfiguration { Map toJson() => _$SupabaseConfigurationToJson(this); } + +@JsonSerializable() +class AppFlowyCloudConfiguration { + final String base_url; + final String base_ws_url; + + AppFlowyCloudConfiguration({ + required this.base_url, + required this.base_ws_url, + }); + + factory AppFlowyCloudConfiguration.fromJson(Map json) => + _$AppFlowyCloudConfigurationFromJson(json); + + Map toJson() => _$AppFlowyCloudConfigurationToJson(this); +} diff --git a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.i.dart b/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.i.dart deleted file mode 100644 index 3dd6fb3c70..0000000000 --- a/frontend/appflowy_flutter/packages/appflowy_backend/lib/env_serde.i.dart +++ /dev/null @@ -1,33 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'env_serde.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -AppFlowyEnv _$AppFlowyEnvFromJson(Map json) => AppFlowyEnv( - supabase_config: SupabaseConfiguration.fromJson( - json['supabase_config'] as Map), - ); - -Map _$AppFlowyEnvToJson(AppFlowyEnv instance) => - { - 'supabase_config': instance.supabase_config, - }; - -SupabaseConfiguration _$SupabaseConfigurationFromJson( - Map json) => - SupabaseConfiguration( - enable_sync: json['enable_sync'] as bool? ?? true, - url: json['url'] as String, - anon_key: json['anon_key'] as String, - ); - -Map _$SupabaseConfigurationToJson( - SupabaseConfiguration instance) => - { - 'enable_sync': instance.enable_sync, - 'url': instance.url, - 'anon_key': instance.anon_key, - }; diff --git a/frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/colorscheme.dart b/frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/colorscheme.dart index 0319a2108e..1d9125eb36 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/colorscheme.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/colorscheme.dart @@ -88,7 +88,6 @@ class FlowyColorScheme { final Color calendarWeekendBGColor; //grid bottom count color final Color gridRowCountColor; - const FlowyColorScheme({ required this.surface, required this.hover, diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index ff4ba0b78f..a25bfc3e94 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -244,7 +244,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "glib", "libc", ] @@ -276,12 +276,52 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79d6dc922a2792b006573f60b2648076355daeae5ce9cb59507e5908c9625d31" +[[package]] +name = "attohttpc" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" +dependencies = [ + "http", + "log", + "native-tls", + "serde", + "serde_json", + "url", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aws-creds" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3776743bb68d4ad02ba30ba8f64373f1be4e082fe47651767171ce75bb2f6cf5" +dependencies = [ + "attohttpc", + "dirs", + "log", + "quick-xml 0.26.0", + "rust-ini", + "serde", + "thiserror", + "time", + "url", +] + +[[package]] +name = "aws-region" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056557a61427d0e5ba29dd931031c8ffed4ee7a550e7cd55692a9d8deb0a9dba" +dependencies = [ + "thiserror", +] + [[package]] name = "backoff" version = "0.4.0" @@ -338,7 +378,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -374,6 +414,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitvec" version = "1.0.1" @@ -545,7 +591,7 @@ version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib", "libc", @@ -716,20 +762,27 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ "anyhow", "bytes", - "collab-sync-protocol", + "collab", + "collab-define", + "database-entity", + "futures-core", "futures-util", + "gotrue", "gotrue-entity", + "lib0", + "mime", "opener", + "parking_lot", "reqwest", + "scraper", "serde", "serde_json", "serde_repr", "shared_entity", - "storage-entity", "thiserror", "tokio", "tokio-retry", @@ -737,6 +790,8 @@ dependencies = [ "tokio-tungstenite", "tracing", "url", + "uuid", + "yrs", ] [[package]] @@ -770,7 +825,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", @@ -786,7 +841,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", @@ -798,7 +853,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", @@ -809,15 +864,15 @@ dependencies = [ "serde_json", "thiserror", "tokio", + "tokio-stream", "tracing", - "y-sync", "yrs", ] [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", @@ -847,11 +902,13 @@ dependencies = [ [[package]] name = "collab-define" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", + "bytes", "collab", "serde", + "serde_json", "serde_repr", "uuid", ] @@ -859,7 +916,7 @@ dependencies = [ [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "proc-macro2", "quote", @@ -871,7 +928,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "collab", @@ -891,7 +948,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "chrono", @@ -931,7 +988,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "async-trait", "bincode", @@ -952,14 +1009,14 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", + "bytes", "collab", "collab-define", "collab-persistence", - "collab-sync-protocol", "futures-util", "lib0", "parking_lot", @@ -973,29 +1030,13 @@ dependencies = [ "tokio-stream", "tracing", "uuid", - "y-sync", - "yrs", -] - -[[package]] -name = "collab-sync-protocol" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" -dependencies = [ - "bytes", - "collab", - "collab-define", - "md5", - "serde", - "serde_json", - "y-sync", "yrs", ] [[package]] name = "collab-user" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "collab", @@ -1057,6 +1098,34 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" +dependencies = [ + "cookie", + "idna 0.2.3", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1079,7 +1148,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-graphics-types", "foreign-types", @@ -1092,7 +1161,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "libc", ] @@ -1211,6 +1280,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "cssparser" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 1.0.6", + "phf 0.11.2", + "smallvec", +] + [[package]] name = "cssparser-macros" version = "0.6.1" @@ -1344,6 +1426,26 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "database-entity" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "chrono", + "collab-define", + "serde", + "serde_json", + "sqlx", + "uuid", + "validator", +] + [[package]] name = "date_time_parser" version = "0.2.0" @@ -1459,6 +1561,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1469,6 +1580,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1486,6 +1608,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + [[package]] name = "dotenv" version = "0.15.0" @@ -1525,6 +1653,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +[[package]] +name = "ego-tree" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" + [[package]] name = "either" version = "1.8.1" @@ -1627,7 +1761,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "winapi", ] @@ -1775,6 +1909,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "client-api", "collab", "collab-define", "collab-integrate", @@ -1806,6 +1941,7 @@ dependencies = [ "serde_json", "serde_repr", "tokio", + "tokio-stream", "tracing", "uuid", ] @@ -2355,7 +2491,7 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -2371,7 +2507,7 @@ version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -2468,6 +2604,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -2514,7 +2659,7 @@ version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -2544,7 +2689,7 @@ version = "0.15.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -2608,7 +2753,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -2624,11 +2769,28 @@ dependencies = [ "system-deps 6.1.1", ] +[[package]] +name = "gotrue" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "anyhow", + "futures-util", + "gotrue-entity", + "infra", + "reqwest", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ + "anyhow", + "reqwest", "serde", "serde_json", ] @@ -2640,7 +2802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" dependencies = [ "atk", - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -2800,7 +2962,21 @@ checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" dependencies = [ "log", "mac", - "markup5ever", + "markup5ever 0.10.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever 0.11.0", "proc-macro2", "quote", "syn 1.0.109", @@ -2944,6 +3120,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.4.0" @@ -3020,6 +3217,17 @@ dependencies = [ "cfb", ] +[[package]] +name = "infra" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "anyhow", + "reqwest", + "serde", + "serde_json", +] + [[package]] name = "inout" version = "0.1.3" @@ -3091,7 +3299,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "glib", "javascriptcore-rs-sys", ] @@ -3164,10 +3372,10 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358" dependencies = [ - "cssparser", - "html5ever", + "cssparser 0.27.2", + "html5ever 0.25.2", "matches", - "selectors", + "selectors 0.22.0", ] [[package]] @@ -3189,7 +3397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec 0.5.2", - "bitflags", + "bitflags 1.3.2", "cfg-if", "ryu", "static_assertions", @@ -3411,6 +3619,20 @@ dependencies = [ "tendril", ] +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "matchers" version = "0.0.1" @@ -3435,6 +3657,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "maybe-async" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "md-5" version = "0.10.5" @@ -3502,6 +3735,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "minidom" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f45614075738ce1b77a1768912a60c0227525971b03e09122a05b8a34a2a6278" +dependencies = [ + "rxml", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3571,7 +3813,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "jni-sys", "ndk-sys", "num_enum", @@ -3782,7 +4024,7 @@ version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -3830,6 +4072,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown 0.12.3", +] + [[package]] name = "os_pipe" version = "0.9.2" @@ -3852,7 +4104,7 @@ version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "glib", "libc", "once_cell", @@ -4009,6 +4261,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ + "phf_macros 0.11.2", "phf_shared 0.11.2", ] @@ -4100,6 +4353,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -4130,18 +4396,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", @@ -4175,7 +4441,7 @@ dependencies = [ "base64 0.21.2", "indexmap 1.9.3", "line-wrap", - "quick-xml", + "quick-xml 0.28.2", "serde", "time", ] @@ -4186,7 +4452,7 @@ version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", @@ -4410,6 +4676,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + [[package]] name = "ptr_meta" version = "0.1.4" @@ -4430,6 +4702,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.28.2" @@ -4586,7 +4878,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -4595,7 +4887,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -4658,6 +4950,8 @@ checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64 0.21.2", "bytes", + "cookie", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -4765,6 +5059,49 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust-s3" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b2ac5ff6acfbe74226fa701b5ef793aaa054055c13ebb7060ad36942956e027" +dependencies = [ + "async-trait", + "aws-creds", + "aws-region", + "base64 0.13.1", + "bytes", + "cfg-if", + "futures", + "hex", + "hmac", + "http", + "log", + "maybe-async", + "md5", + "minidom", + "percent-encoding", + "quick-xml 0.26.0", + "reqwest", + "serde", + "serde_derive", + "sha2", + "thiserror", + "time", + "tokio", + "tokio-stream", + "url", +] + [[package]] name = "rust_decimal" version = "1.30.0" @@ -4820,7 +5157,7 @@ version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -4887,6 +5224,23 @@ dependencies = [ "rust_decimal_macros", ] +[[package]] +name = "rxml" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98f186c7a2f3abbffb802984b7f1dfd65dac8be1aafdaabbca4137f53f0dff7" +dependencies = [ + "bytes", + "rxml_validation", + "smartstring", +] + +[[package]] +name = "rxml_validation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" + [[package]] name = "ryu" version = "1.0.13" @@ -4938,6 +5292,23 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scraper" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" +dependencies = [ + "ahash 0.8.3", + "cssparser 0.31.2", + "ego-tree", + "getopts", + "html5ever 0.26.0", + "once_cell", + "selectors 0.25.0", + "smallvec", + "tendril", +] + [[package]] name = "sct" version = "0.7.0" @@ -4960,7 +5331,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -4983,8 +5354,8 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" dependencies = [ - "bitflags", - "cssparser", + "bitflags 1.3.2", + "cssparser 0.27.2", "derive_more", "fxhash", "log", @@ -4992,11 +5363,30 @@ dependencies = [ "phf 0.8.0", "phf_codegen 0.8.0", "precomputed-hash", - "servo_arc", + "servo_arc 0.1.1", "smallvec", "thin-slice", ] +[[package]] +name = "selectors" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" +dependencies = [ + "bitflags 2.4.0", + "cssparser 0.31.2", + "derive_more", + "fxhash", + "log", + "new_debug_unreachable", + "phf 0.10.1", + "phf_codegen 0.10.0", + "precomputed-hash", + "servo_arc 0.3.0", + "smallvec", +] + [[package]] name = "semver" version = "1.0.17" @@ -5140,6 +5530,15 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "servo_arc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "sha1" version = "0.10.5" @@ -5180,16 +5579,19 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ "anyhow", + "gotrue-entity", "opener", "reqwest", + "rust-s3", "serde", "serde_json", "serde_repr", "thiserror", "url", + "uuid", ] [[package]] @@ -5270,6 +5672,17 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + [[package]] name = "socket2" version = "0.4.9" @@ -5296,7 +5709,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio", "glib", "libc", @@ -5310,7 +5723,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio-sys", "glib-sys", "gobject-sys", @@ -5438,20 +5851,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "storage-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" -dependencies = [ - "chrono", - "collab-define", - "serde", - "serde_json", - "sqlx", - "uuid", - "validator", -] - [[package]] name = "string_cache" version = "0.8.7" @@ -5585,7 +5984,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "cc", "cocoa", @@ -5816,7 +6215,7 @@ dependencies = [ "dunce", "glob", "heck 0.4.1", - "html5ever", + "html5ever 0.25.2", "infer", "json-patch", "kuchiki", @@ -6089,9 +6488,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", @@ -6302,13 +6701,13 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", @@ -6461,7 +6860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", "serde", ] @@ -6489,7 +6888,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" dependencies = [ - "idna", + "idna 0.4.0", "lazy_static", "regex", "serde", @@ -6701,7 +7100,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk", "gdk-sys", @@ -6726,7 +7125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", @@ -7081,7 +7480,7 @@ dependencies = [ "gio", "glib", "gtk", - "html5ever", + "html5ever 0.25.2", "http", "kuchiki", "libc", @@ -7142,17 +7541,6 @@ dependencies = [ "libc", ] -[[package]] -name = "y-sync" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54d34b68ec4514a0659838c2b1ba867c571b20b3804a1338dacf4fa9062d801" -dependencies = [ - "lib0", - "thiserror", - "yrs", -] - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 044a450871..2c82010016 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -18,18 +18,11 @@ serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.2", features = ["fs-all", "shell-open"] } tauri-utils = "1.2" -bytes = { version = "1.4" } +bytes = { version = "1.5" } tracing = { version = "0.1", features = ["log"] } -lib-dispatch = { path = "../../rust-lib/lib-dispatch", features = [ - "use_serde", -] } -flowy-core = { path = "../../rust-lib/flowy-core", features = [ - "rev-sqlite", - "ts", -] } -flowy-notification = { path = "../../rust-lib/flowy-notification", features = [ - "ts", -] } +lib-dispatch = { path = "../../rust-lib/lib-dispatch", features = ["use_serde"] } +flowy-core = { path = "../../rust-lib/flowy-core", features = ["rev-sqlite", "ts"] } +flowy-notification = { path = "../../rust-lib/flowy-notification", features = ["ts"] } [features] # by default Tauri runs in production mode @@ -40,24 +33,30 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f8f6a" } - -# ⚠️⚠️⚠️ +# Please using the following command to update the revision id +# Current directory: frontend +# Run the script: +# scripts/tool/update_client_api_rev.sh new_rev_id +# ⚠️⚠️⚠️️ +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b0c213" } # Please use the following script to update collab. # Working directory: frontend # # To update the commit ID, run: -# scripts/tool/update_collab_rev.sh e37ee7 +# scripts/tool/update_collab_rev.sh new_rev_id # # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-sync-protocol = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } + + + + diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 6e0db240ec..585906d068 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -238,12 +238,52 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112ef6b3f6cb3cb6fc5b6b494ef7a848492cff1ab0ef4de10b0f7d572861c905" +[[package]] +name = "attohttpc" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" +dependencies = [ + "http", + "log", + "native-tls", + "serde", + "serde_json", + "url", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aws-creds" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3776743bb68d4ad02ba30ba8f64373f1be4e082fe47651767171ce75bb2f6cf5" +dependencies = [ + "attohttpc", + "dirs", + "log", + "quick-xml", + "rust-ini", + "serde", + "thiserror", + "time", + "url", +] + +[[package]] +name = "aws-region" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056557a61427d0e5ba29dd931031c8ffed4ee7a550e7cd55692a9d8deb0a9dba" +dependencies = [ + "thiserror", +] + [[package]] name = "axum" version = "0.6.20" @@ -421,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ "borsh-derive", - "hashbrown 0.12.3", + "hashbrown 0.13.2", ] [[package]] @@ -561,16 +601,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.29" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", "windows-targets", ] @@ -594,7 +633,7 @@ checksum = "e2f5ebdc942f57ed96d560a6d1a459bae5851102a25d5bf89dc04ae453e31ecf" dependencies = [ "parse-zoneinfo", "phf 0.11.2", - "phf_codegen", + "phf_codegen 0.11.2", ] [[package]] @@ -621,20 +660,27 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ "anyhow", "bytes", - "collab-sync-protocol", + "collab", + "collab-define", + "database-entity", + "futures-core", "futures-util", + "gotrue", "gotrue-entity", + "lib0", + "mime", "opener", + "parking_lot", "reqwest", + "scraper", "serde", "serde_json", "serde_repr", "shared_entity", - "storage-entity", "thiserror", "tokio", "tokio-retry", @@ -642,6 +688,8 @@ dependencies = [ "tokio-tungstenite", "tracing", "url", + "uuid", + "yrs", ] [[package]] @@ -672,7 +720,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", @@ -683,15 +731,15 @@ dependencies = [ "serde_json", "thiserror", "tokio", + "tokio-stream", "tracing", - "y-sync", "yrs", ] [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", @@ -721,11 +769,13 @@ dependencies = [ [[package]] name = "collab-define" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", + "bytes", "collab", "serde", + "serde_json", "serde_repr", "uuid", ] @@ -733,7 +783,7 @@ dependencies = [ [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "proc-macro2", "quote", @@ -745,7 +795,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "collab", @@ -765,7 +815,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "chrono", @@ -805,7 +855,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "async-trait", "bincode", @@ -826,14 +876,14 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "async-trait", + "bytes", "collab", "collab-define", "collab-persistence", - "collab-sync-protocol", "futures-util", "lib0", "parking_lot", @@ -847,29 +897,13 @@ dependencies = [ "tokio-stream", "tracing", "uuid", - "y-sync", - "yrs", -] - -[[package]] -name = "collab-sync-protocol" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" -dependencies = [ - "bytes", - "collab", - "collab-define", - "md5", - "serde", - "serde_json", - "y-sync", "yrs", ] [[package]] name = "collab-user" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e37ee7#e37ee7ea66e27da7ef4ec1128adba7f4af8ede32" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=86c5e8#86c5e8891af93de2d035a57214894e854d39662a" dependencies = [ "anyhow", "collab", @@ -951,6 +985,34 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" +dependencies = [ + "cookie", + "idna 0.2.3", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1064,6 +1126,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.11.2", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.31", +] + [[package]] name = "csv" version = "1.2.2" @@ -1168,6 +1253,26 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "database-entity" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "chrono", + "collab-define", + "serde", + "serde_json", + "sqlx", + "uuid", + "validator", +] + [[package]] name = "date_time_parser" version = "0.2.0" @@ -1183,6 +1288,9 @@ name = "deranged" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] [[package]] name = "derivative" @@ -1226,6 +1334,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "deunicode" version = "0.4.4" @@ -1276,6 +1395,32 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + [[package]] name = "dotenv" version = "0.15.0" @@ -1288,12 +1433,33 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + [[package]] name = "dyn-clone" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" +[[package]] +name = "ego-tree" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" + [[package]] name = "either" version = "1.9.0" @@ -1517,6 +1683,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "client-api", "collab", "collab-define", "collab-integrate", @@ -1549,6 +1716,7 @@ dependencies = [ "serde_json", "serde_repr", "tokio", + "tokio-stream", "tracing", "uuid", ] @@ -2039,6 +2207,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures" version = "0.3.28" @@ -2145,6 +2323,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2165,6 +2352,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -2235,11 +2431,28 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gotrue" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "anyhow", + "futures-util", + "gotrue-entity", + "infra", + "reqwest", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ + "anyhow", + "reqwest", "serde", "serde_json", ] @@ -2361,6 +2574,20 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "http" version = "0.2.9" @@ -2502,6 +2729,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.4.0" @@ -2556,6 +2804,17 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "infra" +version = "0.1.0" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" +dependencies = [ + "anyhow", + "reqwest", + "serde", + "serde_json", +] + [[package]] name = "inout" version = "0.1.3" @@ -2810,6 +3069,26 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "matchers" version = "0.0.1" @@ -2828,12 +3107,29 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "matchit" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" +[[package]] +name = "maybe-async" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "md-5" version = "0.10.5" @@ -2901,6 +3197,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "minidom" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f45614075738ce1b77a1768912a60c0227525971b03e09122a05b8a34a2a6278" +dependencies = [ + "rxml", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2954,6 +3259,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "nom" version = "5.1.3" @@ -3099,6 +3410,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown 0.12.3", +] + [[package]] name = "os_pipe" version = "0.9.2" @@ -3249,20 +3570,40 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros", + "phf_macros 0.8.0", "phf_shared 0.8.0", "proc-macro-hack", ] +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + [[package]] name = "phf" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ + "phf_macros 0.11.2", "phf_shared 0.11.2", ] +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + [[package]] name = "phf_codegen" version = "0.11.2" @@ -3283,6 +3624,16 @@ dependencies = [ "rand 0.7.3", ] +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + [[package]] name = "phf_generator" version = "0.11.2" @@ -3307,6 +3658,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.31", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -3316,6 +3680,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "phf_shared" version = "0.11.2" @@ -3419,6 +3792,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "prettyplease" version = "0.2.14" @@ -3596,6 +3975,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + [[package]] name = "ptr_meta" version = "0.1.4" @@ -3616,6 +4001,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quickcheck" version = "1.0.3" @@ -3810,6 +4215,15 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -3819,6 +4233,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "regex" version = "1.9.5" @@ -3889,6 +4314,8 @@ checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64 0.21.3", "bytes", + "cookie", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -3996,6 +4423,49 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust-s3" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b2ac5ff6acfbe74226fa701b5ef793aaa054055c13ebb7060ad36942956e027" +dependencies = [ + "async-trait", + "aws-creds", + "aws-region", + "base64 0.13.1", + "bytes", + "cfg-if", + "futures", + "hex", + "hmac", + "http", + "log", + "maybe-async", + "md5", + "minidom", + "percent-encoding", + "quick-xml", + "reqwest", + "serde", + "serde_derive", + "sha2", + "thiserror", + "time", + "tokio", + "tokio-stream", + "url", +] + [[package]] name = "rust_decimal" version = "1.32.0" @@ -4106,6 +4576,23 @@ dependencies = [ "rust_decimal_macros", ] +[[package]] +name = "rxml" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98f186c7a2f3abbffb802984b7f1dfd65dac8be1aafdaabbca4137f53f0dff7" +dependencies = [ + "bytes", + "rxml_validation", + "smartstring", +] + +[[package]] +name = "rxml_validation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" + [[package]] name = "ryu" version = "1.0.15" @@ -4145,6 +4632,23 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scraper" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" +dependencies = [ + "ahash 0.8.3", + "cssparser", + "ego-tree", + "getopts", + "html5ever", + "once_cell", + "selectors", + "smallvec", + "tendril", +] + [[package]] name = "sct" version = "0.7.0" @@ -4184,6 +4688,25 @@ dependencies = [ "libc", ] +[[package]] +name = "selectors" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" +dependencies = [ + "bitflags 2.4.0", + "cssparser", + "derive_more", + "fxhash", + "log", + "new_debug_unreachable", + "phf 0.10.1", + "phf_codegen 0.10.0", + "precomputed-hash", + "servo_arc", + "smallvec", +] + [[package]] name = "serde" version = "1.0.188" @@ -4249,6 +4772,15 @@ dependencies = [ "serde", ] +[[package]] +name = "servo_arc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "sha1" version = "0.10.5" @@ -4289,16 +4821,19 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b0c213#b0c213b5c0b941e2013b0126e200f98201a82f54" dependencies = [ "anyhow", + "gotrue-entity", "opener", "reqwest", + "rust-s3", "serde", "serde_json", "serde_repr", "thiserror", "url", + "uuid", ] [[package]] @@ -4373,6 +4908,17 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + [[package]] name = "socket2" version = "0.4.9" @@ -4492,6 +5038,12 @@ dependencies = [ "url", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -4499,17 +5051,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "storage-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f8f6a#8f8f6af0f9fa1229d43e0dcbc54c62cc41ccaa3b" +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ - "chrono", - "collab-define", + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", "serde", - "serde_json", - "sqlx", - "uuid", - "validator", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", ] [[package]] @@ -4623,6 +5187,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "tera" version = "1.19.1" @@ -4696,17 +5271,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.28" @@ -4714,8 +5278,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ "deranged", + "itoa", "serde", "time-core", + "time-macros", ] [[package]] @@ -4724,6 +5290,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +[[package]] +name = "time-macros" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -4851,9 +5426,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", @@ -5075,13 +5650,13 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", @@ -5231,7 +5806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", ] @@ -5258,7 +5833,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" dependencies = [ - "idna", + "idna 0.4.0", "lazy_static", "regex", "serde", @@ -5337,12 +5912,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5591,17 +6160,6 @@ dependencies = [ "tap", ] -[[package]] -name = "y-sync" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54d34b68ec4514a0659838c2b1ba867c571b20b3804a1338dacf4fa9062d801" -dependencies = [ - "lib0", - "thiserror", - "yrs", -] - [[package]] name = "yaml-rust" version = "0.4.5" @@ -5641,7 +6199,7 @@ dependencies = [ "hmac", "pbkdf2 0.11.0", "sha1", - "time 0.3.28", + "time", "zstd", ] diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index f61ea33168..07fc8ab5b0 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -77,9 +77,12 @@ lto = false incremental = false [patch.crates-io] -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f8f6a" } - -# ⚠️⚠️⚠️ +# Please using the following command to update the revision id +# Current directory: frontend +# Run the script: +# scripts/tool/update_client_api_rev.sh new_rev_id +# ⚠️⚠️⚠️️ +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b0c213" } # Please use the following script to update collab. # Working directory: frontend # @@ -89,12 +92,11 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f8 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-sync-protocol = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } -collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e37ee7" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } +collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "86c5e8" } diff --git a/frontend/rust-lib/collab-integrate/src/collab_builder.rs b/frontend/rust-lib/collab-integrate/src/collab_builder.rs index b0e1cbb59d..0ea60762ee 100644 --- a/frontend/rust-lib/collab-integrate/src/collab_builder.rs +++ b/frontend/rust-lib/collab-integrate/src/collab_builder.rs @@ -201,7 +201,17 @@ impl AppFlowyCollabBuilder { CollabSource::AFCloud => { #[cfg(feature = "appflowy_cloud_integrate")] { - // + let local_collab = Arc::downgrade(&collab); + let plugins = block_on( + cloud_storage.get_plugins(CollabPluginContext::AppFlowyCloud { + uid, + collab_object: collab_object.clone(), + local_collab, + }), + ); + for plugin in plugins { + collab.lock().add_plugin(plugin); + } } }, CollabSource::Supabase => { diff --git a/frontend/rust-lib/dart-ffi/src/env_serde.rs b/frontend/rust-lib/dart-ffi/src/env_serde.rs index 9b1bca69f3..ac7f3ad820 100644 --- a/frontend/rust-lib/dart-ffi/src/env_serde.rs +++ b/frontend/rust-lib/dart-ffi/src/env_serde.rs @@ -1,10 +1,12 @@ use serde::Deserialize; +use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::supabase_config::SupabaseConfiguration; #[derive(Deserialize, Debug)] pub struct AppFlowyEnv { supabase_config: SupabaseConfiguration, + appflowy_cloud_config: AFCloudConfiguration, } impl AppFlowyEnv { @@ -13,6 +15,7 @@ impl AppFlowyEnv { pub fn parser(env_str: &str) { if let Ok(env) = serde_json::from_str::(env_str) { env.supabase_config.write_env(); + env.appflowy_cloud_config.write_env(); } } } diff --git a/frontend/rust-lib/flowy-core/Cargo.toml b/frontend/rust-lib/flowy-core/Cargo.toml index 38e59635d4..531b87b627 100644 --- a/frontend/rust-lib/flowy-core/Cargo.toml +++ b/frontend/rust-lib/flowy-core/Cargo.toml @@ -31,11 +31,13 @@ collab = { version = "0.1.0" } diesel = { version = "1.4.8", features = ["sqlite"] } uuid = { version = "1.3.3", features = ["v4"] } flowy-storage = { workspace = true } +client-api = { version = "0.1.0", features = ["collab-sync"] } tracing = { version = "0.1", features = ["log"] } futures-core = { version = "0.3", default-features = false } bytes = "1.5" tokio = { version = "1.26", features = ["full"] } +tokio-stream = {version = "0.1.14", features = ["sync"]} console-subscriber = { version = "0.1.8", optional = true } parking_lot = "0.12.1" anyhow = "1.0.75" diff --git a/frontend/rust-lib/flowy-core/src/integrate/log.rs b/frontend/rust-lib/flowy-core/src/integrate/log.rs index 248b5c9b30..cdcacfe940 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/log.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/log.rs @@ -25,7 +25,7 @@ pub(crate) fn create_log_filter(level: String, with_crates: Vec) -> Stri filters.push(format!("collab_persistence={}", level)); filters.push(format!("collab_database={}", level)); filters.push(format!("collab_plugins={}", level)); - filters.push(format!("appflowy_integrate={}", level)); + filters.push(format!("collab_integrate={}", level)); filters.push(format!("collab={}", level)); filters.push(format!("flowy_user={}", level)); filters.push(format!("flowy_document2={}", level)); @@ -37,7 +37,7 @@ pub(crate) fn create_log_filter(level: String, with_crates: Vec) -> Stri filters.push(format!("dart_ffi={}", "info")); filters.push(format!("flowy_sqlite={}", "info")); - filters.push(format!("flowy_net={}", level)); + filters.push(format!("client_api={}", level)); #[cfg(feature = "profiling")] filters.push(format!("tokio={}", level)); diff --git a/frontend/rust-lib/flowy-core/src/integrate/server.rs b/frontend/rust-lib/flowy-core/src/integrate/server.rs index 522c361a91..2895582230 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/server.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/server.rs @@ -6,12 +6,12 @@ use parking_lot::RwLock; use serde_repr::*; use collab_integrate::YrsDocAction; -use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_server::af_cloud::configuration::appflowy_cloud_server_configuration; +use flowy_error::{FlowyError, FlowyResult}; use flowy_server::af_cloud::AFCloudServer; use flowy_server::local_server::{LocalServer, LocalServerDB}; use flowy_server::supabase::SupabaseServer; use flowy_server::{AppFlowyEncryption, AppFlowyServer, EncryptionImpl}; +use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::supabase_config::SupabaseConfiguration; use flowy_sqlite::kv::StorePreferences; use flowy_user::services::database::{ @@ -30,10 +30,10 @@ pub enum ServerType { /// Local server provider. /// Offline mode, no user authentication and the data is stored locally. Local = 0, - /// Self-hosted server provider. + /// AppFlowy Cloud server provider. /// The [AppFlowy-Server](https://github.com/AppFlowy-IO/AppFlowy-Cloud) is still a work in /// progress. - AppFlowyCloud = 1, + AFCloud = 1, /// Supabase server provider. /// It uses supabase postgresql database to store data and user authentication. Supabase = 2, @@ -43,7 +43,7 @@ impl Display for ServerType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ServerType::Local => write!(f, "Local"), - ServerType::AppFlowyCloud => write!(f, "AppFlowyCloud"), + ServerType::AFCloud => write!(f, "AppFlowyCloud"), ServerType::Supabase => write!(f, "Supabase"), } } @@ -111,16 +111,8 @@ impl ServerProvider { let server = Arc::new(LocalServer::new(local_db)); Ok::, FlowyError>(server) }, - ServerType::AppFlowyCloud => { - let config = appflowy_cloud_server_configuration().map_err(|e| { - FlowyError::new( - ErrorCode::InvalidAuthConfig, - format!( - "Missing self host config: {:?}. Error: {:?}", - server_type, e - ), - ) - })?; + ServerType::AFCloud => { + let config = AFCloudConfiguration::from_env()?; tracing::trace!("🔑AppFlowy cloud config: {:?}", config); let server = Arc::new(AFCloudServer::new( config, @@ -163,7 +155,7 @@ impl From for ServerType { fn from(auth_provider: AuthType) -> Self { match auth_provider { AuthType::Local => ServerType::Local, - AuthType::SelfHosted => ServerType::AppFlowyCloud, + AuthType::AFCloud => ServerType::AFCloud, AuthType::Supabase => ServerType::Supabase, } } diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index fbac71045c..39eef86637 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -2,10 +2,10 @@ use std::sync::Arc; use anyhow::Error; use bytes::Bytes; +use client_api::collab_sync::{SinkConfig, SyncObject, SyncPlugin}; use collab::core::origin::{CollabClient, CollabOrigin}; use collab::preclude::CollabPlugin; use collab_define::CollabType; -use collab_plugins::sync_plugin::{SyncObject, SyncPlugin}; use collab_integrate::collab_builder::{CollabPluginContext, CollabSource, CollabStorageProvider}; use collab_integrate::postgres::SupabaseDBPlugin; @@ -177,14 +177,14 @@ impl DatabaseCloudService for ServerProvider { fn get_collab_update( &self, object_id: &str, - object_ty: CollabType, + collab_type: CollabType, ) -> FutureResult { let server = self.get_server(&self.get_server_type()); let database_id = object_id.to_string(); FutureResult::new(async move { server? .database_service() - .get_collab_update(&database_id, object_ty) + .get_collab_update(&database_id, collab_type) .await }) } @@ -273,19 +273,31 @@ impl CollabStorageProvider for ServerProvider { collab_object, local_collab, } => { - if let Ok(server) = self.get_server(&ServerType::AppFlowyCloud) { + if let Ok(server) = self.get_server(&ServerType::AFCloud) { match server.collab_ws_channel(&collab_object.object_id).await { - Ok(Some(channel)) => { + Ok(Some((channel, ws_connect_state))) => { let origin = CollabOrigin::Client(CollabClient::new( collab_object.uid, collab_object.device_id.clone(), )); let sync_object = SyncObject::from(collab_object); let (sink, stream) = (channel.sink(), channel.stream()); - let sync_plugin = SyncPlugin::new(origin, sync_object, local_collab, sink, stream); + let sink_config = SinkConfig::new().with_timeout(6); + let sync_plugin = SyncPlugin::new( + origin, + sync_object, + local_collab, + sink, + sink_config, + stream, + Some(channel), + ws_connect_state, + ); plugins.push(Arc::new(sync_plugin)); }, - Ok(None) => {}, + Ok(None) => { + tracing::error!("🔴Failed to get collab ws channel: channel is none"); + }, Err(err) => tracing::error!("🔴Failed to get collab ws channel: {:?}", err), } } diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index b6e02a74c5..66df943338 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -232,7 +232,7 @@ impl From for CollabSource { fn from(server_type: ServerType) -> Self { match server_type { ServerType::Local => CollabSource::Local, - ServerType::AppFlowyCloud => CollabSource::Local, + ServerType::AFCloud => CollabSource::AFCloud, ServerType::Supabase => CollabSource::Supabase, } } diff --git a/frontend/rust-lib/flowy-database-deps/src/cloud.rs b/frontend/rust-lib/flowy-database-deps/src/cloud.rs index 25cc8b014a..0809942a8c 100644 --- a/frontend/rust-lib/flowy-database-deps/src/cloud.rs +++ b/frontend/rust-lib/flowy-database-deps/src/cloud.rs @@ -15,7 +15,7 @@ pub trait DatabaseCloudService: Send + Sync { fn get_collab_update( &self, object_id: &str, - object_ty: CollabType, + collab_type: CollabType, ) -> FutureResult; fn batch_get_collab_updates( diff --git a/frontend/rust-lib/flowy-database2/Cargo.toml b/frontend/rust-lib/flowy-database2/Cargo.toml index 39c084d5ae..aa4e6351ee 100644 --- a/frontend/rust-lib/flowy-database2/Cargo.toml +++ b/frontend/rust-lib/flowy-database2/Cargo.toml @@ -26,7 +26,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = {version = "1.0"} serde_repr = "0.1" lib-infra = { path = "../../../shared-lib/lib-infra" } -chrono = { version = "0.4.27", default-features = false, features = ["clock"] } +chrono = { version = "0.4.31", default-features = false, features = ["clock"] } rust_decimal = "1.28.1" rusty-money = {version = "0.4.1", features = ["iso"]} lazy_static = "1.4.0" @@ -39,7 +39,7 @@ anyhow = "1.0" async-stream = "0.3.4" rayon = "1.6.1" nanoid = "0.4.0" -async-trait = "0.1" +async-trait = "0.1.73" chrono-tz = "0.8.2" csv = "1.1.6" diff --git a/frontend/rust-lib/flowy-document2/src/document.rs b/frontend/rust-lib/flowy-document2/src/document.rs index fc4d6bd003..bfa90980a7 100644 --- a/frontend/rust-lib/flowy-document2/src/document.rs +++ b/frontend/rust-lib/flowy-document2/src/document.rs @@ -7,7 +7,6 @@ use collab::core::collab::MutexCollab; use collab_document::{blocks::DocumentData, document::Document}; use futures::StreamExt; use parking_lot::Mutex; -use tokio_stream::wrappers::WatchStream; use flowy_error::FlowyResult; @@ -61,7 +60,7 @@ fn subscribe_document_changed(doc_id: &str, document: &MutexDocument) { fn subscribe_document_snapshot_state(collab: &Arc) { let document_id = collab.lock().object_id.clone(); - let mut snapshot_state = WatchStream::new(collab.lock().subscribe_snapshot_state()); + let mut snapshot_state = collab.lock().subscribe_snapshot_state(); tokio::spawn(async move { while let Some(snapshot_state) = snapshot_state.next().await { if let Some(new_snapshot_id) = snapshot_state.snapshot_id() { @@ -79,7 +78,7 @@ fn subscribe_document_snapshot_state(collab: &Arc) { fn subscribe_document_sync_state(collab: &Arc) { let document_id = collab.lock().object_id.clone(); - let mut sync_state_stream = WatchStream::new(collab.lock().subscribe_sync_state()); + let mut sync_state_stream = collab.lock().subscribe_sync_state(); tokio::spawn(async move { while let Some(sync_state) = sync_state_stream.next().await { send_notification( diff --git a/frontend/rust-lib/flowy-error/src/code.rs b/frontend/rust-lib/flowy-error/src/code.rs index f3d1b89dec..64015aca4a 100644 --- a/frontend/rust-lib/flowy-error/src/code.rs +++ b/frontend/rust-lib/flowy-error/src/code.rs @@ -250,6 +250,9 @@ pub enum ErrorCode { #[error("Missing payload")] MissingPayload = 82, + + #[error("Permission denied")] + NotEnoughPermissions = 83, } impl ErrorCode { diff --git a/frontend/rust-lib/flowy-error/src/impl_from/cloud.rs b/frontend/rust-lib/flowy-error/src/impl_from/cloud.rs index 23d85c72b1..2c01e97e8b 100644 --- a/frontend/rust-lib/flowy-error/src/impl_from/cloud.rs +++ b/frontend/rust-lib/flowy-error/src/impl_from/cloud.rs @@ -20,6 +20,9 @@ impl From for FlowyError { client_api::error::ErrorCode::UrlMissingParameter => ErrorCode::InvalidParams, client_api::error::ErrorCode::InvalidOAuthProvider => ErrorCode::InvalidAuthConfig, client_api::error::ErrorCode::NotLoggedIn => ErrorCode::UserUnauthorized, + client_api::error::ErrorCode::NotEnoughPermissions => ErrorCode::NotEnoughPermissions, + client_api::error::ErrorCode::UserNameIsEmpty => ErrorCode::UserNameIsEmpty, + _ => ErrorCode::Internal, }; FlowyError::new(code, error.message) diff --git a/frontend/rust-lib/flowy-folder2/Cargo.toml b/frontend/rust-lib/flowy-folder2/Cargo.toml index 4a17ab1e81..2aab24d526 100644 --- a/frontend/rust-lib/flowy-folder2/Cargo.toml +++ b/frontend/rust-lib/flowy-folder2/Cargo.toml @@ -24,7 +24,7 @@ lib-infra = { path = "../../../shared-lib/lib-infra" } tokio = { version = "1.26", features = ["full"] } nanoid = "0.4.0" lazy_static = "1.4.0" -chrono = { version = "0.4.27", default-features = false, features = ["clock"] } +chrono = { version = "0.4.31", default-features = false, features = ["clock"] } strum_macros = "0.21" protobuf = {version = "2.28.0"} uuid = { version = "1.3.3", features = ["v4"] } diff --git a/frontend/rust-lib/flowy-server-config/src/af_cloud_config.rs b/frontend/rust-lib/flowy-server-config/src/af_cloud_config.rs new file mode 100644 index 0000000000..22c68976a7 --- /dev/null +++ b/frontend/rust-lib/flowy-server-config/src/af_cloud_config.rs @@ -0,0 +1,40 @@ +use serde::{Deserialize, Serialize}; + +use flowy_error::{ErrorCode, FlowyError}; + +pub const AF_CLOUD_BASE_URL: &str = "AF_CLOUD_BASE_URL"; +pub const AF_CLOUD_WS_BASE_URL: &str = "AF_CLOUD_WS_BASE_URL"; +pub const AF_CLOUD_GOTRUE_URL: &str = "AF_GOTRUE_URL"; + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct AFCloudConfiguration { + pub base_url: String, + pub base_ws_url: String, + pub gotrue_url: String, +} + +impl AFCloudConfiguration { + pub fn from_env() -> Result { + let base_url = std::env::var(AF_CLOUD_BASE_URL) + .map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing AF_CLOUD_BASE_URL"))?; + + let base_ws_url = std::env::var(AF_CLOUD_WS_BASE_URL) + .map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing AF_CLOUD_WS_BASE_URL"))?; + + let gotrue_url = std::env::var(AF_CLOUD_GOTRUE_URL) + .map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing AF_CLOUD_GOTRUE_URL"))?; + + Ok(Self { + base_url, + base_ws_url, + gotrue_url, + }) + } + + /// Write the configuration to the environment variables. + pub fn write_env(&self) { + std::env::set_var(AF_CLOUD_BASE_URL, &self.base_url); + std::env::set_var(AF_CLOUD_WS_BASE_URL, &self.base_ws_url); + std::env::set_var(AF_CLOUD_GOTRUE_URL, &self.gotrue_url); + } +} diff --git a/frontend/rust-lib/flowy-server-config/src/lib.rs b/frontend/rust-lib/flowy-server-config/src/lib.rs index 8dfcc56877..70b5bb1087 100644 --- a/frontend/rust-lib/flowy-server-config/src/lib.rs +++ b/frontend/rust-lib/flowy-server-config/src/lib.rs @@ -1 +1,2 @@ +pub mod af_cloud_config; pub mod supabase_config; diff --git a/frontend/rust-lib/flowy-server/Cargo.toml b/frontend/rust-lib/flowy-server/Cargo.toml index acf943f484..559768bf6b 100644 --- a/frontend/rust-lib/flowy-server/Cargo.toml +++ b/frontend/rust-lib/flowy-server/Cargo.toml @@ -19,11 +19,11 @@ thiserror = "1.0" tokio = { version = "1.26", features = ["sync"]} parking_lot = "0.12" lazy_static = "1.4.0" -bytes = { version = "1.0.1", features = ["serde"] } +bytes = { version = "1.5", features = ["serde"] } tokio-retry = "0.3" anyhow = "1.0" uuid = { version = "1.3.3", features = ["v4"] } -chrono = { version = "0.4.27", default-features = false, features = ["clock"] } +chrono = { version = "0.4.31", default-features = false, features = ["clock"] } collab = { version = "0.1.0" } collab-plugins = { version = "0.1.0", features = ["sync_plugin"] } collab-document = { version = "0.1.0" } @@ -42,7 +42,7 @@ flowy-storage = { workspace = true } mime_guess = "2.0" url = "2.4" tokio-util = "0.7" -client-api = { version = "0.1.0" } +client-api = { version = "0.1.0", features = ["collab-sync"] } [dev-dependencies] uuid = { version = "1.3.3", features = ["v4"] } @@ -51,3 +51,4 @@ dotenv = "0.15.0" yrs = "0.16.5" assert-json-diff = "2.0.2" serde_json = "1.0.104" +client-api = { version = "0.1.0" } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/configuration.rs b/frontend/rust-lib/flowy-server/src/af_cloud/configuration.rs deleted file mode 100644 index 3893788866..0000000000 --- a/frontend/rust-lib/flowy-server/src/af_cloud/configuration.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::convert::{TryFrom, TryInto}; - -use config::FileFormat; -use serde_aux::field_attributes::deserialize_number_from_string; - -pub const HEADER_TOKEN: &str = "token"; - -#[derive(serde::Deserialize, Clone, Debug)] -pub struct AFCloudConfiguration { - #[serde(deserialize_with = "deserialize_number_from_string")] - pub port: u16, - pub host: String, - pub http_scheme: String, - pub ws_scheme: String, -} - -pub fn appflowy_cloud_server_configuration() -> Result { - let mut settings = config::Config::default(); - let base = include_str!("./configuration/base.yaml"); - settings.merge(config::File::from_str(base, FileFormat::Yaml).required(true))?; - - let environment: Environment = std::env::var("APP_ENVIRONMENT") - .unwrap_or_else(|_| "local".to_owned()) - .try_into() - .expect("Failed to parse APP_ENVIRONMENT."); - - let custom = match environment { - Environment::Local => include_str!("./configuration/local.yaml"), - Environment::Production => include_str!("./configuration/production.yaml"), - }; - - settings.merge(config::File::from_str(custom, FileFormat::Yaml).required(true))?; - settings.try_into() -} - -impl AFCloudConfiguration { - pub fn reset_host_with_port(&mut self, host: &str, port: u16) { - self.host = host.to_owned(); - self.port = port; - } - - pub fn base_url(&self) -> String { - format!("{}://{}:{}", self.http_scheme, self.host, self.port) - } - - pub fn ws_addr(&self) -> String { - format!("{}://{}:{}/ws", self.ws_scheme, self.host, self.port) - } -} - -pub enum Environment { - Local, - Production, -} - -impl Environment { - #[allow(dead_code)] - pub fn as_str(&self) -> &'static str { - match self { - Environment::Local => "local", - Environment::Production => "production", - } - } -} - -impl TryFrom for Environment { - type Error = String; - - fn try_from(s: String) -> Result { - match s.to_lowercase().as_str() { - "local" => Ok(Self::Local), - "production" => Ok(Self::Production), - other => Err(format!( - "{} is not a supported environment. Use either `local` or `production`.", - other - )), - } - } -} diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/base.yaml b/frontend/rust-lib/flowy-server/src/af_cloud/configuration/base.yaml deleted file mode 100644 index c2d6e08b00..0000000000 --- a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/base.yaml +++ /dev/null @@ -1,5 +0,0 @@ -port: 8000 -host: 0.0.0.0 -http_scheme: http -ws_scheme: ws - diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/local.yaml b/frontend/rust-lib/flowy-server/src/af_cloud/configuration/local.yaml deleted file mode 100644 index 1ca44fcf49..0000000000 --- a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/local.yaml +++ /dev/null @@ -1,3 +0,0 @@ -host: 127.0.0.1 -http_scheme: http -ws_scheme: ws diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/production.yaml b/frontend/rust-lib/flowy-server/src/af_cloud/configuration/production.yaml deleted file mode 100644 index d16fca4590..0000000000 --- a/frontend/rust-lib/flowy-server/src/af_cloud/configuration/production.yaml +++ /dev/null @@ -1,2 +0,0 @@ -host: 0.0.0.0 - diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs index a8e154790b..a655e69f12 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs @@ -1,4 +1,6 @@ use anyhow::Error; +use client_api::entity::QueryCollabParams; +use client_api::error::ErrorCode::RecordNotFound; use collab_define::CollabType; use flowy_database_deps::cloud::{ @@ -16,10 +18,27 @@ where { fn get_collab_update( &self, - _object_id: &str, - _object_ty: CollabType, + object_id: &str, + collab_type: CollabType, ) -> FutureResult { - FutureResult::new(async move { Ok(vec![]) }) + let object_id = object_id.to_string(); + let try_get_client = self.0.try_get_client(); + FutureResult::new(async move { + let params = QueryCollabParams { + object_id, + collab_type, + }; + match try_get_client?.get_collab(params).await { + Ok(data) => Ok(vec![data]), + Err(err) => { + if err.code == RecordNotFound { + Ok(vec![]) + } else { + Err(Error::new(err)) + } + }, + } + }) } fn batch_get_collab_updates( diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs index 05f6ce2ae8..54935542c5 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs @@ -1,4 +1,8 @@ use anyhow::Error; +use client_api::entity::QueryCollabParams; +use collab::core::origin::CollabOrigin; +use collab_define::CollabType; +use collab_document::document::Document; use flowy_document_deps::cloud::*; use lib_infra::future::FutureResult; @@ -11,8 +15,17 @@ impl DocumentCloudService for AFCloudDocumentCloudServiceImpl where T: AFServer, { - fn get_document_updates(&self, _document_id: &str) -> FutureResult>, Error> { - FutureResult::new(async move { Ok(vec![]) }) + fn get_document_updates(&self, document_id: &str) -> FutureResult>, Error> { + let try_get_client = self.0.try_get_client(); + let document_id = document_id.to_string(); + FutureResult::new(async move { + let params = QueryCollabParams { + object_id: document_id.to_string(), + collab_type: CollabType::Document, + }; + let data = try_get_client?.get_collab(params).await?; + Ok(vec![data]) + }) } fn get_document_snapshots( @@ -23,7 +36,17 @@ where FutureResult::new(async move { Ok(vec![]) }) } - fn get_document_data(&self, _document_id: &str) -> FutureResult, Error> { - FutureResult::new(async move { Ok(None) }) + fn get_document_data(&self, document_id: &str) -> FutureResult, Error> { + let try_get_client = self.0.try_get_client(); + let document_id = document_id.to_string(); + FutureResult::new(async move { + let params = QueryCollabParams { + object_id: document_id.clone(), + collab_type: CollabType::Document, + }; + let updates = vec![try_get_client?.get_collab(params).await?]; + let document = Document::from_updates(CollabOrigin::Empty, updates, &document_id, vec![])?; + Ok(document.get_document_data().ok()) + }) } } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/file_storage.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/file_storage.rs new file mode 100644 index 0000000000..8710377eac --- /dev/null +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/file_storage.rs @@ -0,0 +1,43 @@ +use bytes::Bytes; +use flowy_error::FlowyError; +use flowy_storage::{FileStorageService, StorageObject}; +use lib_infra::future::FutureResult; + +use crate::af_cloud::AFServer; + +pub struct AFCloudFileStorageServiceImpl { + #[allow(dead_code)] + client: T, +} + +impl AFCloudFileStorageServiceImpl { + pub fn new(client: T) -> Self { + Self { client } + } +} + +impl FileStorageService for AFCloudFileStorageServiceImpl +where + T: AFServer, +{ + fn create_object(&self, _object: StorageObject) -> FutureResult { + FutureResult::new(async move { + // TODO + Ok("".to_owned()) + }) + } + + fn delete_object_by_url(&self, _object_url: String) -> FutureResult<(), FlowyError> { + FutureResult::new(async move { + // TODO + Ok(()) + }) + } + + fn get_object_by_url(&self, _object_url: String) -> FutureResult { + FutureResult::new(async move { + // TODO + Ok(Bytes::new()) + }) + } +} diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs index 8a8d658696..5c608e61e0 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs @@ -1,6 +1,9 @@ use anyhow::Error; +use client_api::entity::QueryCollabParams; +use collab::core::origin::CollabOrigin; +use collab_define::CollabType; -use flowy_folder_deps::cloud::{FolderCloudService, FolderData, FolderSnapshot, Workspace}; +use flowy_folder_deps::cloud::{Folder, FolderCloudService, FolderData, FolderSnapshot, Workspace}; use lib_infra::future::FutureResult; use crate::af_cloud::AFServer; @@ -15,8 +18,19 @@ where FutureResult::new(async move { todo!() }) } - fn get_folder_data(&self, _workspace_id: &str) -> FutureResult, Error> { - FutureResult::new(async move { Ok(None) }) + fn get_folder_data(&self, workspace_id: &str) -> FutureResult, Error> { + let workspace_id = workspace_id.to_string(); + let try_get_client = self.0.try_get_client(); + FutureResult::new(async move { + let params = QueryCollabParams { + object_id: workspace_id.clone(), + collab_type: CollabType::Folder, + }; + let updates = vec![try_get_client?.get_collab(params).await?]; + let folder = + Folder::from_collab_raw_data(CollabOrigin::Empty, updates, &workspace_id, vec![])?; + Ok(folder.get_folder_data()) + }) } fn get_folder_snapshots( @@ -27,15 +41,20 @@ where FutureResult::new(async move { Ok(vec![]) }) } - fn get_folder_updates( - &self, - _workspace_id: &str, - _uid: i64, - ) -> FutureResult>, Error> { - FutureResult::new(async move { Ok(vec![]) }) + fn get_folder_updates(&self, workspace_id: &str, _uid: i64) -> FutureResult>, Error> { + let workspace_id = workspace_id.to_string(); + let try_get_client = self.0.try_get_client(); + FutureResult::new(async move { + let params = QueryCollabParams { + object_id: workspace_id, + collab_type: CollabType::Folder, + }; + let updates = vec![try_get_client?.get_collab(params).await?]; + Ok(updates) + }) } fn service_name(&self) -> String { - "SelfHosted".to_string() + "AppFlowy Cloud".to_string() } } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/mod.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/mod.rs index 0280cfbefb..612ab81db4 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/mod.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/mod.rs @@ -1,9 +1,11 @@ pub(crate) use database::*; pub(crate) use document::*; +pub(crate) use file_storage::*; pub(crate) use folder::*; pub(crate) use user::*; mod database; mod document; +mod file_storage; mod folder; mod user; diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user.rs index 92ddd482ed..e288bf8959 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user.rs @@ -1,15 +1,19 @@ +use std::collections::HashMap; use std::sync::Arc; -use anyhow::Error; +use anyhow::{anyhow, Error}; +use client_api::entity::dto::UserUpdateParams; +use client_api::entity::{AFUserProfileView, AFWorkspace, AFWorkspaces, InsertCollabParams}; use collab_define::CollabObject; -use flowy_error::FlowyError; +use flowy_error::{ErrorCode, FlowyError}; use flowy_user_deps::cloud::UserCloudService; use flowy_user_deps::entities::*; use lib_infra::box_any::BoxAny; use lib_infra::future::FutureResult; use crate::af_cloud::{AFCloudClient, AFServer}; +use crate::supabase::define::{USER_DEVICE_ID, USER_SIGN_IN_URL}; pub(crate) struct AFCloudUserAuthServiceImpl { server: T, @@ -25,67 +29,151 @@ impl UserCloudService for AFCloudUserAuthServiceImpl where T: AFServer, { - fn sign_up(&self, params: BoxAny) -> FutureResult { + fn sign_up(&self, params: BoxAny) -> FutureResult { let try_get_client = self.server.try_get_client(); FutureResult::new(async move { - let params = params.unbox_or_error::()?; + let params = oauth_params_from_box_any(params)?; let resp = user_sign_up_request(try_get_client?, params).await?; Ok(resp) }) } - fn sign_in(&self, _params: BoxAny) -> FutureResult { - todo!() + // Zack: Not sure if this is needed anymore since sign_up handles both cases + fn sign_in(&self, params: BoxAny) -> FutureResult { + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let client = try_get_client?; + let params = oauth_params_from_box_any(params)?; + let resp = user_sign_in_with_url(client, params).await?; + Ok(resp) + }) } fn sign_out(&self, _token: Option) -> FutureResult<(), Error> { - todo!() + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { Ok(try_get_client?.sign_out().await?) }) + } + + fn generate_sign_in_callback_url(&self, email: &str) -> FutureResult { + let email = email.to_string(); + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + // TODO(nathan): replace the admin_email and admin_password with encryption key + let admin_email = std::env::var("GOTRUE_ADMIN_EMAIL").unwrap(); + let admin_password = std::env::var("GOTRUE_ADMIN_PASSWORD").unwrap(); + let url = try_get_client? + .generate_sign_in_callback_url(&admin_email, &admin_password, &email) + .await?; + Ok(url) + }) } fn update_user( &self, _credential: UserCredentials, - _params: UpdateUserProfileParams, + params: UpdateUserProfileParams, ) -> FutureResult<(), Error> { - todo!() + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let client = try_get_client?; + client + .update(UserUpdateParams { + name: params.name, + email: params.email, + password: params.password, + }) + .await?; + Ok(()) + }) } fn get_user_profile( &self, _credential: UserCredentials, ) -> FutureResult, Error> { - todo!() + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let client = try_get_client?; + let profile = client.profile().await?; + let encryption_type = encryption_type_from_profile(&profile); + Ok(Some(UserProfile { + email: profile.email.unwrap_or("".to_string()), + name: profile.name.unwrap_or("".to_string()), + token: token_from_client(client).await.unwrap_or("".to_string()), + icon_url: "".to_owned(), + openai_key: "".to_owned(), + workspace_id: match profile.latest_workspace_id { + Some(w) => w.to_string(), + None => "".to_string(), + }, + auth_type: AuthType::AFCloud, + encryption_type, + uid: profile.uid.ok_or(anyhow!("no uid found"))?, + })) + }) } - fn get_user_workspaces( - &self, - _uid: i64, - ) -> FutureResult, Error> { - // TODO(nathan): implement the RESTful API for this - todo!() + fn get_user_workspaces(&self, _uid: i64) -> FutureResult, Error> { + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let workspaces = try_get_client?.workspaces().await?; + Ok(to_user_workspaces(workspaces)?) + }) } - fn check_user(&self, _credential: UserCredentials) -> FutureResult<(), Error> { - // TODO(nathan): implement the RESTful API for this - FutureResult::new(async { Ok(()) }) + fn check_user(&self, credential: UserCredentials) -> FutureResult<(), Error> { + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + // from params + let token = credential.token.ok_or(anyhow!("expecting token"))?; + let uuid = credential.uuid.ok_or(anyhow!("expecting uuid"))?; + let uid = credential.uid.ok_or(anyhow!("expecting uid"))?; + + // from cloud + let client = try_get_client?; + let profile = client.profile().await?; + let client_token = client.access_token()?; + + // compare and check + if uuid != profile.uuid.ok_or(anyhow!("expecting uuid"))?.to_string() { + return Err(anyhow!("uuid mismatch")); + } + if uid != profile.uid.ok_or(anyhow!("expecting uid"))? { + return Err(anyhow!("uid mismatch")); + } + if token != client_token { + return Err(anyhow!("token mismatch")); + } + Ok(()) + }) } fn add_workspace_member( &self, - _user_email: String, - _workspace_id: String, + user_email: String, + workspace_id: String, ) -> FutureResult<(), Error> { - // TODO(nathan): implement the RESTful API for this - FutureResult::new(async { Ok(()) }) + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + try_get_client? + .add_workspace_members(workspace_id.parse()?, vec![user_email]) + .await?; + Ok(()) + }) } fn remove_workspace_member( &self, - _user_email: String, - _workspace_id: String, + user_email: String, + workspace_id: String, ) -> FutureResult<(), Error> { - // TODO(nathan): implement the RESTful API for this - FutureResult::new(async { Ok(()) }) + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + try_get_client? + .remove_workspace_members(workspace_id.parse()?, vec![user_email]) + .await?; + Ok(()) + }) } fn get_user_awareness_updates(&self, _uid: i64) -> FutureResult>, Error> { @@ -100,39 +188,108 @@ where fn create_collab_object( &self, - _collab_object: &CollabObject, - _data: Vec, + collab_object: &CollabObject, + data: Vec, ) -> FutureResult<(), Error> { - // TODO(nathan): implement the RESTful API for this - FutureResult::new(async { Ok(()) }) + let try_get_client = self.server.try_get_client(); + let collab_object = collab_object.clone(); + FutureResult::new(async move { + let client = try_get_client?; + let params = InsertCollabParams::new( + collab_object.uid, + collab_object.object_id.clone(), + collab_object.collab_type.clone(), + data, + collab_object.workspace_id.clone(), + ); + client.create_collab(params).await?; + Ok(()) + }) } } pub async fn user_sign_up_request( client: Arc, - params: SignUpParams, -) -> Result { - client - .read() - .await - .sign_up(¶ms.email, ¶ms.password) - .await?; - todo!() - // tracing::info!("User signed up: {:?}", user); - // match user.confirmed_at { - // Some(_) => { - // // User is already confirmed, help her/him to sign in - // let token = client.sign_in_password(¶ms.email, ¶ms.password).await?; - // - // // TODO: - // // Query workspace list - // // Query user profile - // - // todo!() - // }, - // None => Err(FlowyError::new( - // ErrorCode::AwaitingEmailConfirmation, - // "Awaiting email confirmation".to_string(), - // )), - // } + params: AFCloudOAuthParams, +) -> Result { + user_sign_in_with_url(client, params).await +} + +pub async fn user_sign_in_with_url( + client: Arc, + params: AFCloudOAuthParams, +) -> Result { + let is_new_user = client.sign_in_url(¶ms.sign_in_url).await?; + let (profile, af_workspaces) = tokio::try_join!(client.profile(), client.workspaces())?; + + let latest_workspace = to_user_workspace( + af_workspaces + .get_latest(&profile) + .or(af_workspaces.first().cloned()) + .ok_or(anyhow!("no workspace found"))?, + )?; + + let user_workspaces = to_user_workspaces(af_workspaces)?; + let encryption_type = encryption_type_from_profile(&profile); + + Ok(AuthResponse { + user_id: profile.uid.ok_or(anyhow!("no uid found"))?, + name: profile.name.ok_or(anyhow!("no name found"))?, + latest_workspace, + user_workspaces, + email: profile.email, + token: token_from_client(client.clone()).await, + device_id: params.device_id, + encryption_type, + is_new_user, + }) +} + +async fn token_from_client(client: Arc) -> Option { + client.access_token().ok() +} + +fn encryption_type_from_profile(profile: &AFUserProfileView) -> EncryptionType { + match &profile.encryption_sign { + Some(e) => EncryptionType::SelfEncryption(e.to_string()), + None => EncryptionType::NoEncryption, + } +} + +fn to_user_workspace(af_workspace: AFWorkspace) -> Result { + Ok(UserWorkspace { + id: af_workspace.workspace_id.to_string(), + name: af_workspace + .workspace_name + .ok_or(anyhow!("no workspace_name found"))?, + created_at: af_workspace + .created_at + .ok_or(anyhow!("no created_at found"))?, + database_views_aggregate_id: af_workspace + .database_storage_id + .ok_or(anyhow!("no database_views_aggregate_id found"))? + .to_string(), + }) +} + +fn to_user_workspaces(af_workspaces: AFWorkspaces) -> Result, FlowyError> { + let mut result = Vec::with_capacity(af_workspaces.len()); + for item in af_workspaces.0.into_iter() { + let user_workspace = to_user_workspace(item)?; + result.push(user_workspace); + } + Ok(result) +} + +fn oauth_params_from_box_any(any: BoxAny) -> Result { + let map: HashMap = any.unbox_or_error()?; + let sign_in_url = map + .get(USER_SIGN_IN_URL) + .ok_or_else(|| FlowyError::new(ErrorCode::MissingAuthField, "Missing token field"))? + .as_str(); + let device_id = map.get(USER_DEVICE_ID).cloned().unwrap_or_default(); + Ok(AFCloudOAuthParams { + sign_in_url: sign_in_url.to_string(), + device_id, + }) } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/mod.rs b/frontend/rust-lib/flowy-server/src/af_cloud/mod.rs index 90ba7604f7..554e1a18d7 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/mod.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/mod.rs @@ -1,5 +1,4 @@ pub use server::*; -pub mod configuration; pub mod impls; mod server; diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/server.rs b/frontend/rust-lib/flowy-server/src/af_cloud/server.rs index f24b624cda..fbbbef4ccf 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/server.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/server.rs @@ -3,7 +3,9 @@ use std::sync::Arc; use anyhow::Error; use client_api::notify::{TokenState, TokenStateReceiver}; -use client_api::ws::{BusinessID, WSClient, WSClientConfig, WebSocketChannel}; +use client_api::ws::{ + BusinessID, WSClient, WSClientConfig, WSConnectStateReceiver, WebSocketChannel, +}; use client_api::Client; use tokio::sync::RwLock; @@ -11,18 +13,18 @@ use flowy_database_deps::cloud::DatabaseCloudService; use flowy_document_deps::cloud::DocumentCloudService; use flowy_error::{ErrorCode, FlowyError}; use flowy_folder_deps::cloud::FolderCloudService; +use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_storage::FileStorageService; use flowy_user_deps::cloud::UserCloudService; use lib_infra::future::FutureResult; -use crate::af_cloud::configuration::AFCloudConfiguration; use crate::af_cloud::impls::{ - AFCloudDatabaseCloudServiceImpl, AFCloudDocumentCloudServiceImpl, AFCloudFolderCloudServiceImpl, - AFCloudUserAuthServiceImpl, + AFCloudDatabaseCloudServiceImpl, AFCloudDocumentCloudServiceImpl, AFCloudFileStorageServiceImpl, + AFCloudFolderCloudServiceImpl, AFCloudUserAuthServiceImpl, }; use crate::AppFlowyServer; -pub(crate) type AFCloudClient = RwLock; +pub(crate) type AFCloudClient = client_api::Client; pub struct AFCloudServer { #[allow(dead_code)] @@ -41,17 +43,22 @@ impl AFCloudServer { device_id: Arc>, ) -> Self { let http_client = reqwest::Client::new(); - let api_client = client_api::Client::from(http_client, &config.base_url(), &config.ws_addr()); + let api_client = client_api::Client::from( + http_client, + &config.base_url, + &config.base_ws_url, + &config.gotrue_url, + ); let token_state_rx = api_client.subscribe_token_state(); let enable_sync = AtomicBool::new(enable_sync); let ws_client = WSClient::new(WSClientConfig { buffer_capacity: 100, - ping_per_secs: 2, + ping_per_secs: 8, retry_connect_per_pings: 5, }); let ws_client = Arc::new(RwLock::new(ws_client)); - let api_client = Arc::new(RwLock::new(api_client)); + let api_client = Arc::new(api_client); spawn_ws_conn(&device_id, token_state_rx, &ws_client, &api_client); Self { @@ -100,24 +107,24 @@ impl AppFlowyServer for AFCloudServer { fn collab_ws_channel( &self, object_id: &str, - ) -> FutureResult>, anyhow::Error> { + ) -> FutureResult, WSConnectStateReceiver)>, anyhow::Error> { if self.enable_sync.load(Ordering::SeqCst) { let object_id = object_id.to_string(); let weak_ws_client = Arc::downgrade(&self.ws_client); FutureResult::new(async move { match weak_ws_client.upgrade() { - None => { - tracing::warn!("🟡Collab WS client is dropped"); - Ok(None) - }, - Some(ws_client) => Ok( - ws_client + None => Ok(None), + Some(ws_client) => { + let channel = ws_client .read() .await .subscribe(BusinessID::CollabId, object_id) .await - .ok(), - ), + .ok(); + let connect_state_recv = ws_client.read().await.subscribe_connect_state().await; + + Ok(channel.map(|c| (c, connect_state_recv))) + }, } }) } else { @@ -126,7 +133,8 @@ impl AppFlowyServer for AFCloudServer { } fn file_storage(&self) -> Option> { - None + let client = AFServerImpl(self.get_client()); + Some(Arc::new(AFCloudFileStorageServiceImpl::new(client))) } } @@ -138,8 +146,34 @@ fn spawn_ws_conn( device_id: &Arc>, mut token_state_rx: TokenStateReceiver, ws_client: &Arc>, - api_client: &Arc>, + api_client: &Arc, ) { + let weak_device_id = Arc::downgrade(device_id); + let weak_ws_client = Arc::downgrade(ws_client); + let weak_api_client = Arc::downgrade(api_client); + + tokio::spawn(async move { + if let Some(ws_client) = weak_ws_client.upgrade() { + let mut state_recv = ws_client.read().await.subscribe_connect_state().await; + while let Ok(state) = state_recv.recv().await { + if !state.is_timeout() { + continue; + } + + // Try to reconnect if the connection is timed out. + if let (Some(api_client), Some(device_id)) = + (weak_api_client.upgrade(), weak_device_id.upgrade()) + { + let device_id = device_id.read().clone(); + if let Ok(ws_addr) = api_client.ws_url(&device_id) { + tracing::info!("🟢WebSocket Reconnecting"); + let _ = ws_client.write().await.connect(ws_addr).await; + } + } + } + } + }); + let weak_device_id = Arc::downgrade(device_id); let weak_ws_client = Arc::downgrade(ws_client); let weak_api_client = Arc::downgrade(api_client); @@ -154,15 +188,14 @@ fn spawn_ws_conn( weak_device_id.upgrade(), ) { let device_id = device_id.read().clone(); - if let Ok(ws_addr) = api_client.read().await.ws_url(&device_id) { - tracing::info!("🟢Connecting to websocket"); + if let Ok(ws_addr) = api_client.ws_url(&device_id) { let _ = ws_client.write().await.connect(ws_addr).await; } } }, TokenState::Invalid => { if let Some(ws_client) = weak_ws_client.upgrade() { - tracing::info!("🟡Disconnecting from websocket"); + tracing::info!("🟡WebSocket Disconnecting"); ws_client.write().await.disconnect().await; } }, diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/database.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/database.rs index a8d9958f96..472e851bc7 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/database.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/database.rs @@ -12,7 +12,7 @@ impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl { fn get_collab_update( &self, _object_id: &str, - _object_ty: CollabType, + _collab_type: CollabType, ) -> FutureResult { FutureResult::new(async move { Ok(vec![]) }) } diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs index 12a64952fb..2c22e2d9d8 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs @@ -24,7 +24,7 @@ pub(crate) struct LocalServerUserAuthServiceImpl { } impl UserCloudService for LocalServerUserAuthServiceImpl { - fn sign_up(&self, params: BoxAny) -> FutureResult { + fn sign_up(&self, params: BoxAny) -> FutureResult { FutureResult::new(async move { let params = params.unbox_or_error::()?; let uid = ID_GEN.lock().next_id(); @@ -35,7 +35,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { } else { params.name.clone() }; - Ok(SignUpResponse { + Ok(AuthResponse { user_id: uid, name: user_name, latest_workspace: user_workspace.clone(), @@ -49,7 +49,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { }) } - fn sign_in(&self, params: BoxAny) -> FutureResult { + fn sign_in(&self, params: BoxAny) -> FutureResult { let db = self.db.clone(); FutureResult::new(async move { let params: SignInParams = params.unbox_or_error::()?; @@ -58,11 +58,12 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { let user_workspace = db .get_user_workspace(uid)? .unwrap_or_else(make_user_workspace); - Ok(SignInResponse { + Ok(AuthResponse { user_id: uid, name: params.name, latest_workspace: user_workspace.clone(), user_workspaces: vec![user_workspace], + is_new_user: false, email: Some(params.email), token: None, device_id: params.device_id, @@ -75,6 +76,14 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { FutureResult::new(async { Ok(()) }) } + fn generate_sign_in_callback_url(&self, _email: &str) -> FutureResult { + FutureResult::new(async { + Err(anyhow::anyhow!( + "Can't generate callback url when using offline mode" + )) + }) + } + fn update_user( &self, _credential: UserCredentials, diff --git a/frontend/rust-lib/flowy-server/src/server.rs b/frontend/rust-lib/flowy-server/src/server.rs index bb28cb907d..1ab246ca17 100644 --- a/frontend/rust-lib/flowy-server/src/server.rs +++ b/frontend/rust-lib/flowy-server/src/server.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use client_api::ws::WebSocketChannel; +use client_api::ws::{WSConnectStateReceiver, WebSocketChannel}; use collab_define::CollabObject; use collab_plugins::cloud_storage::RemoteCollabStorage; use parking_lot::RwLock; @@ -94,7 +94,7 @@ pub trait AppFlowyServer: Send + Sync + 'static { fn collab_ws_channel( &self, _object_id: &str, - ) -> FutureResult>, anyhow::Error> { + ) -> FutureResult, WSConnectStateReceiver)>, anyhow::Error> { FutureResult::new(async { Ok(None) }) } diff --git a/frontend/rust-lib/flowy-server/src/supabase/api/database.rs b/frontend/rust-lib/flowy-server/src/supabase/api/database.rs index 57d5be273e..27b88fa445 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/api/database.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/api/database.rs @@ -29,7 +29,7 @@ where fn get_collab_update( &self, object_id: &str, - object_ty: CollabType, + collab_type: CollabType, ) -> FutureResult { let try_get_postgrest = self.server.try_get_weak_postgrest(); let object_id = object_id.to_string(); @@ -38,7 +38,7 @@ where tx.send( async move { let postgrest = try_get_postgrest?; - let updates = FetchObjectUpdateAction::new(object_id.to_string(), object_ty, postgrest) + let updates = FetchObjectUpdateAction::new(object_id.to_string(), collab_type, postgrest) .run_with_fix_interval(5, 10) .await?; Ok(updates) diff --git a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs index cc539a9c69..2a61d42a0c 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::future::Future; use std::iter::Take; use std::pin::Pin; @@ -63,11 +64,11 @@ impl UserCloudService for SupabaseUserServiceImpl where T: SupabaseServerService, { - fn sign_up(&self, params: BoxAny) -> FutureResult { + fn sign_up(&self, params: BoxAny) -> FutureResult { let try_get_postgrest = self.server.try_get_postgrest(); FutureResult::new(async move { let postgrest = try_get_postgrest?; - let params = third_party_params_from_box_any(params)?; + let params = oauth_params_from_box_any(params)?; let is_new_user = postgrest .from(USER_TABLE) .select("uid") @@ -117,7 +118,7 @@ where user_profile.name }; - Ok(SignUpResponse { + Ok(AuthResponse { user_id: user_profile.uid, name: user_name, latest_workspace: latest_workspace.unwrap(), @@ -131,11 +132,11 @@ where }) } - fn sign_in(&self, params: BoxAny) -> FutureResult { + fn sign_in(&self, params: BoxAny) -> FutureResult { let try_get_postgrest = self.server.try_get_postgrest(); FutureResult::new(async move { let postgrest = try_get_postgrest?; - let params = third_party_params_from_box_any(params)?; + let params = oauth_params_from_box_any(params)?; let uuid = params.uuid; let response = get_user_profile(postgrest.clone(), GetUserProfileParams::Uuid(uuid)) .await? @@ -146,11 +147,12 @@ where .find(|user_workspace| user_workspace.id == response.latest_workspace_id) .cloned(); - Ok(SignInResponse { + Ok(AuthResponse { user_id: response.uid, name: DEFAULT_USER_NAME(), latest_workspace: latest_workspace.unwrap(), user_workspaces, + is_new_user: false, email: None, token: None, device_id: params.device_id, @@ -163,6 +165,14 @@ where FutureResult::new(async { Ok(()) }) } + fn generate_sign_in_callback_url(&self, _email: &str) -> FutureResult { + FutureResult::new(async { + Err(anyhow::anyhow!( + "Can't generate callback url when using supabase" + )) + }) + } + fn update_user( &self, _credential: UserCredentials, @@ -624,3 +634,15 @@ fn empty_workspace_update(collab_object: &CollabObject) -> Vec { folder.set_current_workspace(&workspace_id); collab.encode_as_update_v1().0 } + +fn oauth_params_from_box_any(any: BoxAny) -> Result { + let map: HashMap = any.unbox_or_error()?; + let uuid = uuid_from_map(&map)?; + let email = map.get("email").cloned().unwrap_or_default(); + let device_id = map.get("device_id").cloned().unwrap_or_default(); + Ok(SupabaseOAuthParams { + uuid, + email, + device_id, + }) +} diff --git a/frontend/rust-lib/flowy-server/src/supabase/define.rs b/frontend/rust-lib/flowy-server/src/supabase/define.rs index 31b4e097f5..558d9b68f6 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/define.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/define.rs @@ -11,6 +11,7 @@ pub const AF_COLLAB_SNAPSHOT_CREATED_AT_COLUMN: &str = "created_at"; pub const AF_COLLAB_SNAPSHOT_TABLE: &str = "af_collab_snapshot"; pub const USER_UUID: &str = "uuid"; +pub const USER_SIGN_IN_URL: &str = "sign_in_url"; pub const USER_UID: &str = "uid"; pub const OWNER_USER_UID: &str = "owner_uid"; pub const USER_EMAIL: &str = "email"; diff --git a/frontend/rust-lib/flowy-server/tests/af_cloud_test/mod.rs b/frontend/rust-lib/flowy-server/tests/af_cloud_test/mod.rs new file mode 100644 index 0000000000..94ad2e2e1d --- /dev/null +++ b/frontend/rust-lib/flowy-server/tests/af_cloud_test/mod.rs @@ -0,0 +1,2 @@ +mod user_test; +mod util; diff --git a/frontend/rust-lib/flowy-server/tests/af_cloud_test/user_test.rs b/frontend/rust-lib/flowy-server/tests/af_cloud_test/user_test.rs new file mode 100644 index 0000000000..f336a913c0 --- /dev/null +++ b/frontend/rust-lib/flowy-server/tests/af_cloud_test/user_test.rs @@ -0,0 +1,21 @@ +use flowy_server::AppFlowyServer; +use flowy_user_deps::entities::AuthResponse; +use lib_infra::box_any::BoxAny; + +use crate::af_cloud_test::util::{ + af_cloud_server, af_cloud_sign_up_param, generate_test_email, get_af_cloud_config, +}; + +#[tokio::test] +async fn sign_up_test() { + if let Some(config) = get_af_cloud_config() { + let server = af_cloud_server(config.clone()); + let user_service = server.user_service(); + let email = generate_test_email(); + let params = af_cloud_sign_up_param(&email, &config).await; + let resp: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + assert_eq!(resp.email.unwrap(), email); + assert!(resp.is_new_user); + assert_eq!(resp.user_workspaces.len(), 1); + } +} diff --git a/frontend/rust-lib/flowy-server/tests/af_cloud_test/util.rs b/frontend/rust-lib/flowy-server/tests/af_cloud_test/util.rs new file mode 100644 index 0000000000..049afcd0d4 --- /dev/null +++ b/frontend/rust-lib/flowy-server/tests/af_cloud_test/util.rs @@ -0,0 +1,57 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use parking_lot::RwLock; +use uuid::Uuid; + +use flowy_server::af_cloud::AFCloudServer; +use flowy_server::supabase::define::{USER_DEVICE_ID, USER_SIGN_IN_URL}; +use flowy_server_config::af_cloud_config::AFCloudConfiguration; + +use crate::setup_log; + +pub fn get_af_cloud_config() -> Option { + dotenv::from_filename("./.env.ci").ok()?; + setup_log(); + AFCloudConfiguration::from_env().ok() +} + +pub fn af_cloud_server(config: AFCloudConfiguration) -> Arc { + let fake_device_id = uuid::Uuid::new_v4().to_string(); + let device_id = Arc::new(RwLock::new(fake_device_id)); + Arc::new(AFCloudServer::new(config, true, device_id)) +} + +pub async fn generate_sign_in_url(user_email: &str, config: &AFCloudConfiguration) -> String { + let http_client = reqwest::Client::new(); + let api_client = client_api::Client::from( + http_client, + &config.base_url, + &config.base_ws_url, + &config.gotrue_url, + ); + + let admin_email = std::env::var("GOTRUE_ADMIN_EMAIL").unwrap(); + let admin_password = std::env::var("GOTRUE_ADMIN_PASSWORD").unwrap(); + api_client + .generate_sign_in_callback_url(&admin_email, &admin_password, user_email) + .await + .unwrap() +} + +pub async fn af_cloud_sign_up_param( + email: &str, + config: &AFCloudConfiguration, +) -> HashMap { + let mut params = HashMap::new(); + params.insert( + USER_SIGN_IN_URL.to_string(), + generate_sign_in_url(email, config).await, + ); + params.insert(USER_DEVICE_ID.to_string(), Uuid::new_v4().to_string()); + params +} + +pub fn generate_test_email() -> String { + format!("{}@test.com", Uuid::new_v4()) +} diff --git a/frontend/rust-lib/flowy-server/tests/main.rs b/frontend/rust-lib/flowy-server/tests/main.rs index edbbb44472..cd827b9b9d 100644 --- a/frontend/rust-lib/flowy-server/tests/main.rs +++ b/frontend/rust-lib/flowy-server/tests/main.rs @@ -4,6 +4,7 @@ use tracing_subscriber::fmt::Subscriber; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::EnvFilter; +mod af_cloud_test; mod supabase_test; pub fn setup_log() { diff --git a/frontend/rust-lib/flowy-server/tests/supabase_test/database_test.rs b/frontend/rust-lib/flowy-server/tests/supabase_test/database_test.rs index 94dbc344df..2944b2f149 100644 --- a/frontend/rust-lib/flowy-server/tests/supabase_test/database_test.rs +++ b/frontend/rust-lib/flowy-server/tests/supabase_test/database_test.rs @@ -1,7 +1,7 @@ use collab_define::{CollabObject, CollabType}; use uuid::Uuid; -use flowy_user_deps::entities::SignUpResponse; +use flowy_user_deps::entities::AuthResponse; use lib_infra::box_any::BoxAny; use crate::supabase_test::util::{ @@ -18,7 +18,7 @@ async fn supabase_create_database_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); let collab_service = collab_service(); let database_service = database_service(); diff --git a/frontend/rust-lib/flowy-server/tests/supabase_test/folder_test.rs b/frontend/rust-lib/flowy-server/tests/supabase_test/folder_test.rs index e395f7bf20..b3414b626c 100644 --- a/frontend/rust-lib/flowy-server/tests/supabase_test/folder_test.rs +++ b/frontend/rust-lib/flowy-server/tests/supabase_test/folder_test.rs @@ -6,7 +6,7 @@ use yrs::types::ToJson; use yrs::updates::decoder::Decode; use yrs::{merge_updates_v1, Array, Doc, Map, MapPrelim, ReadTxn, StateVector, Transact, Update}; -use flowy_user_deps::entities::SignUpResponse; +use flowy_user_deps::entities::AuthResponse; use lib_infra::box_any::BoxAny; use crate::supabase_test::util::{ @@ -37,7 +37,7 @@ async fn supabase_get_folder_test() { let collab_service = collab_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); let collab_object = CollabObject::new( user.user_id, @@ -111,7 +111,7 @@ async fn supabase_duplicate_updates_test() { let collab_service = collab_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); let collab_object = CollabObject::new( user.user_id, @@ -218,7 +218,7 @@ async fn supabase_diff_state_vector_test() { let collab_service = collab_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); let collab_object = CollabObject::new( user.user_id, diff --git a/frontend/rust-lib/flowy-server/tests/supabase_test/user_test.rs b/frontend/rust-lib/flowy-server/tests/supabase_test/user_test.rs index 83ca62a919..18e92fe4af 100644 --- a/frontend/rust-lib/flowy-server/tests/supabase_test/user_test.rs +++ b/frontend/rust-lib/flowy-server/tests/supabase_test/user_test.rs @@ -17,7 +17,7 @@ async fn supabase_user_sign_up_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); assert!(!user.latest_workspace.id.is_empty()); assert!(!user.user_workspaces.is_empty()); assert!(!user.latest_workspace.database_views_aggregate_id.is_empty()); @@ -31,11 +31,11 @@ async fn supabase_user_sign_up_with_existing_uuid_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let _user: SignUpResponse = user_service + let _user: AuthResponse = user_service .sign_up(BoxAny::new(params.clone())) .await .unwrap(); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); assert!(!user.latest_workspace.id.is_empty()); assert!(!user.latest_workspace.database_views_aggregate_id.is_empty()); assert!(!user.user_workspaces.is_empty()); @@ -49,7 +49,7 @@ async fn supabase_update_user_profile_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service + let user: AuthResponse = user_service .sign_up(BoxAny::new(params.clone())) .await .unwrap(); @@ -87,7 +87,7 @@ async fn supabase_get_user_profile_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service + let user: AuthResponse = user_service .sign_up(BoxAny::new(params.clone())) .await .unwrap(); @@ -123,7 +123,7 @@ async fn user_encryption_sign_test() { let user_service = user_auth_service(); let uuid = Uuid::new_v4().to_string(); let params = third_party_sign_up_param(uuid); - let user: SignUpResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); + let user: AuthResponse = user_service.sign_up(BoxAny::new(params)).await.unwrap(); // generate encryption sign let secret = generate_encryption_secret(); diff --git a/frontend/rust-lib/flowy-server/tests/supabase_test/util.rs b/frontend/rust-lib/flowy-server/tests/supabase_test/util.rs index 95bcc05fdc..b22fe1b925 100644 --- a/frontend/rust-lib/flowy-server/tests/supabase_test/util.rs +++ b/frontend/rust-lib/flowy-server/tests/supabase_test/util.rs @@ -37,7 +37,7 @@ pub fn get_supabase_dev_config() -> Option { } pub fn collab_service() -> Arc { - let (server, encryption_impl) = appflowy_server(None); + let (server, encryption_impl) = supabase_server_service(None); Arc::new(SupabaseCollabStorageImpl::new( server, None, @@ -46,17 +46,17 @@ pub fn collab_service() -> Arc { } pub fn database_service() -> Arc { - let (server, _encryption_impl) = appflowy_server(None); + let (server, _encryption_impl) = supabase_server_service(None); Arc::new(SupabaseDatabaseServiceImpl::new(server)) } pub fn user_auth_service() -> Arc { - let (server, _encryption_impl) = appflowy_server(None); + let (server, _encryption_impl) = supabase_server_service(None); Arc::new(SupabaseUserServiceImpl::new(server, vec![], None)) } pub fn folder_service() -> Arc { - let (server, _encryption_impl) = appflowy_server(None); + let (server, _encryption_impl) = supabase_server_service(None); Arc::new(SupabaseFolderServiceImpl::new(server)) } @@ -77,7 +77,7 @@ pub fn file_storage_service() -> Arc { pub fn encryption_folder_service( secret: Option, ) -> (Arc, Arc) { - let (server, encryption_impl) = appflowy_server(secret); + let (server, encryption_impl) = supabase_server_service(secret); let service = Arc::new(SupabaseFolderServiceImpl::new(server)); (service, encryption_impl) } @@ -86,7 +86,7 @@ pub fn encryption_folder_service( pub fn encryption_collab_service( secret: Option, ) -> (Arc, Arc) { - let (server, encryption_impl) = appflowy_server(secret); + let (server, encryption_impl) = supabase_server_service(secret); let service = Arc::new(SupabaseCollabStorageImpl::new( server, None, @@ -120,7 +120,7 @@ pub async fn print_encryption_folder_snapshot(folder_id: &str, encryption_secret println!("{}", serde_json::to_string_pretty(&json).unwrap()); } -pub fn appflowy_server( +pub fn supabase_server_service( encryption_secret: Option, ) -> (SupabaseServerServiceImpl, Arc) { let config = SupabaseConfiguration::from_env().unwrap(); diff --git a/frontend/rust-lib/flowy-test/Cargo.toml b/frontend/rust-lib/flowy-test/Cargo.toml index 18ec1cf419..c2b613ac5a 100644 --- a/frontend/rust-lib/flowy-test/Cargo.toml +++ b/frontend/rust-lib/flowy-test/Cargo.toml @@ -35,22 +35,22 @@ nanoid = "0.4.0" tracing = { version = "0.1.27" } parking_lot = "0.12.1" uuid = { version = "1.3.3", features = ["serde", "v4"] } - -[dev-dependencies] -dotenv = "0.15.0" -tempdir = "0.3.7" -uuid = { version = "1.3.3", features = ["v4"] } collab = { version = "0.1.0" } collab-document = { version = "0.1.0" } collab-folder = { version = "0.1.0" } collab-database = { version = "0.1.0" } collab-plugins = { version = "0.1.0" } collab-define = { version = "0.1.0" } + +[dev-dependencies] +dotenv = "0.15.0" +tempdir = "0.3.7" +uuid = { version = "1.3.3", features = ["v4"] } assert-json-diff = "2.0.2" tokio-postgres = { version = "0.7.8" } zip = "0.6.6" [features] -default = ["cloud_test"] +default = ["supabase_cloud_test"] dart = ["flowy-core/dart"] -cloud_test = [] \ No newline at end of file +supabase_cloud_test = [] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-test/src/lib.rs b/frontend/rust-lib/flowy-test/src/lib.rs index ab71ad8dbf..112805b811 100644 --- a/frontend/rust-lib/flowy-test/src/lib.rs +++ b/frontend/rust-lib/flowy-test/src/lib.rs @@ -5,6 +5,12 @@ use std::path::PathBuf; use std::sync::Arc; use bytes::Bytes; +use collab::core::collab::MutexCollab; +use collab::core::origin::CollabOrigin; +use collab::preclude::updates::decoder::Decode; +use collab::preclude::{merge_updates_v1, Update}; +use collab_document::blocks::DocumentData; +use collab_document::document::Document; use nanoid::nanoid; use parking_lot::RwLock; use protobuf::ProtobufError; @@ -21,14 +27,15 @@ use flowy_folder2::entities::*; use flowy_folder2::event_map::FolderEvent; use flowy_notification::entities::SubscribeObject; use flowy_notification::{register_notification_sender, NotificationSender}; -use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_UUID}; +use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_URL, USER_UUID}; use flowy_user::entities::{ - AuthTypePB, ThirdPartyAuthPB, UpdateCloudConfigPB, UserCloudConfigPB, UserProfilePB, + AuthTypePB, OAuthCallbackRequestPB, OAuthCallbackResponsePB, OAuthPB, UpdateCloudConfigPB, + UserCloudConfigPB, UserProfilePB, }; use flowy_user::errors::{FlowyError, FlowyResult}; use flowy_user::event_map::UserEvent::*; -use crate::document::document_event::OpenDocumentData; +use crate::document::document_event::{DocumentEventTest, OpenDocumentData}; use crate::event_builder::EventBuilder; use crate::user_event::{async_sign_up, SignUpContext}; @@ -59,10 +66,52 @@ impl FlowyCoreTest { Self::default() } + pub async fn insert_document_text(&self, document_id: &str, text: &str, index: usize) { + let document_event = DocumentEventTest::new_with_core(self.clone()); + document_event + .insert_index(document_id, text, index, None) + .await; + } + + pub async fn get_document_data(&self, view_id: &str) -> DocumentData { + let pb = EventBuilder::new(self.clone()) + .event(DocumentEvent::GetDocumentData) + .payload(OpenDocumentPayloadPB { + document_id: view_id.to_string(), + }) + .async_send() + .await + .parse::(); + + DocumentData::from(pb) + } + + pub async fn get_document_update(&self, document_id: &str) -> Vec { + let cloud_service = self.document_manager.get_cloud_service().clone(); + let remote_updates = cloud_service + .get_document_updates(document_id) + .await + .unwrap(); + + if remote_updates.is_empty() { + return vec![]; + } + + let updates = remote_updates + .iter() + .map(|update| update.as_ref()) + .collect::>(); + + merge_updates_v1(&updates).unwrap() + } + pub fn new_with_user_data_path(path: PathBuf, name: String) -> Self { let config = AppFlowyCoreConfig::new(path.to_str().unwrap(), name).log_filter( - "debug", - vec!["flowy_test".to_string(), "lib_dispatch".to_string()], + "trace", + vec![ + "flowy_test".to_string(), + // "lib_dispatch".to_string() + ], ); let inner = std::thread::spawn(|| AppFlowyCore::new(config)) @@ -120,13 +169,13 @@ impl FlowyCoreTest { pub async fn supabase_party_sign_up(&self) -> UserProfilePB { let map = third_party_sign_up_param(Uuid::new_v4().to_string()); - let payload = ThirdPartyAuthPB { + let payload = OAuthPB { map, auth_type: AuthTypePB::Supabase, }; EventBuilder::new(self.clone()) - .event(ThirdPartyAuth) + .event(OAuth) .payload(payload) .async_send() .await @@ -148,7 +197,38 @@ impl FlowyCoreTest { self.sign_up_as_guest().await.user_profile } - pub async fn third_party_sign_up_with_uuid( + pub async fn af_cloud_sign_in_with_email(&self, email: &str) -> FlowyResult { + let payload = OAuthCallbackRequestPB { + email: email.to_string(), + auth_type: AuthTypePB::AFCloud, + }; + let sign_in_url = EventBuilder::new(self.clone()) + .event(OAuthCallbackURL) + .payload(payload) + .async_send() + .await + .try_parse::()? + .sign_in_url; + + let mut map = HashMap::new(); + map.insert(USER_SIGN_IN_URL.to_string(), sign_in_url); + map.insert(USER_DEVICE_ID.to_string(), uuid::Uuid::new_v4().to_string()); + let payload = OAuthPB { + map, + auth_type: AuthTypePB::AFCloud, + }; + + let user_profile = EventBuilder::new(self.clone()) + .event(OAuth) + .payload(payload) + .async_send() + .await + .try_parse::()?; + + Ok(user_profile) + } + + pub async fn supabase_sign_up_with_uuid( &self, uuid: &str, email: Option, @@ -160,13 +240,13 @@ impl FlowyCoreTest { USER_EMAIL.to_string(), email.unwrap_or_else(|| format!("{}@appflowy.io", nanoid!(10))), ); - let payload = ThirdPartyAuthPB { + let payload = OAuthPB { map, auth_type: AuthTypePB::Supabase, }; let user_profile = EventBuilder::new(self.clone()) - .event(ThirdPartyAuth) + .event(OAuth) .payload(payload) .async_send() .await @@ -879,3 +959,14 @@ pub fn third_party_sign_up_param(uuid: String) -> HashMap { params.insert(USER_DEVICE_ID.to_string(), Uuid::new_v4().to_string()); params } + +pub fn assert_document_data_equal(collab_update: &[u8], doc_id: &str, expected: DocumentData) { + let collab = MutexCollab::new(CollabOrigin::Server, doc_id, vec![]); + collab.lock().with_origin_transact_mut(|txn| { + let update = Update::decode_v1(collab_update).unwrap(); + txn.apply_update(update); + }); + let document = Document::open(Arc::new(collab)).unwrap(); + let actual = document.get_document_data().unwrap(); + assert_eq!(actual, expected); +} diff --git a/frontend/rust-lib/flowy-test/tests/database/mod.rs b/frontend/rust-lib/flowy-test/tests/database/mod.rs index cf818e3251..d4ad853e80 100644 --- a/frontend/rust-lib/flowy-test/tests/database/mod.rs +++ b/frontend/rust-lib/flowy-test/tests/database/mod.rs @@ -1,4 +1,4 @@ mod local_test; -#[cfg(feature = "cloud_test")] +#[cfg(feature = "supabase_cloud_test")] mod supabase_test; diff --git a/frontend/rust-lib/flowy-test/tests/database/supabase_test/helper.rs b/frontend/rust-lib/flowy-test/tests/database/supabase_test/helper.rs index ade3149a7e..c1452c0e83 100644 --- a/frontend/rust-lib/flowy-test/tests/database/supabase_test/helper.rs +++ b/frontend/rust-lib/flowy-test/tests/database/supabase_test/helper.rs @@ -23,20 +23,14 @@ impl FlowySupabaseDatabaseTest { #[allow(dead_code)] pub async fn new_with_user(uuid: String) -> Option { let inner = FlowySupabaseTest::new()?; - inner - .third_party_sign_up_with_uuid(&uuid, None) - .await - .unwrap(); + inner.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); Some(Self { uuid, inner }) } pub async fn new_with_new_user() -> Option { let inner = FlowySupabaseTest::new()?; let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner - .third_party_sign_up_with_uuid(&uuid, None) - .await - .unwrap(); + let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); Some(Self { uuid, inner }) } diff --git a/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/edit_test.rs b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/edit_test.rs new file mode 100644 index 0000000000..5f6e7113e8 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/edit_test.rs @@ -0,0 +1,34 @@ +use std::time::Duration; + +use flowy_document2::entities::DocumentSyncStatePB; +use flowy_test::assert_document_data_equal; + +use crate::document::af_cloud_test::util::AFCloudDocumentTest; +use crate::util::receive_with_timeout; + +#[tokio::test] +async fn af_cloud_edit_document_test() { + if let Some(test) = AFCloudDocumentTest::new().await { + let document_id = test.create_document().await; + let cloned_test = test.clone(); + let cloned_document_id = document_id.clone(); + tokio::spawn(async move { + cloned_test + .insert_document_text(&cloned_document_id, "hello world", 0) + .await; + }); + + // wait all update are send to the remote + let mut rx = test + .notification_sender + .subscribe_with_condition::(&document_id, |pb| pb.is_finish); + receive_with_timeout(&mut rx, Duration::from_secs(15)) + .await + .unwrap(); + + let document_data = test.get_document_data(&document_id).await; + let update = test.get_document_update(&document_id).await; + assert!(!update.is_empty()); + assert_document_data_equal(&update, &document_id, document_data); + } +} diff --git a/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/mod.rs b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/mod.rs new file mode 100644 index 0000000000..b233186e5e --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/mod.rs @@ -0,0 +1,2 @@ +mod edit_test; +mod util; diff --git a/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/util.rs b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/util.rs new file mode 100644 index 0000000000..4abf56fa07 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/document/af_cloud_test/util.rs @@ -0,0 +1,37 @@ +use std::ops::Deref; + +use crate::util::{generate_test_email, AFCloudTest}; + +pub struct AFCloudDocumentTest { + inner: AFCloudTest, +} + +impl AFCloudDocumentTest { + pub async fn new() -> Option { + let inner = AFCloudTest::new()?; + let email = generate_test_email(); + let _ = inner.af_cloud_sign_in_with_email(&email).await.unwrap(); + Some(Self { inner }) + } + + pub async fn create_document(&self) -> String { + let current_workspace = self.inner.get_current_workspace().await; + let view = self + .inner + .create_document( + ¤t_workspace.workspace.id, + "my document".to_string(), + vec![], + ) + .await; + view.id + } +} + +impl Deref for AFCloudDocumentTest { + type Target = AFCloudTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} diff --git a/frontend/rust-lib/flowy-test/tests/document/mod.rs b/frontend/rust-lib/flowy-test/tests/document/mod.rs index cf818e3251..797220fc44 100644 --- a/frontend/rust-lib/flowy-test/tests/document/mod.rs +++ b/frontend/rust-lib/flowy-test/tests/document/mod.rs @@ -1,4 +1,5 @@ mod local_test; -#[cfg(feature = "cloud_test")] +mod af_cloud_test; +#[cfg(feature = "supabase_cloud_test")] mod supabase_test; diff --git a/frontend/rust-lib/flowy-test/tests/document/supabase_test/edit_test.rs b/frontend/rust-lib/flowy-test/tests/document/supabase_test/edit_test.rs new file mode 100644 index 0000000000..b0adbeac57 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/document/supabase_test/edit_test.rs @@ -0,0 +1,61 @@ +use std::time::Duration; + +use flowy_document2::entities::DocumentSyncStatePB; +use flowy_test::assert_document_data_equal; + +use crate::document::supabase_test::helper::FlowySupabaseDocumentTest; +use crate::util::receive_with_timeout; + +#[tokio::test] +async fn supabase_document_edit_sync_test() { + if let Some(test) = FlowySupabaseDocumentTest::new().await { + let view = test.create_document().await; + let document_id = view.id.clone(); + + let cloned_test = test.clone(); + let cloned_document_id = document_id.clone(); + tokio::spawn(async move { + cloned_test + .insert_document_text(&cloned_document_id, "hello world", 0) + .await; + }); + + // wait all update are send to the remote + let mut rx = test + .notification_sender + .subscribe_with_condition::(&document_id, |pb| pb.is_finish); + receive_with_timeout(&mut rx, Duration::from_secs(30)) + .await + .unwrap(); + + let document_data = test.get_document_data(&document_id).await; + let update = test.get_document_update(&document_id).await; + assert_document_data_equal(&update, &document_id, document_data); + } +} + +#[tokio::test] +async fn supabase_document_edit_sync_test2() { + if let Some(test) = FlowySupabaseDocumentTest::new().await { + let view = test.create_document().await; + let document_id = view.id.clone(); + + for i in 0..10 { + test + .insert_document_text(&document_id, "hello world", i) + .await; + } + + // wait all update are send to the remote + let mut rx = test + .notification_sender + .subscribe_with_condition::(&document_id, |pb| pb.is_finish); + receive_with_timeout(&mut rx, Duration::from_secs(30)) + .await + .unwrap(); + + let document_data = test.get_document_data(&document_id).await; + let update = test.get_document_update(&document_id).await; + assert_document_data_equal(&update, &document_id, document_data); + } +} diff --git a/frontend/rust-lib/flowy-test/tests/document/supabase_test/helper.rs b/frontend/rust-lib/flowy-test/tests/document/supabase_test/helper.rs index 651670961c..160662fc66 100644 --- a/frontend/rust-lib/flowy-test/tests/document/supabase_test/helper.rs +++ b/frontend/rust-lib/flowy-test/tests/document/supabase_test/helper.rs @@ -1,17 +1,7 @@ use std::ops::Deref; -use std::sync::Arc; -use collab::core::collab::MutexCollab; -use collab::core::origin::CollabOrigin; -use collab::preclude::updates::decoder::Decode; -use collab::preclude::{merge_updates_v1, Update}; -use collab_document::blocks::DocumentData; -use collab_document::document::Document; - -use flowy_document2::entities::{ - DocumentDataPB, OpenDocumentPayloadPB, RepeatedDocumentSnapshotPB, -}; -use flowy_document2::event_map::DocumentEvent::{GetDocumentData, GetDocumentSnapshots}; +use flowy_document2::entities::{OpenDocumentPayloadPB, RepeatedDocumentSnapshotPB}; +use flowy_document2::event_map::DocumentEvent::GetDocumentSnapshots; use flowy_folder2::entities::ViewPB; use flowy_test::event_builder::EventBuilder; @@ -25,7 +15,7 @@ impl FlowySupabaseDocumentTest { pub async fn new() -> Option { let inner = FlowySupabaseTest::new()?; let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner.third_party_sign_up_with_uuid(&uuid, None).await; + let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await; Some(Self { inner }) } @@ -41,6 +31,7 @@ impl FlowySupabaseDocumentTest { .await } + #[allow(dead_code)] pub async fn get_document_snapshots(&self, view_id: &str) -> RepeatedDocumentSnapshotPB { EventBuilder::new(self.inner.deref().clone()) .event(GetDocumentSnapshots) @@ -51,38 +42,6 @@ impl FlowySupabaseDocumentTest { .await .parse::() } - - pub async fn get_document_data(&self, view_id: &str) -> DocumentData { - let pb = EventBuilder::new(self.inner.deref().clone()) - .event(GetDocumentData) - .payload(OpenDocumentPayloadPB { - document_id: view_id.to_string(), - }) - .async_send() - .await - .parse::(); - - DocumentData::from(pb) - } - - pub async fn get_collab_update(&self, document_id: &str) -> Vec { - let cloud_service = self.document_manager.get_cloud_service().clone(); - let remote_updates = cloud_service - .get_document_updates(document_id) - .await - .unwrap(); - - if remote_updates.is_empty() { - return vec![]; - } - - let updates = remote_updates - .iter() - .map(|update| update.as_ref()) - .collect::>(); - - merge_updates_v1(&updates).unwrap() - } } impl Deref for FlowySupabaseDocumentTest { @@ -92,14 +51,3 @@ impl Deref for FlowySupabaseDocumentTest { &self.inner } } - -pub fn assert_document_data_equal(collab_update: &[u8], doc_id: &str, expected: DocumentData) { - let collab = MutexCollab::new(CollabOrigin::Server, doc_id, vec![]); - collab.lock().with_origin_transact_mut(|txn| { - let update = Update::decode_v1(collab_update).unwrap(); - txn.apply_update(update); - }); - let document = Document::open(Arc::new(collab)).unwrap(); - let actual = document.get_document_data().unwrap(); - assert_eq!(actual, expected); -} diff --git a/frontend/rust-lib/flowy-test/tests/document/supabase_test/mod.rs b/frontend/rust-lib/flowy-test/tests/document/supabase_test/mod.rs index 73c1966501..165f5fdfc0 100644 --- a/frontend/rust-lib/flowy-test/tests/document/supabase_test/mod.rs +++ b/frontend/rust-lib/flowy-test/tests/document/supabase_test/mod.rs @@ -1,3 +1,3 @@ +mod edit_test; mod file_test; mod helper; -mod test; diff --git a/frontend/rust-lib/flowy-test/tests/document/supabase_test/test.rs b/frontend/rust-lib/flowy-test/tests/document/supabase_test/test.rs deleted file mode 100644 index 5fdb689e98..0000000000 --- a/frontend/rust-lib/flowy-test/tests/document/supabase_test/test.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::ops::Deref; -use std::time::Duration; - -use flowy_document2::entities::{DocumentSnapshotStatePB, DocumentSyncStatePB}; -use flowy_document2::notification::DocumentNotification::DidUpdateDocumentSnapshotState; -use flowy_test::document::document_event::DocumentEventTest; - -use crate::document::supabase_test::helper::{ - assert_document_data_equal, FlowySupabaseDocumentTest, -}; -use crate::util::receive_with_timeout; - -#[tokio::test] -async fn supabase_initial_document_snapshot_test() { - if let Some(test) = FlowySupabaseDocumentTest::new().await { - let view = test.create_document().await; - - let mut rx = test - .notification_sender - .subscribe::(&view.id, DidUpdateDocumentSnapshotState); - - receive_with_timeout(&mut rx, Duration::from_secs(30)) - .await - .unwrap(); - - let snapshots = test.get_document_snapshots(&view.id).await; - assert_eq!(snapshots.items.len(), 1); - - let document_data = test.get_document_data(&view.id).await; - assert_document_data_equal(&snapshots.items[0].data, &view.id, document_data); - } -} - -#[tokio::test] -async fn supabase_document_edit_sync_test() { - if let Some(test) = FlowySupabaseDocumentTest::new().await { - let view = test.create_document().await; - let document_id = view.id.clone(); - - let core = test.deref().deref().clone(); - let document_event = DocumentEventTest::new_with_core(core); - document_event - .insert_index(&document_id, "hello world", 0, None) - .await; - - // wait all update are send to the remote - let mut rx = test - .notification_sender - .subscribe_with_condition::(&document_id, |pb| pb.is_finish); - receive_with_timeout(&mut rx, Duration::from_secs(30)) - .await - .unwrap(); - - let document_data = test.get_document_data(&document_id).await; - let update = test.get_collab_update(&document_id).await; - assert_document_data_equal(&update, &document_id, document_data); - } -} - -#[tokio::test] -async fn supabase_document_edit_sync_test2() { - if let Some(test) = FlowySupabaseDocumentTest::new().await { - let view = test.create_document().await; - let document_id = view.id.clone(); - let core = test.deref().deref().clone(); - let document_event = DocumentEventTest::new_with_core(core); - - for i in 0..10 { - document_event - .insert_index(&document_id, "hello world", i, None) - .await; - } - - // wait all update are send to the remote - let mut rx = test - .notification_sender - .subscribe_with_condition::(&document_id, |pb| pb.is_finish); - receive_with_timeout(&mut rx, Duration::from_secs(30)) - .await - .unwrap(); - - let document_data = test.get_document_data(&document_id).await; - let update = test.get_collab_update(&document_id).await; - assert_document_data_equal(&update, &document_id, document_data); - } -} diff --git a/frontend/rust-lib/flowy-test/tests/folder/mod.rs b/frontend/rust-lib/flowy-test/tests/folder/mod.rs index cf818e3251..d4ad853e80 100644 --- a/frontend/rust-lib/flowy-test/tests/folder/mod.rs +++ b/frontend/rust-lib/flowy-test/tests/folder/mod.rs @@ -1,4 +1,4 @@ mod local_test; -#[cfg(feature = "cloud_test")] +#[cfg(feature = "supabase_cloud_test")] mod supabase_test; diff --git a/frontend/rust-lib/flowy-test/tests/folder/supabase_test/helper.rs b/frontend/rust-lib/flowy-test/tests/folder/supabase_test/helper.rs index 48e82c78f0..02afe2a65c 100644 --- a/frontend/rust-lib/flowy-test/tests/folder/supabase_test/helper.rs +++ b/frontend/rust-lib/flowy-test/tests/folder/supabase_test/helper.rs @@ -21,7 +21,7 @@ impl FlowySupabaseFolderTest { pub async fn new() -> Option { let inner = FlowySupabaseTest::new()?; let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner.third_party_sign_up_with_uuid(&uuid, None).await; + let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await; Some(Self { inner }) } diff --git a/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/mod.rs b/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/mod.rs new file mode 100644 index 0000000000..585722915d --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/mod.rs @@ -0,0 +1 @@ +mod test; diff --git a/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/test.rs b/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/test.rs new file mode 100644 index 0000000000..5cbde63af6 --- /dev/null +++ b/frontend/rust-lib/flowy-test/tests/user/af_cloud_test/test.rs @@ -0,0 +1,13 @@ +use flowy_test::FlowyCoreTest; + +use crate::util::{generate_test_email, get_af_cloud_config}; + +#[tokio::test] +async fn af_cloud_sign_up_test() { + if get_af_cloud_config().is_some() { + let test = FlowyCoreTest::new(); + let email = generate_test_email(); + let user = test.af_cloud_sign_in_with_email(&email).await.unwrap(); + assert_eq!(user.email, email); + } +} diff --git a/frontend/rust-lib/flowy-test/tests/user/mod.rs b/frontend/rust-lib/flowy-test/tests/user/mod.rs index bcd7dec3c7..1e3198d51d 100644 --- a/frontend/rust-lib/flowy-test/tests/user/mod.rs +++ b/frontend/rust-lib/flowy-test/tests/user/mod.rs @@ -1,5 +1,6 @@ mod local_test; mod migration_test; -#[cfg(feature = "cloud_test")] +mod af_cloud_test; +#[cfg(feature = "supabase_cloud_test")] mod supabase_test; diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs index 6fa1f5b30f..f9b716b249 100644 --- a/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/auth_test.rs @@ -14,9 +14,7 @@ use flowy_server::supabase::define::{USER_EMAIL, USER_UUID}; use flowy_test::document::document_event::DocumentEventTest; use flowy_test::event_builder::EventBuilder; use flowy_test::FlowyCoreTest; -use flowy_user::entities::{ - AuthTypePB, ThirdPartyAuthPB, UpdateUserProfilePayloadPB, UserProfilePB, -}; +use flowy_user::entities::{AuthTypePB, OAuthPB, UpdateUserProfilePayloadPB, UserProfilePB}; use flowy_user::errors::ErrorCode; use flowy_user::event_map::UserEvent::*; @@ -32,13 +30,13 @@ async fn third_party_sign_up_test() { USER_EMAIL.to_string(), format!("{}@appflowy.io", nanoid!(6)), ); - let payload = ThirdPartyAuthPB { + let payload = OAuthPB { map, auth_type: AuthTypePB::Supabase, }; let response = EventBuilder::new(test.clone()) - .event(ThirdPartyAuth) + .event(OAuth) .payload(payload) .async_send() .await @@ -74,8 +72,8 @@ async fn third_party_sign_up_with_duplicated_uuid() { map.insert(USER_EMAIL.to_string(), email.clone()); let response_1 = EventBuilder::new(test.clone()) - .event(ThirdPartyAuth) - .payload(ThirdPartyAuthPB { + .event(OAuth) + .payload(OAuthPB { map: map.clone(), auth_type: AuthTypePB::Supabase, }) @@ -85,8 +83,8 @@ async fn third_party_sign_up_with_duplicated_uuid() { dbg!(&response_1); let response_2 = EventBuilder::new(test.clone()) - .event(ThirdPartyAuth) - .payload(ThirdPartyAuthPB { + .event(OAuth) + .payload(OAuthPB { map: map.clone(), auth_type: AuthTypePB::Supabase, }) @@ -103,11 +101,11 @@ async fn third_party_sign_up_with_duplicated_email() { let test = FlowyCoreTest::new(); let email = format!("{}@appflowy.io", nanoid!(6)); test - .third_party_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) + .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) .await .unwrap(); let error = test - .third_party_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) + .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) .await .err() .unwrap(); @@ -127,10 +125,7 @@ async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() { let old_workspace = test.folder_manager.get_current_workspace().await.unwrap(); let uuid = uuid::Uuid::new_v4().to_string(); - test - .third_party_sign_up_with_uuid(&uuid, None) - .await - .unwrap(); + test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); let new_views = test .folder_manager .get_current_workspace_views() @@ -159,7 +154,7 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() { let email = format!("{}@appflowy.io", nanoid!(6)); // The workspace of the guest will be migrated to the new user with given uuid let _user_profile = test - .third_party_sign_up_with_uuid(&uuid, Some(email.clone())) + .supabase_sign_up_with_uuid(&uuid, Some(email.clone())) .await .unwrap(); let old_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap(); @@ -185,7 +180,7 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() { // upload to cloud user with given uuid. This time the workspace of the guest will not be merged // because the cloud user already has a workspace test - .third_party_sign_up_with_uuid(&uuid, Some(email)) + .supabase_sign_up_with_uuid(&uuid, Some(email)) .await .unwrap(); let new_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap(); @@ -214,10 +209,7 @@ async fn check_not_exist_user_test() { async fn get_user_profile_test() { if let Some(test) = FlowySupabaseTest::new() { let uuid = uuid::Uuid::new_v4().to_string(); - test - .third_party_sign_up_with_uuid(&uuid, None) - .await - .unwrap(); + test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); let result = test.get_user_profile().await; assert!(result.is_ok()); @@ -228,10 +220,7 @@ async fn get_user_profile_test() { async fn update_user_profile_test() { if let Some(test) = FlowySupabaseTest::new() { let uuid = uuid::Uuid::new_v4().to_string(); - let profile = test - .third_party_sign_up_with_uuid(&uuid, None) - .await - .unwrap(); + let profile = test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); test .update_user_profile(UpdateUserProfilePayloadPB::new(profile.id).name("lucas")) .await; @@ -246,11 +235,11 @@ async fn update_user_profile_with_existing_email_test() { if let Some(test) = FlowySupabaseTest::new() { let email = format!("{}@appflowy.io", nanoid!(6)); let _ = test - .third_party_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) + .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) .await; let profile = test - .third_party_sign_up_with_uuid( + .supabase_sign_up_with_uuid( &uuid::Uuid::new_v4().to_string(), Some(format!("{}@appflowy.io", nanoid!(6))), ) diff --git a/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs b/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs index 1e3f9293a8..bad3ffdd5a 100644 --- a/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs +++ b/frontend/rust-lib/flowy-test/tests/user/supabase_test/workspace_test.rs @@ -4,7 +4,7 @@ use flowy_folder2::entities::WorkspaceSettingPB; use flowy_folder2::event_map::FolderEvent::GetCurrentWorkspace; use flowy_server::supabase::define::{USER_EMAIL, USER_UUID}; use flowy_test::{event_builder::EventBuilder, FlowyCoreTest}; -use flowy_user::entities::{AuthTypePB, ThirdPartyAuthPB, UserProfilePB}; +use flowy_user::entities::{AuthTypePB, OAuthPB, UserProfilePB}; use flowy_user::event_map::UserEvent::*; use crate::util::*; @@ -19,13 +19,13 @@ async fn initial_workspace_test() { USER_EMAIL.to_string(), format!("{}@gmail.com", uuid::Uuid::new_v4()), ); - let payload = ThirdPartyAuthPB { + let payload = OAuthPB { map, auth_type: AuthTypePB::Supabase, }; let _ = EventBuilder::new(test.clone()) - .event(ThirdPartyAuth) + .event(OAuth) .payload(payload) .async_send() .await diff --git a/frontend/rust-lib/flowy-test/tests/util.rs b/frontend/rust-lib/flowy-test/tests/util.rs index 04c69c5fdc..974a858d35 100644 --- a/frontend/rust-lib/flowy-test/tests/util.rs +++ b/frontend/rust-lib/flowy-test/tests/util.rs @@ -11,12 +11,14 @@ use collab_plugins::cloud_storage::RemoteCollabStorage; use nanoid::nanoid; use tokio::sync::mpsc::Receiver; use tokio::time::timeout; +use uuid::Uuid; use zip::ZipArchive; use flowy_database_deps::cloud::DatabaseCloudService; use flowy_folder_deps::cloud::{FolderCloudService, FolderSnapshot}; use flowy_server::supabase::api::*; use flowy_server::{AppFlowyEncryption, EncryptionImpl}; +use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::supabase_config::SupabaseConfiguration; use flowy_test::event_builder::EventBuilder; use flowy_test::Cleaner; @@ -211,3 +213,35 @@ pub fn unzip_history_user_db(root: &str, folder_name: &str) -> std::io::Result<( PathBuf::from(path), )) } + +pub struct AFCloudTest { + inner: FlowyCoreTest, +} + +impl AFCloudTest { + pub fn new() -> Option { + let _ = get_af_cloud_config()?; + let test = FlowyCoreTest::new(); + test.set_auth_type(AuthTypePB::AFCloud); + test.server_provider.set_auth_type(AuthType::AFCloud); + + Some(Self { inner: test }) + } +} + +impl Deref for AFCloudTest { + type Target = FlowyCoreTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +pub fn generate_test_email() -> String { + format!("{}@test.com", Uuid::new_v4()) +} + +pub fn get_af_cloud_config() -> Option { + dotenv::from_filename("./.env.ci").ok()?; + AFCloudConfiguration::from_env().ok() +} diff --git a/frontend/rust-lib/flowy-user-deps/Cargo.toml b/frontend/rust-lib/flowy-user-deps/Cargo.toml index b147033533..f4c6c69556 100644 --- a/frontend/rust-lib/flowy-user-deps/Cargo.toml +++ b/frontend/rust-lib/flowy-user-deps/Cargo.toml @@ -13,6 +13,6 @@ serde = { version = "1.0", features = ["derive"] } collab-define = { version = "0.1.0" } serde_json = { version = "1.0"} serde_repr = "0.1" -chrono = { version = "0.4.27", default-features = false, features = ["clock", "serde"] } +chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"] } anyhow = "1.0.71" tokio = { version = "1.26", features = ["sync"] } diff --git a/frontend/rust-lib/flowy-user-deps/src/cloud.rs b/frontend/rust-lib/flowy-user-deps/src/cloud.rs index 8fb7f39f5c..84b48d3c09 100644 --- a/frontend/rust-lib/flowy-user-deps/src/cloud.rs +++ b/frontend/rust-lib/flowy-user-deps/src/cloud.rs @@ -13,8 +13,7 @@ use lib_infra::box_any::BoxAny; use lib_infra::future::FutureResult; use crate::entities::{ - SignInResponse, SignUpResponse, ThirdPartyParams, UpdateUserProfileParams, UserCredentials, - UserProfile, UserWorkspace, + AuthResponse, UpdateUserProfileParams, UserCredentials, UserProfile, UserWorkspace, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -62,15 +61,18 @@ pub trait UserCloudService: Send + Sync + 'static { /// Sign up a new account. /// The type of the params is defined the this trait's implementation. /// Use the `unbox_or_error` of the [BoxAny] to get the params. - fn sign_up(&self, params: BoxAny) -> FutureResult; + fn sign_up(&self, params: BoxAny) -> FutureResult; /// Sign in an account /// The type of the params is defined the this trait's implementation. - fn sign_in(&self, params: BoxAny) -> FutureResult; + fn sign_in(&self, params: BoxAny) -> FutureResult; /// Sign out an account fn sign_out(&self, token: Option) -> FutureResult<(), Error>; + /// Generate a sign in callback url for the user with the given email + fn generate_sign_in_callback_url(&self, email: &str) -> FutureResult; + /// Using the user's token to update the user information fn update_user( &self, @@ -129,18 +131,6 @@ pub struct UserUpdate { pub encryption_sign: String, } -pub fn third_party_params_from_box_any(any: BoxAny) -> Result { - let map: HashMap = any.unbox_or_error()?; - let uuid = uuid_from_map(&map)?; - let email = map.get("email").cloned().unwrap_or_default(); - let device_id = map.get("device_id").cloned().unwrap_or_default(); - Ok(ThirdPartyParams { - uuid, - email, - device_id, - }) -} - pub fn uuid_from_map(map: &HashMap) -> Result { let uuid = map .get("uuid") diff --git a/frontend/rust-lib/flowy-user-deps/src/entities.rs b/frontend/rust-lib/flowy-user-deps/src/entities.rs index 87d1f6004c..1c32dfb83c 100644 --- a/frontend/rust-lib/flowy-user-deps/src/entities.rs +++ b/frontend/rust-lib/flowy-user-deps/src/entities.rs @@ -81,7 +81,7 @@ pub struct SignUpParams { } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SignUpResponse { +pub struct AuthResponse { pub user_id: i64, pub name: String, pub latest_workspace: UserWorkspace, @@ -93,7 +93,7 @@ pub struct SignUpResponse { pub encryption_type: EncryptionType, } -impl UserAuthResponse for SignUpResponse { +impl UserAuthResponse for AuthResponse { fn user_id(&self) -> i64 { self.user_id } @@ -129,7 +129,7 @@ impl UserAuthResponse for SignUpResponse { #[derive(Clone, Debug)] pub struct UserCredentials { - /// Currently, the token is only used when the [AuthType] is SelfHosted + /// Currently, the token is only used when the [AuthType] is AFCloud pub token: Option, /// The user id @@ -326,7 +326,7 @@ pub enum AuthType { Local = 0, /// Currently not supported. It will be supported in the future when the /// [AppFlowy-Server](https://github.com/AppFlowy-IO/AppFlowy-Server) ready. - SelfHosted = 1, + AFCloud = 1, /// It uses Supabase as the backend. Supabase = 2, } @@ -347,14 +347,19 @@ impl From for AuthType { fn from(value: i32) -> Self { match value { 0 => AuthType::Local, - 1 => AuthType::SelfHosted, + 1 => AuthType::AFCloud, 2 => AuthType::Supabase, _ => AuthType::Local, } } } -pub struct ThirdPartyParams { +pub struct SupabaseOAuthParams { pub uuid: Uuid, pub email: String, pub device_id: String, } + +pub struct AFCloudOAuthParams { + pub sign_in_url: String, + pub device_id: String, +} diff --git a/frontend/rust-lib/flowy-user/Cargo.toml b/frontend/rust-lib/flowy-user/Cargo.toml index 46e3809862..faf6ee8131 100644 --- a/frontend/rust-lib/flowy-user/Cargo.toml +++ b/frontend/rust-lib/flowy-user/Cargo.toml @@ -44,7 +44,7 @@ validator = "0.16.0" unicode-segmentation = "1.10" fancy-regex = "0.11.0" uuid = { version = "1.3.3", features = [ "v4"] } -chrono = { version = "0.4.27", default-features = false, features = ["clock"] } +chrono = { version = "0.4.31", default-features = false, features = ["clock"] } base64 = "^0.21" [dev-dependencies] diff --git a/frontend/rust-lib/flowy-user/src/entities/auth.rs b/frontend/rust-lib/flowy-user/src/entities/auth.rs index 31bb18972f..d63bc61141 100644 --- a/frontend/rust-lib/flowy-user/src/entities/auth.rs +++ b/frontend/rust-lib/flowy-user/src/entities/auth.rs @@ -79,7 +79,7 @@ impl TryInto for SignUpPayloadPB { } #[derive(ProtoBuf, Default)] -pub struct ThirdPartyAuthPB { +pub struct OAuthPB { /// Use this field to store the third party auth information. /// Different auth type has different fields. /// Supabase: @@ -92,10 +92,25 @@ pub struct ThirdPartyAuthPB { pub auth_type: AuthTypePB, } +#[derive(ProtoBuf, Default)] +pub struct OAuthCallbackRequestPB { + #[pb(index = 1)] + pub email: String, + + #[pb(index = 2)] + pub auth_type: AuthTypePB, +} + +#[derive(ProtoBuf, Default)] +pub struct OAuthCallbackResponsePB { + #[pb(index = 1)] + pub sign_in_url: String, +} + #[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)] pub enum AuthTypePB { Local = 0, - SelfHosted = 1, + AFCloud = 1, Supabase = 2, } diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index 9948b606af..4e9b2f258b 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -218,8 +218,8 @@ pub async fn get_user_setting( /// Only used for third party auth. /// Use [UserEvent::SignIn] or [UserEvent::SignUp] If the [AuthType] is Local or SelfHosted #[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn third_party_auth_handler( - data: AFPluginData, +pub async fn oauth_handler( + data: AFPluginData, manager: AFPluginState>, ) -> DataResult { let manager = upgrade_manager(manager)?; @@ -229,6 +229,21 @@ pub async fn third_party_auth_handler( data_result_ok(user_profile.into()) } +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub async fn get_oauth_url_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> DataResult { + let manager = upgrade_manager(manager)?; + let params = data.into_inner(); + let auth_type: AuthType = params.auth_type.into(); + let sign_in_url = manager + .generate_sign_in_callback_url(&auth_type, ¶ms.email) + .await?; + let resp = OAuthCallbackResponsePB { sign_in_url }; + data_result_ok(resp) +} + #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_encrypt_secret_handler( manager: AFPluginState>, diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index ab7b76cfef..0aec5f9621 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -37,7 +37,8 @@ pub fn init(user_session: Weak) -> AFPlugin { .event(UserEvent::GetCloudConfig, get_cloud_config_handler) .event(UserEvent::SetEncryptionSecret, set_encrypt_secret_handler) .event(UserEvent::CheckEncryptionSign, check_encrypt_secret_handler) - .event(UserEvent::ThirdPartyAuth, third_party_auth_handler) + .event(UserEvent::OAuth, oauth_handler) + .event(UserEvent::OAuthCallbackURL, get_oauth_url_handler) .event( UserEvent::GetAllUserWorkspaces, get_all_user_workspace_handler, @@ -229,8 +230,13 @@ pub enum UserEvent { #[event(output = "UserSettingPB")] GetUserSetting = 9, - #[event(input = "ThirdPartyAuthPB", output = "UserProfilePB")] - ThirdPartyAuth = 10, + #[event(input = "OAuthPB", output = "UserProfilePB")] + OAuth = 10, + + /// Get the OAuth callback url + /// Only use when the [AuthType] is AFCloud + #[event(input = "OAuthCallbackRequestPB", output = "OAuthCallbackResponsePB")] + OAuthCallbackURL = 11, #[event(input = "UpdateCloudConfigPB")] SetCloudConfig = 13, diff --git a/frontend/rust-lib/flowy-user/src/manager.rs b/frontend/rust-lib/flowy-user/src/manager.rs index 998482c904..aa365f6354 100644 --- a/frontend/rust-lib/flowy-user/src/manager.rs +++ b/frontend/rust-lib/flowy-user/src/manager.rs @@ -195,7 +195,7 @@ impl UserManager { auth_type: AuthType, ) -> Result { self.update_auth_type(&auth_type).await; - let response: SignInResponse = self + let response: AuthResponse = self .cloud_services .get_user_service()? .sign_in(params) @@ -252,7 +252,7 @@ impl UserManager { let migration_user = self.get_migration_user(&auth_type).await; let auth_service = self.cloud_services.get_user_service()?; - let response: SignUpResponse = auth_service.sign_up(params).await?; + let response: AuthResponse = auth_service.sign_up(params).await?; let user_profile = UserProfile::from((&response, &auth_type)); if user_profile.encryption_type.is_need_encrypt_secret() { self @@ -300,7 +300,7 @@ impl UserManager { &self, user_profile: &UserProfile, migration_user: Option, - response: SignUpResponse, + response: AuthResponse, auth_type: &AuthType, ) -> FlowyResult<()> { let new_session = Session::from(&response); @@ -543,6 +543,18 @@ impl UserManager { Ok(()) } + pub(crate) async fn generate_sign_in_callback_url( + &self, + auth_type: &AuthType, + email: &str, + ) -> Result { + self.update_auth_type(auth_type).await; + + let auth_service = self.cloud_services.get_user_service()?; + let url = auth_service.generate_sign_in_callback_url(email).await?; + Ok(url) + } + async fn save_auth_data( &self, response: &impl UserAuthResponse, diff --git a/frontend/rust-lib/flowy-user/src/services/entities.rs b/frontend/rust-lib/flowy-user/src/services/entities.rs index eba4304c0a..e1396a723a 100644 --- a/frontend/rust-lib/flowy-user/src/services/entities.rs +++ b/frontend/rust-lib/flowy-user/src/services/entities.rs @@ -7,8 +7,8 @@ use serde::de::{Deserializer, MapAccess, Visitor}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use flowy_user_deps::entities::{AuthResponse, UserProfile, UserWorkspace}; use flowy_user_deps::entities::{AuthType, UserAuthResponse}; -use flowy_user_deps::entities::{SignUpResponse, UserProfile, UserWorkspace}; use crate::entities::AuthTypePB; use crate::migrations::MigrationUser; @@ -162,7 +162,7 @@ impl From for AuthType { match pb { AuthTypePB::Supabase => AuthType::Supabase, AuthTypePB::Local => AuthType::Local, - AuthTypePB::SelfHosted => AuthType::SelfHosted, + AuthTypePB::AFCloud => AuthType::AFCloud, } } } @@ -172,7 +172,7 @@ impl From for AuthTypePB { match auth_type { AuthType::Supabase => AuthTypePB::Supabase, AuthType::Local => AuthTypePB::Local, - AuthType::SelfHosted => AuthTypePB::SelfHosted, + AuthType::AFCloud => AuthTypePB::AFCloud, } } } @@ -206,7 +206,7 @@ const DEFAULT_AUTH_TYPE: fn() -> AuthType = || AuthType::Local; #[derive(Clone)] pub(crate) struct ResumableSignUp { pub user_profile: UserProfile, - pub response: SignUpResponse, + pub response: AuthResponse, pub auth_type: AuthType, pub migration_user: Option, } diff --git a/frontend/scripts/tool/update_client_api_rev.sh b/frontend/scripts/tool/update_client_api_rev.sh new file mode 100755 index 0000000000..f4a8e8bd28 --- /dev/null +++ b/frontend/scripts/tool/update_client_api_rev.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Ensure a new revision ID is provided +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +NEW_REV="$1" +echo "New revision: $NEW_REV" +directories=("rust-lib" "appflowy_tauri/src-tauri") + +for dir in "${directories[@]}"; do + echo "Updating $dir" + + cd "$dir" + sed -i.bak "/^client-api[[:alnum:]-]*[[:space:]]*=/s/rev = \"[a-fA-F0-9]\{6,40\}\"/rev = \"$NEW_REV\"/g" Cargo.toml + + # Detect changed crates + client_api_crates=($(grep -E '^client-api[a-zA-Z0-9_-]* =' Cargo.toml | awk -F'=' '{print $1}' | tr -d ' ')) + + # Update only the changed crates in Cargo.lock + for crate in "${client_api_crates[@]}"; do + echo "Updating $crate" + cargo update -p $crate + done + + cd .. +done + diff --git a/frontend/scripts/tool/update_collab_rev.sh b/frontend/scripts/tool/update_collab_rev.sh index c137625afb..c91302d5f4 100755 --- a/frontend/scripts/tool/update_collab_rev.sh +++ b/frontend/scripts/tool/update_collab_rev.sh @@ -20,11 +20,16 @@ for dir in "${directories[@]}"; do collab_crates=($(grep -E '^collab[a-zA-Z0-9_-]* =' Cargo.toml | awk -F'=' '{print $1}' | tr -d ' ')) # Update only the changed crates in Cargo.lock + + crates_to_update="" for crate in "${collab_crates[@]}"; do - echo "Updating $crate" - cargo update -p $crate + crates_to_update="$crates_to_update -p $crate" done + # Update all the specified crates at once + echo "Updating crates: $crates_to_update" + cargo update $crates_to_update + cd .. done diff --git a/shared-lib/Cargo.lock b/shared-lib/Cargo.lock index f5127301fc..0550d668de 100644 --- a/shared-lib/Cargo.lock +++ b/shared-lib/Cargo.lock @@ -115,9 +115,9 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" @@ -949,22 +949,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.16", ] [[package]] @@ -1011,9 +1011,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.57" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] diff --git a/shared-lib/lib-infra/Cargo.toml b/shared-lib/lib-infra/Cargo.toml index 8b76c804e4..e064f14268 100644 --- a/shared-lib/lib-infra/Cargo.toml +++ b/shared-lib/lib-infra/Cargo.toml @@ -6,9 +6,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = { version = "0.4.27", default-features = false, features = ["clock"] } -bytes = { version = "1.4" } -pin-project = "1.0.12" +chrono = { version = "0.4.31", default-features = false, features = ["clock"] } +bytes = { version = "1.5" } +pin-project = "1.1.3" futures-core = { version = "0.3" } tokio = { version = "1.26", features = ["time", "rt"] } rand = "0.8.5"