mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: migrate user data to cloud (#3078)
* refactor: weak passed-in params in handler * refactor: rename struct * chore: update tables * chore: update schema * chore: add permission * chore: update tables * chore: support transaction mode * chore: workspace database id * chore: add user workspace * feat: return list of workspaces * chore: add user to workspace * feat: separate database row table * refactor: update schema * chore: partition table * chore: use transaction * refactor: dir * refactor: collab db ref * fix: collab db lock * chore: rename files * chore: add tables descriptions * chore: update readme * docs: update documentation * chore: rename crate * chore: update ref * chore: update tests * chore: update tests * refactor: crate deps * chore: update crate ref * chore: remove unused deps * chore: remove unused deps * chore: update collab crate refs * chore: replace client with transaction in pooler * refactor: return error type * refactor: use anyhow error in deps * feat: supabase postgrest user signin (wip) * fix: Cargo.toml source git deps, changed Error to anyhow::Error * fix: uuid serialization * chore: fix conflict * chore: extend the response * feat: add implementation place holders * feat: impl get_user_workspaces * feat: impl get_user_profile * test: create workspace * fix: postgrest: field names and alias * chore: implement folder restful api * chore: implement collab storate with restful api * feat: added placeholders for impl: update_user_profile, check_user * feat: impl: update_user_profile * feat: impl: check_user * fix: use UidResponse, add more debug info for serde serialization error * fix: get_user_profile: use Optional<UserProfileResponse> * chore: imple init sync * chore: support soft delete * feat: postgresql: add migration test * feat: postgresql migration test: added UID display and colored output * feat: postgresql migration test: workspace role * feat: postgresql migration test: create shared common utils * feat: postgresql migration test: fixed shebang * chore: add flush_collab_update pg function * chore: implement datbaase and document restful api * chore: migrate to use restful api * chore: update table schema * chore: fix tests * chore: remove unused code * chore: format code * chore: remove unused env * fix: tauri build * fix: tauri build --------- Co-authored-by: Fu Zi Xiang <speed2exe@live.com.sg>
This commit is contained in:
parent
a885170869
commit
2cd88594e8
@ -1,9 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-net/network_state.pb.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class NetworkListener {
|
||||
@ -46,12 +46,12 @@ class NetworkListener {
|
||||
return NetworkTypePB.VPN;
|
||||
case ConnectivityResult.none:
|
||||
case ConnectivityResult.other:
|
||||
return NetworkTypePB.Unknown;
|
||||
return NetworkTypePB.NetworkUnknown;
|
||||
}
|
||||
}();
|
||||
Log.info("Network type: $networkType");
|
||||
final state = NetworkStatePB.create()..ty = networkType;
|
||||
NetworkEventUpdateNetworkType(state).send().then((result) {
|
||||
UserEventUpdateNetworkState(state).send().then((result) {
|
||||
result.fold(
|
||||
(l) {},
|
||||
(e) => Log.error(e),
|
||||
|
42
frontend/appflowy_flutter/lib/env/env.dart
vendored
42
frontend/appflowy_flutter/lib/env/env.dart
vendored
@ -28,53 +28,13 @@ abstract class Env {
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseAnonKey = _Env.supabaseAnonKey;
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_KEY',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseKey = _Env.supabaseKey;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_JWT_SECRET',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseJwtSecret = _Env.supabaseJwtSecret;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDb = _Env.supabaseDb;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_USER',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDbUser = _Env.supabaseDbUser;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_PASSWORD',
|
||||
defaultValue: '',
|
||||
)
|
||||
static final String supabaseDbPassword = _Env.supabaseDbPassword;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'SUPABASE_DB_PORT',
|
||||
defaultValue: '5432',
|
||||
)
|
||||
static final String supabaseDbPort = _Env.supabaseDbPort;
|
||||
|
||||
@EnviedField(
|
||||
obfuscate: true,
|
||||
varName: 'ENABLE_SUPABASE_SYNC',
|
||||
defaultValue: true,
|
||||
)
|
||||
static final bool enableSupabaseSync = _Env.enableSupabaseSync;
|
||||
}
|
||||
|
||||
bool get isSupabaseEnable => false;
|
||||
|
@ -30,19 +30,11 @@ class InitRustSDKTask extends LaunchTask {
|
||||
}
|
||||
|
||||
AppFlowyEnv getAppFlowyEnv() {
|
||||
final postgresConfig = PostgresConfiguration(
|
||||
url: Env.supabaseDb,
|
||||
password: Env.supabaseDbPassword,
|
||||
port: int.parse(Env.supabaseDbPort),
|
||||
user_name: Env.supabaseDbUser,
|
||||
);
|
||||
|
||||
final supabaseConfig = SupabaseConfiguration(
|
||||
enable_sync: Env.enableSupabaseSync,
|
||||
enable_sync: true,
|
||||
url: Env.supabaseUrl,
|
||||
key: Env.supabaseKey,
|
||||
anon_key: Env.supabaseAnonKey,
|
||||
jwt_secret: Env.supabaseJwtSecret,
|
||||
postgres_config: postgresConfig,
|
||||
);
|
||||
|
||||
return AppFlowyEnv(
|
||||
|
@ -145,10 +145,9 @@ class SupabaseAuthService implements AuthService {
|
||||
Future<void> signOut({
|
||||
AuthTypePB authType = AuthTypePB.Supabase,
|
||||
}) async {
|
||||
if (!isSupabaseEnable) {
|
||||
return _appFlowyAuthService.signOut();
|
||||
if (isSupabaseEnable) {
|
||||
await _auth.signOut();
|
||||
}
|
||||
await _auth.signOut();
|
||||
await _appFlowyAuthService.signOut(
|
||||
authType: authType,
|
||||
);
|
||||
|
@ -125,7 +125,7 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
|
||||
}
|
||||
|
||||
SignInState stateFromCode(FlowyError error) {
|
||||
switch (ErrorCode.valueOf(error.code)!) {
|
||||
switch (ErrorCode.valueOf(error.code)) {
|
||||
case ErrorCode.EmailFormatInvalid:
|
||||
return state.copyWith(
|
||||
isSubmitting: false,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/util/color_generator/color_generator.dart';
|
||||
import 'package:appflowy/workspace/application/menu/menu_user_bloc.dart';
|
||||
@ -87,7 +88,8 @@ class MenuUser extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _renderUserName(BuildContext context) {
|
||||
final String name = userName(context.read<MenuUserBloc>().state.userProfile);
|
||||
final String name =
|
||||
userName(context.read<MenuUserBloc>().state.userProfile);
|
||||
return FlowyText.medium(
|
||||
name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -106,7 +108,17 @@ class MenuUser extends StatelessWidget {
|
||||
builder: (context) {
|
||||
return BlocProvider<DocumentAppearanceCubit>.value(
|
||||
value: BlocProvider.of<DocumentAppearanceCubit>(context),
|
||||
child: SettingsDialog(userProfile),
|
||||
child: SettingsDialog(
|
||||
userProfile,
|
||||
didLogout: () async {
|
||||
Navigator.of(context).pop();
|
||||
await FlowyRunner.run(
|
||||
FlowyApp(),
|
||||
integrationEnv(),
|
||||
);
|
||||
},
|
||||
dismissDialog: () => Navigator.of(context).pop(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -18,8 +18,15 @@ const _dialogHorizontalPadding = EdgeInsets.symmetric(horizontal: 12);
|
||||
const _contentInsetPadding = EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0);
|
||||
|
||||
class SettingsDialog extends StatelessWidget {
|
||||
final VoidCallback dismissDialog;
|
||||
final VoidCallback didLogout;
|
||||
final UserProfilePB user;
|
||||
SettingsDialog(this.user, {Key? key}) : super(key: ValueKey(user.id));
|
||||
SettingsDialog(
|
||||
this.user, {
|
||||
required this.dismissDialog,
|
||||
required this.didLogout,
|
||||
Key? key,
|
||||
}) : super(key: ValueKey(user.id));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -86,7 +93,11 @@ class SettingsDialog extends StatelessWidget {
|
||||
case SettingsPage.files:
|
||||
return const SettingsFileSystemView();
|
||||
case SettingsPage.user:
|
||||
return SettingsUserView(user);
|
||||
return SettingsUserView(
|
||||
user,
|
||||
didLogin: () => dismissDialog(),
|
||||
didLogout: didLogout,
|
||||
);
|
||||
case SettingsPage.supabaseSetting:
|
||||
return const SupabaseSettingView();
|
||||
case SettingsPage.shortcuts:
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:appflowy/startup/launch_configuration.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/sign_in_screen.dart';
|
||||
@ -9,7 +11,8 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SettingThirdPartyLogin extends StatelessWidget {
|
||||
const SettingThirdPartyLogin({super.key});
|
||||
final VoidCallback didLogin;
|
||||
const SettingThirdPartyLogin({required this.didLogin, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -27,13 +30,20 @@ class SettingThirdPartyLogin extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSuccessOrFail(
|
||||
Future<void> _handleSuccessOrFail(
|
||||
Either<UserProfilePB, FlowyError> result,
|
||||
BuildContext context,
|
||||
) {
|
||||
) async {
|
||||
result.fold(
|
||||
(user) {
|
||||
// TODO(Lucas): push to home screen
|
||||
(user) async {
|
||||
didLogin();
|
||||
await FlowyRunner.run(
|
||||
FlowyApp(),
|
||||
integrationEnv(),
|
||||
config: const LaunchConfiguration(
|
||||
autoRegistrationSupported: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
(error) => showSnapBar(context, error.msg),
|
||||
);
|
||||
|
@ -3,11 +3,11 @@ import 'dart:async';
|
||||
|
||||
import 'package:appflowy/env/env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/startup/entry_point.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/util/debounce.dart';
|
||||
import 'package:appflowy/workspace/application/user/settings_user_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
@ -22,8 +22,15 @@ const defaultUserAvatar = '1F600';
|
||||
const _iconSize = Size(60, 60);
|
||||
|
||||
class SettingsUserView extends StatelessWidget {
|
||||
final VoidCallback didLogin;
|
||||
final VoidCallback didLogout;
|
||||
final UserProfilePB user;
|
||||
SettingsUserView(this.user, {Key? key}) : super(key: ValueKey(user.id));
|
||||
SettingsUserView(
|
||||
this.user, {
|
||||
required this.didLogin,
|
||||
required this.didLogout,
|
||||
Key? key,
|
||||
}) : super(key: ValueKey(user.id));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -58,7 +65,9 @@ class SettingsUserView extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (state.userProfile.authType == AuthTypePB.Local) {
|
||||
return const SettingThirdPartyLogin();
|
||||
return SettingThirdPartyLogin(
|
||||
didLogin: didLogin,
|
||||
);
|
||||
} else {
|
||||
return _renderLogoutButton(context);
|
||||
}
|
||||
@ -88,15 +97,17 @@ class SettingsUserView extends StatelessWidget {
|
||||
Widget _renderLogoutButton(BuildContext context) {
|
||||
return FlowyButton(
|
||||
useIntrinsicWidth: true,
|
||||
text: const FlowyText(
|
||||
'Logout',
|
||||
text: FlowyText(
|
||||
LocaleKeys.settings_menu_logout.tr(),
|
||||
),
|
||||
onTap: () async {
|
||||
await getIt<AuthService>().signOut();
|
||||
await FlowyRunner.run(
|
||||
FlowyApp(),
|
||||
integrationEnv(),
|
||||
);
|
||||
NavigatorAlertDialog(
|
||||
title: LocaleKeys.settings_menu_logoutPrompt.tr(),
|
||||
confirm: () async {
|
||||
await getIt<AuthService>().signOut();
|
||||
didLogout();
|
||||
},
|
||||
).show(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import 'package:appflowy_backend/log.dart';
|
||||
// ignore: unnecessary_import
|
||||
import 'package:appflowy_backend/protobuf/dart-ffi/ffi_response.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-net/network_state.pb.dart';
|
||||
import 'package:isolates/isolates.dart';
|
||||
import 'package:isolates/ports.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
@ -23,11 +22,9 @@ import 'package:protobuf/protobuf.dart';
|
||||
import 'dart:convert' show utf8;
|
||||
import '../protobuf/flowy-config/entities.pb.dart';
|
||||
import '../protobuf/flowy-config/event_map.pb.dart';
|
||||
import '../protobuf/flowy-net/event_map.pb.dart';
|
||||
import 'error.dart';
|
||||
|
||||
part 'dart_event/flowy-folder2/dart_event.dart';
|
||||
part 'dart_event/flowy-net/dart_event.dart';
|
||||
part 'dart_event/flowy-user/dart_event.dart';
|
||||
part 'dart_event/flowy-database2/dart_event.dart';
|
||||
part 'dart_event/flowy-document2/dart_event.dart';
|
||||
|
@ -26,16 +26,14 @@ class SupabaseConfiguration {
|
||||
/// Indicates whether the sync feature is enabled.
|
||||
final bool enable_sync;
|
||||
final String url;
|
||||
final String key;
|
||||
final String anon_key;
|
||||
final String jwt_secret;
|
||||
final PostgresConfiguration postgres_config;
|
||||
|
||||
SupabaseConfiguration({
|
||||
this.enable_sync = true,
|
||||
required this.url,
|
||||
required this.key,
|
||||
required this.anon_key,
|
||||
required this.jwt_secret,
|
||||
required this.postgres_config,
|
||||
});
|
||||
|
||||
factory SupabaseConfiguration.fromJson(Map<String, dynamic> json) =>
|
||||
@ -43,23 +41,3 @@ class SupabaseConfiguration {
|
||||
|
||||
Map<String, dynamic> toJson() => _$SupabaseConfigurationToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class PostgresConfiguration {
|
||||
final String url;
|
||||
final String user_name;
|
||||
final String password;
|
||||
final int port;
|
||||
|
||||
PostgresConfiguration({
|
||||
required this.url,
|
||||
required this.user_name,
|
||||
required this.password,
|
||||
required this.port,
|
||||
});
|
||||
|
||||
factory PostgresConfiguration.fromJson(Map<String, dynamic> json) =>
|
||||
_$PostgresConfigurationFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$PostgresConfigurationToJson(this);
|
||||
}
|
||||
|
@ -21,10 +21,8 @@ SupabaseConfiguration _$SupabaseConfigurationFromJson(
|
||||
SupabaseConfiguration(
|
||||
enable_sync: json['enable_sync'] as bool? ?? true,
|
||||
url: json['url'] as String,
|
||||
key: json['key'] as String,
|
||||
anon_key: json['anon_key'] as String,
|
||||
jwt_secret: json['jwt_secret'] as String,
|
||||
postgres_config: PostgresConfiguration.fromJson(
|
||||
json['postgres_config'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SupabaseConfigurationToJson(
|
||||
@ -32,25 +30,6 @@ Map<String, dynamic> _$SupabaseConfigurationToJson(
|
||||
<String, dynamic>{
|
||||
'enable_sync': instance.enable_sync,
|
||||
'url': instance.url,
|
||||
'key': instance.key,
|
||||
'anon_key': instance.anon_key,
|
||||
'jwt_secret': instance.jwt_secret,
|
||||
'postgres_config': instance.postgres_config,
|
||||
};
|
||||
|
||||
PostgresConfiguration _$PostgresConfigurationFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
PostgresConfiguration(
|
||||
url: json['url'] as String,
|
||||
user_name: json['user_name'] as String,
|
||||
password: json['password'] as String,
|
||||
port: json['port'] as int,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PostgresConfigurationToJson(
|
||||
PostgresConfiguration instance) =>
|
||||
<String, dynamic>{
|
||||
'url': instance.url,
|
||||
'user_name': instance.user_name,
|
||||
'password': instance.password,
|
||||
'port': instance.port,
|
||||
};
|
||||
|
315
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
315
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -105,7 +105,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -642,15 +642,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
@ -1030,7 +1021,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1048,7 +1039,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -1059,14 +1050,14 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-retry",
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite 0.18.0",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1093,7 +1084,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1105,7 +1096,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1124,7 +1115,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1144,7 +1135,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1164,30 +1155,26 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"aws-config",
|
||||
"aws-credential-types",
|
||||
"aws-sdk-dynamodb",
|
||||
"base64 0.21.2",
|
||||
"collab",
|
||||
"collab-client-ws",
|
||||
"collab-persistence",
|
||||
"collab-sync",
|
||||
"futures-util",
|
||||
"parking_lot 0.12.1",
|
||||
"postgrest",
|
||||
"rand 0.8.5",
|
||||
"refinery",
|
||||
"rusoto_credential",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar 2.2.1",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tokio-retry",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
@ -1198,7 +1185,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f420738#f4207385738961a9aa4ea871731de204dfee8455"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12811d#12811d26a96330f6c1acaa8815f1d8d61ca3aa61"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
@ -1483,40 +1470,6 @@ dependencies = [
|
||||
"parking_lot_core 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deadpool-runtime",
|
||||
"num_cpus",
|
||||
"retain_mut",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool-postgres"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a24a9d49deefe610b8b60c767a7412e9a931d79a89415cd2d2d71630ca8d7"
|
||||
dependencies = [
|
||||
"deadpool",
|
||||
"log",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool-runtime"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1"
|
||||
dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
@ -1579,22 +1532,13 @@ dependencies = [
|
||||
"migrations_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer 0.10.4",
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
@ -1853,12 +1797,10 @@ dependencies = [
|
||||
name = "flowy-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"appflowy-integrate",
|
||||
"bytes",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-server",
|
||||
"flowy-sqlite",
|
||||
"lib-dispatch",
|
||||
"protobuf",
|
||||
@ -1873,9 +1815,12 @@ dependencies = [
|
||||
"bytes",
|
||||
"diesel",
|
||||
"flowy-config",
|
||||
"flowy-database-deps",
|
||||
"flowy-database2",
|
||||
"flowy-document-deps",
|
||||
"flowy-document2",
|
||||
"flowy-error",
|
||||
"flowy-folder-deps",
|
||||
"flowy-folder2",
|
||||
"flowy-net",
|
||||
"flowy-server",
|
||||
@ -1883,11 +1828,11 @@ dependencies = [
|
||||
"flowy-sqlite",
|
||||
"flowy-task",
|
||||
"flowy-user",
|
||||
"flowy-user-deps",
|
||||
"futures-core",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
"lib-log",
|
||||
"lib-ws",
|
||||
"parking_lot 0.12.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1897,6 +1842,16 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-database-deps"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab-plugins",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-database2"
|
||||
version = "0.1.0"
|
||||
@ -1914,6 +1869,7 @@ dependencies = [
|
||||
"dashmap",
|
||||
"fancy-regex 0.10.0",
|
||||
"flowy-codegen",
|
||||
"flowy-database-deps",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-notification",
|
||||
@ -1954,6 +1910,16 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-document-deps"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab-document",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-document2"
|
||||
version = "0.1.0"
|
||||
@ -1965,6 +1931,7 @@ dependencies = [
|
||||
"collab-document",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-document-deps",
|
||||
"flowy-error",
|
||||
"flowy-notification",
|
||||
"futures",
|
||||
@ -1976,7 +1943,6 @@ dependencies = [
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@ -1995,7 +1961,6 @@ dependencies = [
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-sqlite",
|
||||
"http-error-code",
|
||||
"lib-dispatch",
|
||||
"protobuf",
|
||||
"r2d2",
|
||||
@ -2004,6 +1969,18 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"tokio-postgres",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-folder-deps"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab-folder",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2018,6 +1995,7 @@ dependencies = [
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-folder-deps",
|
||||
"flowy-notification",
|
||||
"lazy_static",
|
||||
"lib-dispatch",
|
||||
@ -2025,7 +2003,6 @@ dependencies = [
|
||||
"nanoid",
|
||||
"parking_lot 0.12.1",
|
||||
"protobuf",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@ -2038,15 +2015,10 @@ dependencies = [
|
||||
name = "flowy-net"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"lib-dispatch",
|
||||
"protobuf",
|
||||
"strum_macros",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -2069,36 +2041,32 @@ name = "flowy-server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"appflowy-integrate",
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"collab-folder",
|
||||
"collab-plugins",
|
||||
"config",
|
||||
"deadpool-postgres",
|
||||
"flowy-database2",
|
||||
"flowy-document2",
|
||||
"flowy-database-deps",
|
||||
"flowy-document-deps",
|
||||
"flowy-error",
|
||||
"flowy-folder2",
|
||||
"flowy-folder-deps",
|
||||
"flowy-server-config",
|
||||
"flowy-user",
|
||||
"flowy-user-deps",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"hyper",
|
||||
"lazy_static",
|
||||
"lib-infra",
|
||||
"nanoid",
|
||||
"parking_lot 0.12.1",
|
||||
"postgrest",
|
||||
"refinery",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde-aux",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tokio-retry",
|
||||
"tracing",
|
||||
"uuid",
|
||||
@ -2147,7 +2115,9 @@ name = "flowy-user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"appflowy-integrate",
|
||||
"base64 0.21.2",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"diesel",
|
||||
@ -2159,6 +2129,7 @@ dependencies = [
|
||||
"flowy-notification",
|
||||
"flowy-server-config",
|
||||
"flowy-sqlite",
|
||||
"flowy-user-deps",
|
||||
"lazy_static",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
@ -2169,7 +2140,6 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@ -2178,6 +2148,20 @@ dependencies = [
|
||||
"validator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-user-deps"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"flowy-error",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -2737,7 +2721,7 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2776,16 +2760,6 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-error-code"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Server?branch=refactor/appflowy_server#1ccd296de8530760d92652dbd9f38f27178059b6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range"
|
||||
version = "0.1.5"
|
||||
@ -3200,31 +3174,6 @@ dependencies = [
|
||||
"tracing-subscriber 0.2.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib-ws"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"lib-infra",
|
||||
"log",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.15.0",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib0"
|
||||
version = "0.16.8"
|
||||
@ -3415,7 +3364,7 @@ version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3704,12 +3653,6 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "3.2.0"
|
||||
@ -4167,10 +4110,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"fallible-iterator",
|
||||
"postgres-protocol",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4548,51 +4489,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "refinery"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb0436d0dd7bd8d4fce1e828751fa79742b08e35f27cfea7546f8a322b5ef24"
|
||||
dependencies = [
|
||||
"refinery-core",
|
||||
"refinery-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "refinery-core"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19206547cd047e8f4dfa6b20c30d3ecaf24be05841b6aa0aa926a47a3d0662bb"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"regex",
|
||||
"serde",
|
||||
"siphasher",
|
||||
"thiserror",
|
||||
"time 0.3.22",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"toml 0.7.5",
|
||||
"url",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "refinery-macros"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d94d4b9241859ba19eaa5c04c86e782eb3aa0aae2c5868e0cfa90c856e58a174"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"refinery-core",
|
||||
"regex",
|
||||
"syn 2.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
@ -4676,12 +4572,6 @@ dependencies = [
|
||||
"winreg 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "retain_mut"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
@ -5140,19 +5030,6 @@ dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
@ -5161,7 +5038,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.7",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5178,7 +5055,7 @@ checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.7",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6003,19 +5880,6 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"pin-project",
|
||||
"tokio",
|
||||
"tungstenite 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.18.0"
|
||||
@ -6025,7 +5889,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite 0.18.0",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6251,25 +6115,6 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"sha-1",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.18.0"
|
||||
|
@ -34,18 +34,20 @@ default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
|
||||
#collab = { path = "../../../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-document = { path = "../../../../AppFlowy-Collab/collab-document" }
|
||||
#collab-database = { path = "../../../../AppFlowy-Collab/collab-database" }
|
||||
#appflowy-integrate = { path = "../../../../AppFlowy-Collab/appflowy-integrate" }
|
||||
#collab = { path = "../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-document = { path = "../../AppFlowy-Collab/collab-document" }
|
||||
#collab-database = { path = "../../AppFlowy-Collab/collab-database" }
|
||||
#appflowy-integrate = { path = "../../AppFlowy-Collab/appflowy-integrate" }
|
||||
#collab-plugins = { path = "../../AppFlowy-Collab/collab-plugins" }
|
||||
|
||||
|
||||
|
||||
|
@ -2,7 +2,6 @@ export * from "./models/flowy-user";
|
||||
export * from "./models/flowy-database2";
|
||||
export * from "./models/flowy-folder2";
|
||||
export * from "./models/flowy-document2";
|
||||
export * from "./models/flowy-net";
|
||||
export * from "./models/flowy-error";
|
||||
export * from "./models/flowy-config";
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "flowy-server-config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -1,14 +0,0 @@
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
@ -210,6 +210,8 @@
|
||||
"user": "User",
|
||||
"files": "Files",
|
||||
"open": "Open Settings",
|
||||
"logout": "Logout",
|
||||
"logoutPrompt": "Are you sure to logout?",
|
||||
"supabaseSetting": "Supabase Setting"
|
||||
},
|
||||
"appearance": {
|
||||
|
553
frontend/rust-lib/Cargo.lock
generated
553
frontend/rust-lib/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -6,13 +6,17 @@ members = [
|
||||
"flowy-core",
|
||||
"dart-ffi",
|
||||
"flowy-user",
|
||||
"flowy-user-deps",
|
||||
"flowy-test",
|
||||
"flowy-sqlite",
|
||||
"flowy-folder2",
|
||||
"flowy-folder-deps",
|
||||
"flowy-notification",
|
||||
"flowy-document2",
|
||||
"flowy-document-deps",
|
||||
"flowy-error",
|
||||
"flowy-database2",
|
||||
"flowy-database-deps",
|
||||
"flowy-task",
|
||||
"flowy-server",
|
||||
"flowy-server-config",
|
||||
@ -34,15 +38,17 @@ opt-level = 3
|
||||
incremental = false
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f420738" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5783a5" }
|
||||
|
||||
#collab = { path = "../../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../../AppFlowy-Collab/collab-folder" }
|
||||
#collab-database= { path = "../../../AppFlowy-Collab/collab-database" }
|
||||
#collab-document = { path = "../../../AppFlowy-Collab/collab-document" }
|
||||
#appflowy-integrate = { path = "../../../AppFlowy-Collab/appflowy-integrate" }
|
||||
#collab = { path = "../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }
|
||||
#collab-database= { path = "../AppFlowy-Collab/collab-database" }
|
||||
#collab-document = { path = "../AppFlowy-Collab/collab-document" }
|
||||
#collab-plugins = { path = "../AppFlowy-Collab/collab-plugins" }
|
||||
#appflowy-integrate = { path = "../AppFlowy-Collab/appflowy-integrate" }
|
||||
|
||||
|
@ -13,8 +13,6 @@ protobuf = {version = "2.28.0"}
|
||||
bytes = { version = "1.4" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
strum_macros = "0.21"
|
||||
appflowy-integrate = {version = "0.1.0" }
|
||||
flowy-server = { path = "../flowy-server" }
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen = { path = "../../../shared-lib/flowy-codegen"}
|
||||
|
@ -1,7 +1,4 @@
|
||||
use appflowy_integrate::config::AWSDynamoDBConfig;
|
||||
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::FlowyError;
|
||||
|
||||
#[derive(Default, ProtoBuf)]
|
||||
pub struct KeyValuePB {
|
||||
@ -17,34 +14,3 @@ pub struct KeyPB {
|
||||
#[pb(index = 1)]
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
#[derive(Default, ProtoBuf)]
|
||||
pub struct CollabPluginConfigPB {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub aws_config: Option<AWSDynamoDBConfigPB>,
|
||||
}
|
||||
|
||||
#[derive(Default, ProtoBuf)]
|
||||
pub struct AWSDynamoDBConfigPB {
|
||||
#[pb(index = 1)]
|
||||
pub access_key_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub secret_access_key: String,
|
||||
// Region list: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html
|
||||
#[pb(index = 3)]
|
||||
pub region: String,
|
||||
}
|
||||
|
||||
impl TryFrom<AWSDynamoDBConfigPB> for AWSDynamoDBConfig {
|
||||
type Error = FlowyError;
|
||||
|
||||
fn try_from(config: AWSDynamoDBConfigPB) -> Result<Self, Self::Error> {
|
||||
Ok(AWSDynamoDBConfig {
|
||||
access_key_id: config.access_key_id,
|
||||
secret_access_key: config.secret_access_key,
|
||||
region: config.region,
|
||||
enable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
use appflowy_integrate::config::AWSDynamoDBConfig;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sqlite::kv::KV;
|
||||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, DataResult};
|
||||
|
||||
use crate::entities::{CollabPluginConfigPB, KeyPB, KeyValuePB};
|
||||
use crate::entities::{KeyPB, KeyValuePB};
|
||||
|
||||
pub(crate) async fn set_key_value_handler(data: AFPluginData<KeyValuePB>) -> FlowyResult<()> {
|
||||
let data = data.into_inner();
|
||||
@ -33,15 +31,3 @@ pub(crate) async fn remove_key_value_handler(data: AFPluginData<KeyPB>) -> Flowy
|
||||
KV::remove(&data.key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn set_collab_plugin_config_handler(
|
||||
data: AFPluginData<CollabPluginConfigPB>,
|
||||
) -> FlowyResult<()> {
|
||||
let config = data.into_inner();
|
||||
if let Some(aws_config_pb) = config.aws_config {
|
||||
if let Ok(aws_config) = AWSDynamoDBConfig::try_from(aws_config_pb) {
|
||||
aws_config.write_env();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -11,10 +11,6 @@ pub fn init() -> AFPlugin {
|
||||
.event(ConfigEvent::SetKeyValue, set_key_value_handler)
|
||||
.event(ConfigEvent::GetKeyValue, get_key_value_handler)
|
||||
.event(ConfigEvent::RemoveKeyValue, remove_key_value_handler)
|
||||
.event(
|
||||
ConfigEvent::SetCollabPluginConfig,
|
||||
set_collab_plugin_config_handler,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, ProtoBuf_Enum, Flowy_Event)]
|
||||
@ -28,7 +24,4 @@ pub enum ConfigEvent {
|
||||
|
||||
#[event(input = "KeyPB")]
|
||||
RemoveKeyValue = 2,
|
||||
|
||||
#[event(input = "CollabPluginConfigPB")]
|
||||
SetCollabPluginConfig = 4,
|
||||
}
|
||||
|
@ -9,17 +9,21 @@ edition = "2018"
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-log = { path = "../lib-log" }
|
||||
flowy-user = { path = "../flowy-user" }
|
||||
flowy-user-deps = { path = "../flowy-user-deps" }
|
||||
flowy-net = { path = "../flowy-net" }
|
||||
flowy-folder2 = { path = "../flowy-folder2" }
|
||||
flowy-folder-deps = { path = "../flowy-folder-deps" }
|
||||
flowy-database2 = { path = "../flowy-database2" }
|
||||
flowy-database-deps = { path = "../flowy-database-deps" }
|
||||
flowy-sqlite = { path = "../flowy-sqlite" }
|
||||
flowy-document2 = { path = "../flowy-document2" }
|
||||
flowy-document-deps = { path = "../flowy-document-deps" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
flowy-task = { path = "../flowy-task" }
|
||||
flowy-server = { path = "../flowy-server" }
|
||||
flowy-server-config = { path = "../flowy-server-config" }
|
||||
flowy-config = { path = "../flowy-config" }
|
||||
appflowy-integrate = { version = "0.1.0" }
|
||||
appflowy-integrate = { version = "0.1.0", features = ["postgres_storage_plugin", "snapshot_plugin"] }
|
||||
diesel = { version = "1.4.8", features = ["sqlite"] }
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
|
||||
@ -30,7 +34,6 @@ tokio = { version = "1.26", features = ["full"] }
|
||||
console-subscriber = { version = "0.1.8", optional = true }
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
lib-ws = { path = "../../../shared-lib/lib-ws" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
@ -4,23 +4,23 @@ use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use flowy_database2::deps::{DatabaseCloudService, DatabaseUser2};
|
||||
use flowy_database2::DatabaseManager2;
|
||||
use flowy_database2::{DatabaseManager, DatabaseUser};
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_task::TaskDispatcher;
|
||||
use flowy_user::services::UserSession;
|
||||
|
||||
pub struct Database2DepsResolver();
|
||||
pub struct DatabaseDepsResolver();
|
||||
|
||||
impl Database2DepsResolver {
|
||||
impl DatabaseDepsResolver {
|
||||
pub async fn resolve(
|
||||
user_session: Weak<UserSession>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
cloud_service: Arc<dyn DatabaseCloudService>,
|
||||
) -> Arc<DatabaseManager2> {
|
||||
) -> Arc<DatabaseManager> {
|
||||
let user = Arc::new(DatabaseUserImpl(user_session));
|
||||
Arc::new(DatabaseManager2::new(
|
||||
Arc::new(DatabaseManager::new(
|
||||
user,
|
||||
task_scheduler,
|
||||
collab_builder,
|
||||
@ -30,7 +30,7 @@ impl Database2DepsResolver {
|
||||
}
|
||||
|
||||
struct DatabaseUserImpl(Weak<UserSession>);
|
||||
impl DatabaseUser2 for DatabaseUserImpl {
|
||||
impl DatabaseUser for DatabaseUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self
|
||||
.0
|
||||
@ -47,7 +47,7 @@ impl DatabaseUser2 for DatabaseUserImpl {
|
||||
.token()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError> {
|
||||
self
|
||||
.0
|
||||
.upgrade()
|
||||
|
@ -3,17 +3,17 @@ use std::sync::{Arc, Weak};
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
|
||||
use flowy_database2::DatabaseManager2;
|
||||
use flowy_document2::deps::{DocumentCloudService, DocumentUser};
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::manager::{DocumentManager, DocumentUser};
|
||||
use flowy_document_deps::cloud::DocumentCloudService;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_user::services::UserSession;
|
||||
|
||||
pub struct Document2DepsResolver();
|
||||
impl Document2DepsResolver {
|
||||
pub struct DocumentDepsResolver();
|
||||
impl DocumentDepsResolver {
|
||||
pub fn resolve(
|
||||
user_session: Weak<UserSession>,
|
||||
_database_manager: &Arc<DatabaseManager2>,
|
||||
_database_manager: &Arc<DatabaseManager>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
cloud_service: Arc<dyn DocumentCloudService>,
|
||||
) -> Arc<DocumentManager> {
|
||||
@ -44,7 +44,7 @@ impl DocumentUser for DocumentUserImpl {
|
||||
.token()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError> {
|
||||
self
|
||||
.0
|
||||
.upgrade()
|
@ -10,29 +10,29 @@ use tokio::sync::RwLock;
|
||||
use flowy_database2::entities::DatabaseLayoutPB;
|
||||
use flowy_database2::services::share::csv::CSVFormat;
|
||||
use flowy_database2::template::{make_default_board, make_default_calendar, make_default_grid};
|
||||
use flowy_database2::DatabaseManager2;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::entities::DocumentDataPB;
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_document2::parser::json::parser::JsonToDocumentParser;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder2::deps::{FolderCloudService, FolderUser};
|
||||
use flowy_folder2::entities::ViewLayoutPB;
|
||||
use flowy_folder2::manager::FolderManager;
|
||||
use flowy_folder2::manager::{FolderManager, FolderUser};
|
||||
use flowy_folder2::share::ImportType;
|
||||
use flowy_folder2::view_operation::{
|
||||
FolderOperationHandler, FolderOperationHandlers, View, WorkspaceViewBuilder,
|
||||
};
|
||||
use flowy_folder2::ViewLayout;
|
||||
use flowy_folder_deps::cloud::FolderCloudService;
|
||||
use flowy_user::services::UserSession;
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub struct Folder2DepsResolver();
|
||||
impl Folder2DepsResolver {
|
||||
pub struct FolderDepsResolver();
|
||||
impl FolderDepsResolver {
|
||||
pub async fn resolve(
|
||||
user_session: Weak<UserSession>,
|
||||
document_manager: &Arc<DocumentManager>,
|
||||
database_manager: &Arc<DatabaseManager2>,
|
||||
database_manager: &Arc<DatabaseManager>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
folder_cloud: Arc<dyn FolderCloudService>,
|
||||
) -> Arc<FolderManager> {
|
||||
@ -49,7 +49,7 @@ impl Folder2DepsResolver {
|
||||
|
||||
fn folder_operation_handlers(
|
||||
document_manager: Arc<DocumentManager>,
|
||||
database_manager: Arc<DatabaseManager2>,
|
||||
database_manager: Arc<DatabaseManager>,
|
||||
) -> FolderOperationHandlers {
|
||||
let mut map: HashMap<ViewLayout, Arc<dyn FolderOperationHandler + Send + Sync>> = HashMap::new();
|
||||
|
||||
@ -81,7 +81,7 @@ impl FolderUser for FolderUserImpl {
|
||||
.token()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError> {
|
||||
self
|
||||
.0
|
||||
.upgrade()
|
||||
@ -218,7 +218,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
||||
}
|
||||
}
|
||||
|
||||
struct DatabaseFolderOperation(Arc<DatabaseManager2>);
|
||||
struct DatabaseFolderOperation(Arc<DatabaseManager>);
|
||||
impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
fn close_view(&self, view_id: &str) -> FutureResult<(), FlowyError> {
|
||||
let database_manager = self.0.clone();
|
@ -1,11 +1,11 @@
|
||||
pub use collab_deps::*;
|
||||
pub use database_deps::*;
|
||||
pub use document2_deps::*;
|
||||
pub use folder2_deps::*;
|
||||
pub use document_deps::*;
|
||||
pub use folder_deps::*;
|
||||
|
||||
mod collab_deps;
|
||||
mod document2_deps;
|
||||
mod folder2_deps;
|
||||
mod document_deps;
|
||||
mod folder_deps;
|
||||
mod util;
|
||||
|
||||
mod database_deps;
|
||||
|
@ -2,25 +2,28 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::collab_builder::{CollabStorageProvider, CollabStorageType};
|
||||
use appflowy_integrate::RemoteCollabStorage;
|
||||
use appflowy_integrate::{CollabType, RemoteCollabStorage, YrsDocAction};
|
||||
use parking_lot::RwLock;
|
||||
use serde_repr::*;
|
||||
|
||||
use flowy_database2::deps::{
|
||||
CollabObjectUpdate, CollabObjectUpdateByOid, DatabaseCloudService, DatabaseSnapshot,
|
||||
};
|
||||
use flowy_document2::deps::{DocumentCloudService, DocumentData, DocumentSnapshot};
|
||||
use flowy_database_deps::cloud::*;
|
||||
use flowy_document2::deps::DocumentData;
|
||||
use flowy_document_deps::cloud::{DocumentCloudService, DocumentSnapshot};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder2::deps::{FolderCloudService, FolderData, FolderSnapshot, Workspace};
|
||||
use flowy_server::local_server::LocalServer;
|
||||
use flowy_folder_deps::cloud::*;
|
||||
use flowy_server::local_server::{LocalServer, LocalServerDB};
|
||||
use flowy_server::self_host::configuration::self_host_server_configuration;
|
||||
use flowy_server::self_host::SelfHostServer;
|
||||
use flowy_server::supabase::SupabaseServer;
|
||||
use flowy_server::AppFlowyServer;
|
||||
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||
use flowy_sqlite::kv::KV;
|
||||
use flowy_user::event_map::{UserAuthService, UserCloudServiceProvider};
|
||||
use flowy_user::services::AuthType;
|
||||
use flowy_user::event_map::UserCloudServiceProvider;
|
||||
use flowy_user::services::database::{
|
||||
get_user_profile, get_user_workspace, open_collab_db, open_user_db,
|
||||
};
|
||||
use flowy_user_deps::cloud::UserService;
|
||||
use flowy_user_deps::entities::*;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::AppFlowyCoreConfig;
|
||||
@ -45,7 +48,7 @@ pub enum ServerProviderType {
|
||||
/// The [AppFlowyServerProvider] provides list of [AppFlowyServer] base on the [AuthType]. Using
|
||||
/// the auth type, the [AppFlowyServerProvider] will create a new [AppFlowyServer] if it doesn't
|
||||
/// exist.
|
||||
/// Each server implements the [AppFlowyServer] trait, which provides the [UserAuthService], etc.
|
||||
/// Each server implements the [AppFlowyServer] trait, which provides the [UserService], etc.
|
||||
pub struct AppFlowyServerProvider {
|
||||
config: AppFlowyCoreConfig,
|
||||
provider_type: RwLock<ServerProviderType>,
|
||||
@ -78,7 +81,11 @@ impl AppFlowyServerProvider {
|
||||
|
||||
let server = match provider_type {
|
||||
ServerProviderType::Local => {
|
||||
let server = Arc::new(LocalServer::new(&self.config.storage_path));
|
||||
let local_db = Arc::new(LocalServerDBImpl {
|
||||
storage_path: self.config.storage_path.clone(),
|
||||
});
|
||||
let server = Arc::new(LocalServer::new(local_db));
|
||||
|
||||
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
|
||||
},
|
||||
ServerProviderType::SelfHosted => {
|
||||
@ -142,9 +149,9 @@ impl UserCloudServiceProvider for AppFlowyServerProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [UserAuthService] base on the current [ServerProviderType].
|
||||
/// Returns the [UserService] base on the current [ServerProviderType].
|
||||
/// Creates a new [AppFlowyServer] if it doesn't exist.
|
||||
fn get_auth_service(&self) -> Result<Arc<dyn UserAuthService>, FlowyError> {
|
||||
fn get_user_service(&self) -> Result<Arc<dyn UserService>, FlowyError> {
|
||||
Ok(
|
||||
self
|
||||
.get_provider(&self.provider_type.read())?
|
||||
@ -154,13 +161,13 @@ impl UserCloudServiceProvider for AppFlowyServerProvider {
|
||||
}
|
||||
|
||||
impl FolderCloudService for AppFlowyServerProvider {
|
||||
fn create_workspace(&self, uid: i64, name: &str) -> FutureResult<Workspace, FlowyError> {
|
||||
fn create_workspace(&self, uid: i64, name: &str) -> FutureResult<Workspace, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let name = name.to_string();
|
||||
FutureResult::new(async move { server?.folder_service().create_workspace(uid, &name).await })
|
||||
}
|
||||
|
||||
fn get_folder_data(&self, workspace_id: &str) -> FutureResult<Option<FolderData>, FlowyError> {
|
||||
fn get_folder_data(&self, workspace_id: &str) -> FutureResult<Option<FolderData>, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let workspace_id = workspace_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
@ -174,7 +181,7 @@ impl FolderCloudService for AppFlowyServerProvider {
|
||||
fn get_folder_latest_snapshot(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<FolderSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<FolderSnapshot>, Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
FutureResult::new(async move {
|
||||
@ -185,11 +192,7 @@ impl FolderCloudService for AppFlowyServerProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_folder_updates(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
uid: i64,
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
fn get_folder_updates(&self, workspace_id: &str, uid: i64) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
FutureResult::new(async move {
|
||||
@ -209,13 +212,17 @@ impl FolderCloudService for AppFlowyServerProvider {
|
||||
}
|
||||
|
||||
impl DatabaseCloudService for AppFlowyServerProvider {
|
||||
fn get_collab_update(&self, object_id: &str) -> FutureResult<CollabObjectUpdate, FlowyError> {
|
||||
fn get_collab_update(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdate, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let database_id = object_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
server?
|
||||
.database_service()
|
||||
.get_collab_update(&database_id)
|
||||
.get_collab_update(&database_id, object_ty)
|
||||
.await
|
||||
})
|
||||
}
|
||||
@ -223,12 +230,13 @@ impl DatabaseCloudService for AppFlowyServerProvider {
|
||||
fn batch_get_collab_updates(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, FlowyError> {
|
||||
object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
FutureResult::new(async move {
|
||||
server?
|
||||
.database_service()
|
||||
.batch_get_collab_updates(object_ids)
|
||||
.batch_get_collab_updates(object_ids, object_ty)
|
||||
.await
|
||||
})
|
||||
}
|
||||
@ -236,7 +244,7 @@ impl DatabaseCloudService for AppFlowyServerProvider {
|
||||
fn get_collab_latest_snapshot(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let database_id = object_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
@ -249,7 +257,7 @@ impl DatabaseCloudService for AppFlowyServerProvider {
|
||||
}
|
||||
|
||||
impl DocumentCloudService for AppFlowyServerProvider {
|
||||
fn get_document_updates(&self, document_id: &str) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
fn get_document_updates(&self, document_id: &str) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let document_id = document_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
@ -263,7 +271,7 @@ impl DocumentCloudService for AppFlowyServerProvider {
|
||||
fn get_document_latest_snapshot(
|
||||
&self,
|
||||
document_id: &str,
|
||||
) -> FutureResult<Option<DocumentSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<DocumentSnapshot>, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let document_id = document_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
@ -274,7 +282,7 @@ impl DocumentCloudService for AppFlowyServerProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_document_data(&self, document_id: &str) -> FutureResult<Option<DocumentData>, FlowyError> {
|
||||
fn get_document_data(&self, document_id: &str) -> FutureResult<Option<DocumentData>, Error> {
|
||||
let server = self.get_provider(&self.provider_type.read());
|
||||
let document_id = document_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
@ -334,3 +342,31 @@ fn current_server_provider() -> ServerProviderType {
|
||||
Some(provider_type) => provider_type,
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalServerDBImpl {
|
||||
storage_path: String,
|
||||
}
|
||||
|
||||
impl LocalServerDB for LocalServerDBImpl {
|
||||
fn get_user_profile(&self, uid: i64) -> Result<Option<UserProfile>, FlowyError> {
|
||||
let sqlite_db = open_user_db(&self.storage_path, uid)?;
|
||||
let user_profile = get_user_profile(&sqlite_db, uid).ok();
|
||||
Ok(user_profile)
|
||||
}
|
||||
|
||||
fn get_user_workspace(&self, uid: i64) -> Result<Option<UserWorkspace>, FlowyError> {
|
||||
let sqlite_db = open_user_db(&self.storage_path, uid)?;
|
||||
let user_workspace = get_user_workspace(&sqlite_db, uid)?;
|
||||
Ok(user_workspace)
|
||||
}
|
||||
|
||||
fn get_collab_updates(&self, uid: i64, object_id: &str) -> Result<Vec<Vec<u8>>, FlowyError> {
|
||||
let collab_db = open_collab_db(&self.storage_path, uid)?;
|
||||
let read_txn = collab_db.read_txn();
|
||||
let updates = read_txn
|
||||
.get_all_updates(uid, object_id)
|
||||
.map_err(|e| FlowyError::internal().context(format!("Failed to open collab db: {:?}", e)))?;
|
||||
|
||||
Ok(updates)
|
||||
}
|
||||
}
|
||||
|
@ -11,17 +11,16 @@ use std::{
|
||||
|
||||
use appflowy_integrate::collab_builder::{AppFlowyCollabBuilder, CollabStorageType};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::debug;
|
||||
|
||||
use flowy_database2::DatabaseManager2;
|
||||
use flowy_document2::manager::DocumentManager as DocumentManager2;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder2::manager::{FolderInitializeData, FolderManager};
|
||||
use flowy_sqlite::kv::KV;
|
||||
use flowy_task::{TaskDispatcher, TaskRunner};
|
||||
use flowy_user::entities::UserProfile;
|
||||
use flowy_user::event_map::{SignUpContext, UserCloudServiceProvider, UserStatusCallback};
|
||||
use flowy_user::services::{get_supabase_config, AuthType, UserSession, UserSessionConfig};
|
||||
use flowy_user::services::{get_supabase_config, UserSession, UserSessionConfig};
|
||||
use flowy_user_deps::entities::{AuthType, UserProfile, UserWorkspace};
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_dispatch::runtime::tokio_default_runtime;
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
@ -113,9 +112,9 @@ pub struct AppFlowyCore {
|
||||
#[allow(dead_code)]
|
||||
pub config: AppFlowyCoreConfig,
|
||||
pub user_session: Arc<UserSession>,
|
||||
pub document_manager2: Arc<DocumentManager2>,
|
||||
pub document_manager: Arc<DocumentManager>,
|
||||
pub folder_manager: Arc<FolderManager>,
|
||||
pub database_manager: Arc<DatabaseManager2>,
|
||||
pub database_manager: Arc<DatabaseManager>,
|
||||
pub event_dispatcher: Arc<AFPluginDispatcher>,
|
||||
pub server_provider: Arc<AppFlowyServerProvider>,
|
||||
pub task_dispatcher: Arc<RwLock<TaskDispatcher>>,
|
||||
@ -135,7 +134,7 @@ impl AppFlowyCore {
|
||||
// Init the key value database
|
||||
init_kv(&config.storage_path);
|
||||
|
||||
debug!("🔥 {:?}", &config);
|
||||
tracing::info!("🔥 {:?}", &config);
|
||||
let runtime = tokio_default_runtime().unwrap();
|
||||
let task_scheduler = TaskDispatcher::new(Duration::from_secs(2));
|
||||
let task_dispatcher = Arc::new(RwLock::new(task_scheduler));
|
||||
@ -146,52 +145,61 @@ impl AppFlowyCore {
|
||||
get_supabase_config(),
|
||||
));
|
||||
|
||||
let (user_session, folder_manager, server_provider, database_manager, document_manager2) =
|
||||
runtime.block_on(async {
|
||||
let user_session = mk_user_session(&config, server_provider.clone());
|
||||
/// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded
|
||||
/// on demand based on the [CollabPluginConfig].
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
server_provider.clone(),
|
||||
Some(Arc::new(SnapshotDBImpl(Arc::downgrade(&user_session)))),
|
||||
));
|
||||
let (
|
||||
user_session,
|
||||
folder_manager,
|
||||
server_provider,
|
||||
database_manager,
|
||||
document_manager,
|
||||
collab_builder,
|
||||
) = runtime.block_on(async {
|
||||
let user_session = mk_user_session(&config, server_provider.clone());
|
||||
/// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded
|
||||
/// on demand based on the [CollabPluginConfig].
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
server_provider.clone(),
|
||||
Some(Arc::new(SnapshotDBImpl(Arc::downgrade(&user_session)))),
|
||||
));
|
||||
|
||||
let database_manager2 = Database2DepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
task_dispatcher.clone(),
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
)
|
||||
.await;
|
||||
let database_manager = DatabaseDepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
task_dispatcher.clone(),
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let document_manager2 = Document2DepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
&database_manager2,
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
);
|
||||
let document_manager = DocumentDepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
&database_manager,
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
);
|
||||
|
||||
let folder_manager = Folder2DepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
&document_manager2,
|
||||
&database_manager2,
|
||||
collab_builder,
|
||||
server_provider.clone(),
|
||||
)
|
||||
.await;
|
||||
let folder_manager = FolderDepsResolver::resolve(
|
||||
Arc::downgrade(&user_session),
|
||||
&document_manager,
|
||||
&database_manager,
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
(
|
||||
user_session,
|
||||
folder_manager,
|
||||
server_provider,
|
||||
database_manager2,
|
||||
document_manager2,
|
||||
)
|
||||
});
|
||||
(
|
||||
user_session,
|
||||
folder_manager,
|
||||
server_provider,
|
||||
database_manager,
|
||||
document_manager,
|
||||
collab_builder,
|
||||
)
|
||||
});
|
||||
|
||||
let user_status_listener = UserStatusCallbackImpl {
|
||||
collab_builder,
|
||||
folder_manager: folder_manager.clone(),
|
||||
database_manager: database_manager.clone(),
|
||||
document_manager: document_manager.clone(),
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
@ -204,17 +212,17 @@ impl AppFlowyCore {
|
||||
|
||||
let event_dispatcher = Arc::new(AFPluginDispatcher::construct(runtime, || {
|
||||
make_plugins(
|
||||
&folder_manager,
|
||||
&database_manager,
|
||||
&user_session,
|
||||
&document_manager2,
|
||||
Arc::downgrade(&folder_manager),
|
||||
Arc::downgrade(&database_manager),
|
||||
Arc::downgrade(&user_session),
|
||||
Arc::downgrade(&document_manager),
|
||||
)
|
||||
}));
|
||||
|
||||
Self {
|
||||
config,
|
||||
user_session,
|
||||
document_manager2,
|
||||
document_manager,
|
||||
folder_manager,
|
||||
database_manager,
|
||||
event_dispatcher,
|
||||
@ -223,6 +231,7 @@ impl AppFlowyCore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Only expose the dispatcher in test
|
||||
pub fn dispatcher(&self) -> Arc<AFPluginDispatcher> {
|
||||
self.event_dispatcher.clone()
|
||||
}
|
||||
@ -254,8 +263,10 @@ fn mk_user_session(
|
||||
}
|
||||
|
||||
struct UserStatusCallbackImpl {
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
folder_manager: Arc<FolderManager>,
|
||||
database_manager: Arc<DatabaseManager2>,
|
||||
database_manager: Arc<DatabaseManager>,
|
||||
document_manager: Arc<DocumentManager>,
|
||||
#[allow(dead_code)]
|
||||
config: AppFlowyCoreConfig,
|
||||
}
|
||||
@ -263,32 +274,56 @@ struct UserStatusCallbackImpl {
|
||||
impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
fn auth_type_did_changed(&self, _auth_type: AuthType) {}
|
||||
|
||||
fn did_init(&self, user_id: i64, workspace_id: &str) -> Fut<FlowyResult<()>> {
|
||||
fn did_init(&self, user_id: i64, user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
||||
let user_id = user_id.to_owned();
|
||||
let workspace_id = workspace_id.to_owned();
|
||||
let user_workspace = user_workspace.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize(user_id, &workspace_id, FolderInitializeData::Empty)
|
||||
.initialize(user_id, &user_workspace.id, FolderInitializeData::Empty)
|
||||
.await?;
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.database_storage_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn did_sign_in(&self, user_id: i64, workspace_id: &str) -> Fut<FlowyResult<()>> {
|
||||
fn did_sign_in(&self, user_id: i64, user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
||||
let user_id = user_id.to_owned();
|
||||
let workspace_id = workspace_id.to_owned();
|
||||
let user_workspace = user_workspace.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize_when_sign_in(user_id, &workspace_id)
|
||||
.initialize_with_workspace_id(user_id, &user_workspace.id)
|
||||
.await?;
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.database_storage_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -297,25 +332,36 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
&self,
|
||||
context: SignUpContext,
|
||||
user_profile: &UserProfile,
|
||||
user_workspace: &UserWorkspace,
|
||||
) -> Fut<FlowyResult<()>> {
|
||||
let user_profile = user_profile.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let user_workspace = user_workspace.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize_when_sign_up(
|
||||
.initialize_with_new_user(
|
||||
user_profile.id,
|
||||
&user_profile.token,
|
||||
context.is_new,
|
||||
context.local_folder,
|
||||
&user_profile.workspace_id,
|
||||
&user_workspace.id,
|
||||
)
|
||||
.await?;
|
||||
database_manager
|
||||
.initialize_with_new_user(
|
||||
user_profile.id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.database_storage_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
database_manager
|
||||
.initialize_with_new_user(user_profile.id, &user_profile.token)
|
||||
document_manager
|
||||
.initialize_with_new_user(user_profile.id, user_workspace.id)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -327,6 +373,37 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn open_workspace(&self, user_id: i64, user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
||||
let user_workspace = user_workspace.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize_with_workspace_id(user_id, &user_workspace.id)
|
||||
.await?;
|
||||
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.database_storage_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn did_update_network(&self, reachable: bool) {
|
||||
self.collab_builder.update_network(reachable);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ServerProviderType> for CollabStorageType {
|
||||
|
@ -1,22 +1,22 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
|
||||
use flowy_database2::DatabaseManager2;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::manager::DocumentManager as DocumentManager2;
|
||||
use flowy_folder2::manager::FolderManager;
|
||||
use flowy_user::services::UserSession;
|
||||
use lib_dispatch::prelude::AFPlugin;
|
||||
|
||||
pub fn make_plugins(
|
||||
folder_manager: &Arc<FolderManager>,
|
||||
database_manager: &Arc<DatabaseManager2>,
|
||||
user_session: &Arc<UserSession>,
|
||||
document_manager2: &Arc<DocumentManager2>,
|
||||
folder_manager: Weak<FolderManager>,
|
||||
database_manager: Weak<DatabaseManager>,
|
||||
user_session: Weak<UserSession>,
|
||||
document_manager2: Weak<DocumentManager2>,
|
||||
) -> Vec<AFPlugin> {
|
||||
let user_plugin = flowy_user::event_map::init(user_session.clone());
|
||||
let folder_plugin = flowy_folder2::event_map::init(folder_manager.clone());
|
||||
let user_plugin = flowy_user::event_map::init(user_session);
|
||||
let folder_plugin = flowy_folder2::event_map::init(folder_manager);
|
||||
let network_plugin = flowy_net::event_map::init();
|
||||
let database_plugin = flowy_database2::event_map::init(database_manager.clone());
|
||||
let document_plugin2 = flowy_document2::event_map::init(document_manager2.clone());
|
||||
let database_plugin = flowy_database2::event_map::init(database_manager);
|
||||
let document_plugin2 = flowy_document2::event_map::init(document_manager2);
|
||||
let config_plugin = flowy_config::event_map::init();
|
||||
vec![
|
||||
user_plugin,
|
||||
|
12
frontend/rust-lib/flowy-database-deps/Cargo.toml
Normal file
12
frontend/rust-lib/flowy-database-deps/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "flowy-database-deps"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
collab-plugins = { version = "0.1.0" }
|
||||
anyhow = "1.0.71"
|
38
frontend/rust-lib/flowy-database-deps/src/cloud.rs
Normal file
38
frontend/rust-lib/flowy-database-deps/src/cloud.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use anyhow::Error;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use collab_plugins::cloud_storage::CollabType;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub type CollabObjectUpdateByOid = HashMap<String, CollabObjectUpdate>;
|
||||
pub type CollabObjectUpdate = Vec<Vec<u8>>;
|
||||
|
||||
/// A trait for database cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
/// [flowy-server] crate for more information.
|
||||
pub trait DatabaseCloudService: Send + Sync {
|
||||
fn get_collab_update(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdate, Error>;
|
||||
|
||||
fn batch_get_collab_updates(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, Error>;
|
||||
|
||||
fn get_collab_latest_snapshot(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, Error>;
|
||||
}
|
||||
|
||||
pub struct DatabaseSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub database_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
1
frontend/rust-lib/flowy-database-deps/src/lib.rs
Normal file
1
frontend/rust-lib/flowy-database-deps/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod cloud;
|
@ -9,12 +9,13 @@ edition = "2021"
|
||||
collab = { version = "0.1.0" }
|
||||
collab-database = { version = "0.1.0" }
|
||||
appflowy-integrate = {version = "0.1.0" }
|
||||
flowy-database-deps = { path = "../flowy-database-deps" }
|
||||
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
flowy-notification = { path = "../flowy-notification" }
|
||||
parking_lot = "0.12.1"
|
||||
protobuf = {version = "2.28.0"}
|
||||
flowy-error = { path = "../flowy-error", features = ["adaptor_dispatch", "collab"]}
|
||||
flowy-error = { path = "../flowy-error", features = ["impl_from_dispatch_error", "impl_from_collab"]}
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
tokio = { version = "1.26", features = ["sync"] }
|
||||
flowy-task= { path = "../flowy-task" }
|
||||
|
@ -1,38 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
pub use collab_database::user::CollabObjectUpdate;
|
||||
pub use collab_database::user::CollabObjectUpdateByOid;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub trait DatabaseUser2: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
/// A trait for database cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
/// [flowy-server] crate for more information.
|
||||
pub trait DatabaseCloudService: Send + Sync {
|
||||
fn get_collab_update(&self, object_id: &str) -> FutureResult<CollabObjectUpdate, FlowyError>;
|
||||
|
||||
fn batch_get_collab_updates(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, FlowyError>;
|
||||
|
||||
fn get_collab_latest_snapshot(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DatabaseSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub database_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use collab_database::database::gen_row_id;
|
||||
use collab_database::rows::RowId;
|
||||
@ -8,7 +8,7 @@ use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataRes
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::manager::DatabaseManager2;
|
||||
use crate::manager::DatabaseManager;
|
||||
use crate::services::cell::CellBuilder;
|
||||
use crate::services::field::checklist_type_option::ChecklistCellChangeset;
|
||||
use crate::services::field::{
|
||||
@ -17,11 +17,21 @@ use crate::services::field::{
|
||||
use crate::services::group::{GroupChangeset, GroupSettingChangeset};
|
||||
use crate::services::share::csv::CSVFormat;
|
||||
|
||||
fn upgrade_manager(
|
||||
database_manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<Arc<DatabaseManager>> {
|
||||
let manager = database_manager
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().context("The database manager is already dropped"))?;
|
||||
Ok(manager)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_database_data_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<DatabasePB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(view_id.as_ref()).await?;
|
||||
let data = database_editor.get_database_data(view_id.as_ref()).await?;
|
||||
@ -31,8 +41,9 @@ pub(crate) async fn get_database_data_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn open_database_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_id = manager
|
||||
.get_database_id_with_view_id(view_id.as_ref())
|
||||
@ -44,8 +55,9 @@ pub(crate) async fn open_database_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_database_id_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<DatabaseIdPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_id = manager
|
||||
.get_database_id_with_view_id(view_id.as_ref())
|
||||
@ -56,8 +68,9 @@ pub(crate) async fn get_database_id_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_database_setting_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<DatabaseViewSettingPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(view_id.as_ref()).await?;
|
||||
let data = database_editor
|
||||
@ -69,8 +82,9 @@ pub(crate) async fn get_database_setting_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn update_database_setting_handler(
|
||||
data: AFPluginData<DatabaseSettingChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: DatabaseSettingChangesetParams = data.into_inner().try_into()?;
|
||||
let editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
|
||||
@ -100,8 +114,9 @@ pub(crate) async fn update_database_setting_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_all_filters_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedFilterPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(view_id.as_ref()).await?;
|
||||
let filters = database_editor.get_all_filters(view_id.as_ref()).await;
|
||||
@ -111,8 +126,9 @@ pub(crate) async fn get_all_filters_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_all_sorts_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedSortPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(view_id.as_ref()).await?;
|
||||
let sorts = database_editor.get_all_sorts(view_id.as_ref()).await;
|
||||
@ -122,8 +138,9 @@ pub(crate) async fn get_all_sorts_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn delete_all_sorts_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(view_id.as_ref()).await?;
|
||||
database_editor.delete_all_sorts(view_id.as_ref()).await;
|
||||
@ -133,8 +150,9 @@ pub(crate) async fn delete_all_sorts_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_fields_handler(
|
||||
data: AFPluginData<GetFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedFieldPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: GetFieldParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let fields = database_editor
|
||||
@ -149,8 +167,9 @@ pub(crate) async fn get_fields_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_primary_field_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<FieldPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id = data.into_inner().value;
|
||||
let database_editor = manager.get_database_with_view_id(&view_id).await?;
|
||||
let mut fields = database_editor
|
||||
@ -177,8 +196,9 @@ pub(crate) async fn get_primary_field_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn update_field_handler(
|
||||
data: AFPluginData<FieldChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: FieldChangesetParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor.update_field(params).await?;
|
||||
@ -188,8 +208,9 @@ pub(crate) async fn update_field_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn update_field_type_option_handler(
|
||||
data: AFPluginData<TypeOptionChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: TypeOptionChangesetParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
if let Some(old_field) = database_editor.get_field(¶ms.field_id) {
|
||||
@ -211,8 +232,9 @@ pub(crate) async fn update_field_type_option_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn delete_field_handler(
|
||||
data: AFPluginData<DeleteFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: FieldIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor.delete_field(¶ms.field_id).await?;
|
||||
@ -222,8 +244,9 @@ pub(crate) async fn delete_field_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn switch_to_field_handler(
|
||||
data: AFPluginData<UpdateFieldTypePayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: EditFieldParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let old_field = database_editor.get_field(¶ms.field_id);
|
||||
@ -257,8 +280,9 @@ pub(crate) async fn switch_to_field_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn duplicate_field_handler(
|
||||
data: AFPluginData<DuplicateFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: FieldIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -271,8 +295,9 @@ pub(crate) async fn duplicate_field_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_field_type_option_data_handler(
|
||||
data: AFPluginData<TypeOptionPathPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<TypeOptionPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: TypeOptionPathParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
if let Some((field, data)) = database_editor
|
||||
@ -294,8 +319,9 @@ pub(crate) async fn get_field_type_option_data_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn create_field_type_option_data_handler(
|
||||
data: AFPluginData<CreateFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<TypeOptionPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CreateFieldParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let (field, data) = database_editor
|
||||
@ -313,8 +339,9 @@ pub(crate) async fn create_field_type_option_data_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn move_field_handler(
|
||||
data: AFPluginData<MoveFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: MoveFieldParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -331,8 +358,9 @@ pub(crate) async fn move_field_handler(
|
||||
// #[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_row_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<OptionalRowPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let row = database_editor
|
||||
@ -343,8 +371,9 @@ pub(crate) async fn get_row_handler(
|
||||
|
||||
pub(crate) async fn get_row_meta_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RowMetaPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
match database_editor.get_row_meta(¶ms.view_id, ¶ms.row_id) {
|
||||
@ -355,8 +384,9 @@ pub(crate) async fn get_row_meta_handler(
|
||||
|
||||
pub(crate) async fn update_row_meta_handler(
|
||||
data: AFPluginData<UpdateRowMetaChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: UpdateRowMetaParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let row_id = RowId::from(params.id.clone());
|
||||
@ -367,8 +397,9 @@ pub(crate) async fn update_row_meta_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn delete_row_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor.delete_row(¶ms.row_id).await;
|
||||
@ -378,8 +409,9 @@ pub(crate) async fn delete_row_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn duplicate_row_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -391,8 +423,9 @@ pub(crate) async fn duplicate_row_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn move_row_handler(
|
||||
data: AFPluginData<MoveRowPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: MoveRowParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -404,8 +437,9 @@ pub(crate) async fn move_row_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn create_row_handler(
|
||||
data: AFPluginData<CreateRowPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RowMetaPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CreateRowParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let fields = database_editor.get_fields(¶ms.view_id, None);
|
||||
@ -433,8 +467,9 @@ pub(crate) async fn create_row_handler(
|
||||
// #[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_cell_handler(
|
||||
data: AFPluginData<CellIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<CellPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CellIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let cell = database_editor
|
||||
@ -447,8 +482,9 @@ pub(crate) async fn get_cell_handler(
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn update_cell_handler(
|
||||
data: AFPluginData<CellChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CellChangesetPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -465,8 +501,9 @@ pub(crate) async fn update_cell_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn new_select_option_handler(
|
||||
data: AFPluginData<CreateSelectOptionPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<SelectOptionPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CreateSelectOptionParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let result = database_editor
|
||||
@ -483,8 +520,9 @@ pub(crate) async fn new_select_option_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn insert_or_update_select_option_handler(
|
||||
data: AFPluginData<RepeatedSelectOptionPayload>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -501,8 +539,9 @@ pub(crate) async fn insert_or_update_select_option_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn delete_select_option_handler(
|
||||
data: AFPluginData<RepeatedSelectOptionPayload>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -519,8 +558,9 @@ pub(crate) async fn delete_select_option_handler(
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_select_option_handler(
|
||||
data: AFPluginData<CellIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<SelectOptionCellDataPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CellIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let options = database_editor
|
||||
@ -532,8 +572,9 @@ pub(crate) async fn get_select_option_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn update_select_option_cell_handler(
|
||||
data: AFPluginData<SelectOptionCellChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager
|
||||
.get_database_with_view_id(¶ms.cell_identifier.view_id)
|
||||
@ -556,8 +597,9 @@ pub(crate) async fn update_select_option_cell_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_checklist_cell_data_handler(
|
||||
data: AFPluginData<CellIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<ChecklistCellDataPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CellIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let data = database_editor
|
||||
@ -569,8 +611,9 @@ pub(crate) async fn get_checklist_cell_data_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn update_checklist_cell_handler(
|
||||
data: AFPluginData<ChecklistCellDataChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: ChecklistCellDataChangesetParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let changeset = ChecklistCellChangeset {
|
||||
@ -588,8 +631,9 @@ pub(crate) async fn update_checklist_cell_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn update_date_cell_handler(
|
||||
data: AFPluginData<DateChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let data = data.into_inner();
|
||||
let cell_id: CellIdParams = data.cell_id.try_into()?;
|
||||
let cell_changeset = DateCellChangeset {
|
||||
@ -612,8 +656,9 @@ pub(crate) async fn update_date_cell_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_groups_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedGroupPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: DatabaseViewIdPB = data.into_inner();
|
||||
let database_editor = manager.get_database_with_view_id(params.as_ref()).await?;
|
||||
let groups = database_editor.load_groups(params.as_ref()).await?;
|
||||
@ -623,8 +668,9 @@ pub(crate) async fn get_groups_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn get_group_handler(
|
||||
data: AFPluginData<DatabaseGroupIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<GroupPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: DatabaseGroupIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let group = database_editor
|
||||
@ -636,8 +682,9 @@ pub(crate) async fn get_group_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn set_group_by_field_handler(
|
||||
data: AFPluginData<GroupByFieldPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: GroupByFieldParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -649,8 +696,9 @@ pub(crate) async fn set_group_by_field_handler(
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn update_group_handler(
|
||||
data: AFPluginData<UpdateGroupPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: UpdateGroupParams = data.into_inner().try_into()?;
|
||||
let view_id = params.view_id.clone();
|
||||
let database_editor = manager.get_database_with_view_id(&view_id).await?;
|
||||
@ -666,8 +714,9 @@ pub(crate) async fn update_group_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn move_group_handler(
|
||||
data: AFPluginData<MoveGroupPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: MoveGroupParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -679,8 +728,9 @@ pub(crate) async fn move_group_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn move_group_row_handler(
|
||||
data: AFPluginData<MoveGroupRowPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: MoveGroupRowParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
@ -696,8 +746,9 @@ pub(crate) async fn move_group_row_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(manager), err)]
|
||||
pub(crate) async fn get_databases_handler(
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedDatabaseDescriptionPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let data = manager.get_all_databases_description().await;
|
||||
data_result_ok(data)
|
||||
}
|
||||
@ -705,8 +756,9 @@ pub(crate) async fn get_databases_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn set_layout_setting_handler(
|
||||
data: AFPluginData<LayoutSettingChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: LayoutSettingChangeset = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let layout_params = LayoutSettingParams {
|
||||
@ -721,8 +773,9 @@ pub(crate) async fn set_layout_setting_handler(
|
||||
|
||||
pub(crate) async fn get_layout_setting_handler(
|
||||
data: AFPluginData<DatabaseLayoutMetaPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<DatabaseLayoutSettingPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: DatabaseLayoutMeta = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let layout_setting_pb = database_editor
|
||||
@ -736,8 +789,9 @@ pub(crate) async fn get_layout_setting_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_calendar_events_handler(
|
||||
data: AFPluginData<CalendarEventRequestPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedCalendarEventPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CalendarEventRequestParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let events = database_editor
|
||||
@ -749,8 +803,9 @@ pub(crate) async fn get_calendar_events_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_no_date_calendar_events_handler(
|
||||
data: AFPluginData<CalendarEventRequestPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedNoDateCalendarEventPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CalendarEventRequestParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let _events = database_editor
|
||||
@ -762,8 +817,9 @@ pub(crate) async fn get_no_date_calendar_events_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_calendar_event_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<CalendarEventPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let event = database_editor
|
||||
@ -778,8 +834,9 @@ pub(crate) async fn get_calendar_event_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn move_calendar_event_handler(
|
||||
data: AFPluginData<MoveCalendarEventPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let data = data.into_inner();
|
||||
let cell_id: CellIdParams = data.cell_path.try_into()?;
|
||||
let cell_changeset = DateCellChangeset {
|
||||
@ -801,7 +858,7 @@ pub(crate) async fn move_calendar_event_handler(
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn create_database_view(
|
||||
_data: AFPluginData<CreateDatabaseViewPayloadPB>,
|
||||
_manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
_manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
// let data: CreateDatabaseViewParams = data.into_inner().try_into()?;
|
||||
Ok(())
|
||||
@ -810,8 +867,9 @@ pub(crate) async fn create_database_view(
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn export_csv_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<DatabaseExportDataPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id = data.into_inner().value;
|
||||
let database = manager.get_database_with_view_id(&view_id).await?;
|
||||
let data = database.export_csv(CSVFormat::Original).await?;
|
||||
@ -824,8 +882,9 @@ pub(crate) async fn export_csv_handler(
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn get_snapshots_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> DataResult<RepeatedDatabaseSnapshotPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let view_id = data.into_inner().value;
|
||||
let snapshots = manager.get_database_snapshots(&view_id).await?;
|
||||
data_result_ok(RepeatedDatabaseSnapshotPB { items: snapshots })
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
|
||||
use strum_macros::Display;
|
||||
|
||||
@ -6,9 +6,9 @@ use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||
use lib_dispatch::prelude::*;
|
||||
|
||||
use crate::event_handler::*;
|
||||
use crate::manager::DatabaseManager2;
|
||||
use crate::manager::DatabaseManager;
|
||||
|
||||
pub fn init(database_manager: Arc<DatabaseManager2>) -> AFPlugin {
|
||||
pub fn init(database_manager: Weak<DatabaseManager>) -> AFPlugin {
|
||||
let plugin = AFPlugin::new()
|
||||
.name(env!("CARGO_PKG_NAME"))
|
||||
.state(database_manager);
|
||||
|
@ -1,11 +1,10 @@
|
||||
pub use manager::*;
|
||||
|
||||
pub mod deps;
|
||||
pub mod entities;
|
||||
mod event_handler;
|
||||
pub mod event_map;
|
||||
mod manager;
|
||||
mod notification;
|
||||
pub mod notification;
|
||||
mod protobuf;
|
||||
pub mod services;
|
||||
pub mod template;
|
||||
|
@ -1,23 +1,23 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::{CollabPersistenceConfig, RocksCollabDB};
|
||||
use appflowy_integrate::{CollabPersistenceConfig, CollabType, RocksCollabDB};
|
||||
use collab::core::collab::{CollabRawData, MutexCollab};
|
||||
use collab_database::blocks::BlockEvent;
|
||||
use collab_database::database::{DatabaseData, YrsDocAction};
|
||||
use collab_database::error::DatabaseError;
|
||||
use collab_database::user::{
|
||||
make_workspace_database_id, CollabFuture, CollabObjectUpdate, CollabObjectUpdateByOid,
|
||||
DatabaseCollabService, WorkspaceDatabase,
|
||||
CollabFuture, CollabObjectUpdate, CollabObjectUpdateByOid, DatabaseCollabService,
|
||||
WorkspaceDatabase,
|
||||
};
|
||||
use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLayout};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
use flowy_task::TaskDispatcher;
|
||||
|
||||
use crate::deps::{DatabaseCloudService, DatabaseUser2};
|
||||
use crate::entities::{
|
||||
DatabaseDescriptionPB, DatabaseLayoutPB, DatabaseSnapshotPB, DidFetchRowPB,
|
||||
RepeatedDatabaseDescriptionPB,
|
||||
@ -27,8 +27,14 @@ use crate::services::database::DatabaseEditor;
|
||||
use crate::services::database_view::DatabaseLayoutDepsResolver;
|
||||
use crate::services::share::csv::{CSVFormat, CSVImporter, ImportResult};
|
||||
|
||||
pub struct DatabaseManager2 {
|
||||
user: Arc<dyn DatabaseUser2>,
|
||||
pub trait DatabaseUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DatabaseManager {
|
||||
user: Arc<dyn DatabaseUser>,
|
||||
workspace_database: Arc<RwLock<Option<Arc<WorkspaceDatabase>>>>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
editors: RwLock<HashMap<String, Arc<DatabaseEditor>>>,
|
||||
@ -36,9 +42,9 @@ pub struct DatabaseManager2 {
|
||||
cloud_service: Arc<dyn DatabaseCloudService>,
|
||||
}
|
||||
|
||||
impl DatabaseManager2 {
|
||||
impl DatabaseManager {
|
||||
pub fn new(
|
||||
database_user: Arc<dyn DatabaseUser2>,
|
||||
database_user: Arc<dyn DatabaseUser>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
cloud_service: Arc<dyn DatabaseCloudService>,
|
||||
@ -53,14 +59,23 @@ impl DatabaseManager2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_collab_exist(&self, uid: i64, collab_db: &Arc<RocksCollabDB>, object_id: &str) -> bool {
|
||||
let read_txn = collab_db.read_txn();
|
||||
read_txn.is_exist(uid, object_id)
|
||||
fn is_collab_exist(&self, uid: i64, collab_db: &Weak<RocksCollabDB>, object_id: &str) -> bool {
|
||||
match collab_db.upgrade() {
|
||||
None => false,
|
||||
Some(collab_db) => {
|
||||
let read_txn = collab_db.read_txn();
|
||||
read_txn.is_exist(uid, object_id)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, uid: i64) -> FlowyResult<()> {
|
||||
pub async fn initialize(
|
||||
&self,
|
||||
uid: i64,
|
||||
_workspace_id: String,
|
||||
workspace_database_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
let workspace_database_id = make_workspace_database_id(uid);
|
||||
let collab_builder = UserDatabaseCollabServiceImpl {
|
||||
collab_builder: self.collab_builder.clone(),
|
||||
cloud_service: self.cloud_service.clone(),
|
||||
@ -73,7 +88,7 @@ impl DatabaseManager2 {
|
||||
tracing::trace!("workspace database not exist, try to fetch from remote");
|
||||
match self
|
||||
.cloud_service
|
||||
.get_collab_update(&workspace_database_id)
|
||||
.get_collab_update(&workspace_database_id, CollabType::WorkspaceDatabase)
|
||||
.await
|
||||
{
|
||||
Ok(updates) => collab_raw_data = updates,
|
||||
@ -91,7 +106,7 @@ impl DatabaseManager2 {
|
||||
let collab = collab_builder.build_collab_with_config(
|
||||
uid,
|
||||
&workspace_database_id,
|
||||
"databases",
|
||||
CollabType::WorkspaceDatabase,
|
||||
collab_db.clone(),
|
||||
collab_raw_data,
|
||||
&config,
|
||||
@ -100,11 +115,21 @@ impl DatabaseManager2 {
|
||||
WorkspaceDatabase::open(uid, collab, collab_db, config, collab_builder);
|
||||
subscribe_block_event(&workspace_database);
|
||||
*self.workspace_database.write().await = Some(Arc::new(workspace_database));
|
||||
|
||||
// Remove all existing editors
|
||||
self.editors.write().await.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn initialize_with_new_user(&self, user_id: i64, _token: &str) -> FlowyResult<()> {
|
||||
self.initialize(user_id).await?;
|
||||
pub async fn initialize_with_new_user(
|
||||
&self,
|
||||
user_id: i64,
|
||||
workspace_id: String,
|
||||
database_storage_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
self
|
||||
.initialize(user_id, workspace_id, database_storage_id)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -346,6 +371,7 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
fn get_collab_update(
|
||||
&self,
|
||||
object_id: &str,
|
||||
object_ty: CollabType,
|
||||
) -> CollabFuture<Result<CollabObjectUpdate, DatabaseError>> {
|
||||
let object_id = object_id.to_string();
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
@ -357,9 +383,8 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
},
|
||||
Some(cloud_service) => {
|
||||
let updates = cloud_service
|
||||
.get_collab_update(&object_id)
|
||||
.await
|
||||
.map_err(|e| DatabaseError::Internal(Box::new(e)))?;
|
||||
.get_collab_update(&object_id, object_ty)
|
||||
.await?;
|
||||
Ok(updates)
|
||||
},
|
||||
}
|
||||
@ -369,6 +394,7 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
fn batch_get_collab_update(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
object_ty: CollabType,
|
||||
) -> CollabFuture<Result<CollabObjectUpdateByOid, DatabaseError>> {
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
Box::pin(async move {
|
||||
@ -379,9 +405,8 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
},
|
||||
Some(cloud_service) => {
|
||||
let updates = cloud_service
|
||||
.batch_get_collab_updates(object_ids)
|
||||
.await
|
||||
.map_err(|e| DatabaseError::Internal(Box::new(e)))?;
|
||||
.batch_get_collab_updates(object_ids, object_ty)
|
||||
.await?;
|
||||
Ok(updates)
|
||||
},
|
||||
}
|
||||
@ -392,8 +417,8 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
&self,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_name: &str,
|
||||
collab_db: Arc<RocksCollabDB>,
|
||||
object_type: CollabType,
|
||||
collab_db: Weak<RocksCollabDB>,
|
||||
collab_raw_data: CollabRawData,
|
||||
config: &CollabPersistenceConfig,
|
||||
) -> Arc<MutexCollab> {
|
||||
@ -402,7 +427,7 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
.build_with_config(
|
||||
uid,
|
||||
object_id,
|
||||
object_name,
|
||||
object_type,
|
||||
collab_db,
|
||||
collab_raw_data,
|
||||
config,
|
||||
|
@ -74,7 +74,11 @@ impl DatabaseEditor {
|
||||
tokio::spawn(async move {
|
||||
while let Some(snapshot_state) = snapshot_state.next().await {
|
||||
if let Some(new_snapshot_id) = snapshot_state.snapshot_id() {
|
||||
tracing::debug!("Did create database remote snapshot: {}", new_snapshot_id);
|
||||
tracing::debug!(
|
||||
"Did create {} database remote snapshot: {}",
|
||||
database_id,
|
||||
new_snapshot_id
|
||||
);
|
||||
send_notification(
|
||||
&database_id,
|
||||
DatabaseNotification::DidUpdateDatabaseSnapshotState,
|
||||
|
12
frontend/rust-lib/flowy-document-deps/Cargo.toml
Normal file
12
frontend/rust-lib/flowy-document-deps/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "flowy-document-deps"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
collab-document = { version = "0.1.0" }
|
||||
anyhow = "1.0.71"
|
25
frontend/rust-lib/flowy-document-deps/src/cloud.rs
Normal file
25
frontend/rust-lib/flowy-document-deps/src/cloud.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use anyhow::Error;
|
||||
pub use collab_document::blocks::DocumentData;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
/// A trait for document cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
/// [flowy-server] crate for more information.
|
||||
pub trait DocumentCloudService: Send + Sync + 'static {
|
||||
fn get_document_updates(&self, document_id: &str) -> FutureResult<Vec<Vec<u8>>, Error>;
|
||||
|
||||
fn get_document_latest_snapshot(
|
||||
&self,
|
||||
document_id: &str,
|
||||
) -> FutureResult<Option<DocumentSnapshot>, Error>;
|
||||
|
||||
fn get_document_data(&self, document_id: &str) -> FutureResult<Option<DocumentData>, Error>;
|
||||
}
|
||||
|
||||
pub struct DocumentSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub document_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
1
frontend/rust-lib/flowy-document-deps/src/lib.rs
Normal file
1
frontend/rust-lib/flowy-document-deps/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod cloud;
|
@ -9,10 +9,11 @@ edition = "2021"
|
||||
collab = { version = "0.1.0" }
|
||||
collab-document = { version = "0.1.0" }
|
||||
appflowy-integrate = {version = "0.1.0" }
|
||||
flowy-document-deps = { path = "../flowy-document-deps" }
|
||||
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
flowy-notification = { path = "../flowy-notification" }
|
||||
flowy-error = { path = "../flowy-error", features = ["adaptor_serde", "adaptor_database", "adaptor_dispatch", "collab"] }
|
||||
flowy-error = { path = "../flowy-error", features = ["impl_from_serde", "impl_from_sqlite", "impl_from_dispatch_error", "impl_from_collab"] }
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
|
||||
@ -20,7 +21,6 @@ protobuf = {version = "2.28.0"}
|
||||
bytes = { version = "1.4" }
|
||||
nanoid = "0.4.0"
|
||||
parking_lot = "0.12.1"
|
||||
strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = {version = "1.0"}
|
||||
|
@ -1,34 +1 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
pub use collab_document::blocks::DocumentData;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub trait DocumentUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>; // unused now.
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
/// A trait for document cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
/// [flowy-server] crate for more information.
|
||||
pub trait DocumentCloudService: Send + Sync + 'static {
|
||||
fn get_document_updates(&self, document_id: &str) -> FutureResult<Vec<Vec<u8>>, FlowyError>;
|
||||
|
||||
fn get_document_latest_snapshot(
|
||||
&self,
|
||||
document_id: &str,
|
||||
) -> FutureResult<Option<DocumentSnapshot>, FlowyError>;
|
||||
|
||||
fn get_document_data(&self, document_id: &str) -> FutureResult<Option<DocumentData>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DocumentSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub document_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* which you can think of as a higher-level interface to interact with documents.
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use collab_document::blocks::{
|
||||
json_str_to_hashmap, Block, BlockAction, BlockActionPayload, BlockActionType, BlockEvent,
|
||||
@ -17,11 +17,21 @@ use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataRes
|
||||
use crate::entities::*;
|
||||
use crate::{manager::DocumentManager, parser::json::parser::JsonToDocumentParser};
|
||||
|
||||
fn upgrade_document(
|
||||
document_manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> FlowyResult<Arc<DocumentManager>> {
|
||||
let manager = document_manager
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().context("The document manager is already dropped"))?;
|
||||
Ok(manager)
|
||||
}
|
||||
|
||||
// Handler for creating a new document
|
||||
pub(crate) async fn create_document_handler(
|
||||
data: AFPluginData<CreateDocumentPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: CreateDocumentParams = data.into_inner().try_into()?;
|
||||
manager.create_document(¶ms.document_id, params.initial_data)?;
|
||||
Ok(())
|
||||
@ -30,8 +40,9 @@ pub(crate) async fn create_document_handler(
|
||||
// Handler for opening an existing document
|
||||
pub(crate) async fn open_document_handler(
|
||||
data: AFPluginData<OpenDocumentPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<DocumentDataPB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: OpenDocumentParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document = manager.get_document(&doc_id).await?;
|
||||
@ -41,8 +52,9 @@ pub(crate) async fn open_document_handler(
|
||||
|
||||
pub(crate) async fn close_document_handler(
|
||||
data: AFPluginData<CloseDocumentPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: CloseDocumentParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
manager.close_document(&doc_id)?;
|
||||
@ -53,8 +65,9 @@ pub(crate) async fn close_document_handler(
|
||||
// if the document does not exist, return an error.
|
||||
pub(crate) async fn get_document_data_handler(
|
||||
data: AFPluginData<OpenDocumentPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<DocumentDataPB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: OpenDocumentParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document_data = manager.get_document_data(&doc_id).await?;
|
||||
@ -64,8 +77,9 @@ pub(crate) async fn get_document_data_handler(
|
||||
// Handler for applying an action to a document
|
||||
pub(crate) async fn apply_action_handler(
|
||||
data: AFPluginData<ApplyActionPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: ApplyActionParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document = manager.get_document(&doc_id).await?;
|
||||
@ -76,7 +90,6 @@ pub(crate) async fn apply_action_handler(
|
||||
|
||||
pub(crate) async fn convert_data_to_document(
|
||||
data: AFPluginData<ConvertDataPayloadPB>,
|
||||
_manager: AFPluginState<Arc<DocumentManager>>,
|
||||
) -> DataResult<DocumentDataPB, FlowyError> {
|
||||
let payload = data.into_inner();
|
||||
let document = convert_data_to_document_internal(payload)?;
|
||||
@ -100,8 +113,9 @@ pub fn convert_data_to_document_internal(
|
||||
|
||||
pub(crate) async fn redo_handler(
|
||||
data: AFPluginData<DocumentRedoUndoPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<DocumentRedoUndoResponsePB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: DocumentRedoUndoParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document = manager.get_document(&doc_id).await?;
|
||||
@ -118,8 +132,9 @@ pub(crate) async fn redo_handler(
|
||||
|
||||
pub(crate) async fn undo_handler(
|
||||
data: AFPluginData<DocumentRedoUndoPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<DocumentRedoUndoResponsePB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: DocumentRedoUndoParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document = manager.get_document(&doc_id).await?;
|
||||
@ -136,8 +151,9 @@ pub(crate) async fn undo_handler(
|
||||
|
||||
pub(crate) async fn can_undo_redo_handler(
|
||||
data: AFPluginData<DocumentRedoUndoPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<DocumentRedoUndoResponsePB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: DocumentRedoUndoParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let document = manager.get_document(&doc_id).await?;
|
||||
@ -154,8 +170,9 @@ pub(crate) async fn can_undo_redo_handler(
|
||||
|
||||
pub(crate) async fn get_snapshot_handler(
|
||||
data: AFPluginData<OpenDocumentPayloadPB>,
|
||||
manager: AFPluginState<Arc<DocumentManager>>,
|
||||
manager: AFPluginState<Weak<DocumentManager>>,
|
||||
) -> DataResult<RepeatedDocumentSnapshotPB, FlowyError> {
|
||||
let manager = upgrade_document(manager)?;
|
||||
let params: OpenDocumentParams = data.into_inner().try_into()?;
|
||||
let doc_id = params.document_id;
|
||||
let snapshots = manager.get_document_snapshots(&doc_id).await?;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
|
||||
use strum_macros::Display;
|
||||
|
||||
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||
@ -7,7 +8,7 @@ use lib_dispatch::prelude::AFPlugin;
|
||||
use crate::event_handler::get_snapshot_handler;
|
||||
use crate::{event_handler::*, manager::DocumentManager};
|
||||
|
||||
pub fn init(document_manager: Arc<DocumentManager>) -> AFPlugin {
|
||||
pub fn init(document_manager: Weak<DocumentManager>) -> AFPlugin {
|
||||
AFPlugin::new()
|
||||
.name(env!("CARGO_PKG_NAME"))
|
||||
.state(document_manager)
|
||||
|
@ -8,5 +8,5 @@ pub mod parser;
|
||||
pub mod protobuf;
|
||||
|
||||
pub mod deps;
|
||||
mod notification;
|
||||
pub mod notification;
|
||||
mod parse;
|
||||
|
@ -1,18 +1,26 @@
|
||||
use std::sync::Weak;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::{CollabType, RocksCollabDB};
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab_document::blocks::DocumentData;
|
||||
use collab_document::document::Document;
|
||||
use collab_document::YrsDocAction;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use flowy_document_deps::cloud::DocumentCloudService;
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
|
||||
use crate::deps::{DocumentCloudService, DocumentUser};
|
||||
use crate::entities::DocumentSnapshotPB;
|
||||
use crate::{document::MutexDocument, document_data::default_document_data};
|
||||
|
||||
pub trait DocumentUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>; // unused now.
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DocumentManager {
|
||||
user: Arc<dyn DocumentUser>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
@ -35,6 +43,15 @@ impl DocumentManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, _uid: i64, _workspace_id: String) -> FlowyResult<()> {
|
||||
self.documents.write().clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn initialize_with_new_user(&self, uid: i64, workspace_id: String) -> FlowyResult<()> {
|
||||
self.initialize(uid, workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
/// Create a new document.
|
||||
///
|
||||
/// if the document already exists, return the existing document.
|
||||
@ -73,7 +90,7 @@ impl DocumentManager {
|
||||
let db = self.user.collab_db(uid)?;
|
||||
let collab = self
|
||||
.collab_builder
|
||||
.build(uid, doc_id, "document", updates, db)?;
|
||||
.build(uid, doc_id, CollabType::Document, updates, db)?;
|
||||
let document = Arc::new(MutexDocument::open(doc_id, collab)?);
|
||||
|
||||
// save the document to the memory and read it from the memory if we open the same document again.
|
||||
@ -110,12 +127,13 @@ impl DocumentManager {
|
||||
|
||||
pub fn delete_document(&self, doc_id: &str) -> FlowyResult<()> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.collab_db(uid)?;
|
||||
let _ = db.with_write_txn(|txn| {
|
||||
txn.delete_doc(uid, &doc_id)?;
|
||||
Ok(())
|
||||
});
|
||||
self.documents.write().remove(doc_id);
|
||||
if let Some(db) = self.user.collab_db(uid)?.upgrade() {
|
||||
let _ = db.with_write_txn(|txn| {
|
||||
txn.delete_doc(uid, &doc_id)?;
|
||||
Ok(())
|
||||
});
|
||||
self.documents.write().remove(doc_id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -151,15 +169,18 @@ impl DocumentManager {
|
||||
let db = self.user.collab_db(uid)?;
|
||||
let collab = self
|
||||
.collab_builder
|
||||
.build(uid, doc_id, "document", updates, db)?;
|
||||
.build(uid, doc_id, CollabType::Document, updates, db)?;
|
||||
Ok(collab)
|
||||
}
|
||||
|
||||
fn is_doc_exist(&self, doc_id: &str) -> FlowyResult<bool> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.collab_db(uid)?;
|
||||
let read_txn = db.read_txn();
|
||||
Ok(read_txn.is_exist(uid, doc_id))
|
||||
if let Some(collab_db) = self.user.collab_db(uid)?.upgrade() {
|
||||
let read_txn = collab_db.read_txn();
|
||||
Ok(read_txn.is_exist(uid, doc_id))
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Only expose this method for testing
|
||||
|
@ -4,7 +4,7 @@ use flowy_notification::NotificationBuilder;
|
||||
const DOCUMENT_OBSERVABLE_SOURCE: &str = "Document";
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug, Default)]
|
||||
pub(crate) enum DocumentNotification {
|
||||
pub enum DocumentNotification {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use anyhow::Error;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -9,11 +10,11 @@ use parking_lot::Once;
|
||||
use tempfile::TempDir;
|
||||
use tracing_subscriber::{fmt::Subscriber, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
use flowy_document2::deps::{DocumentCloudService, DocumentSnapshot, DocumentUser};
|
||||
use flowy_document2::document::MutexDocument;
|
||||
use flowy_document2::document_data::default_document_data;
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_document2::manager::{DocumentManager, DocumentUser};
|
||||
use flowy_document_deps::cloud::*;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub struct DocumentTest {
|
||||
@ -38,12 +39,12 @@ impl Deref for DocumentTest {
|
||||
}
|
||||
|
||||
pub struct FakeUser {
|
||||
kv: Arc<RocksCollabDB>,
|
||||
collab_db: Arc<RocksCollabDB>,
|
||||
}
|
||||
|
||||
impl FakeUser {
|
||||
pub fn new() -> Self {
|
||||
Self { kv: db() }
|
||||
Self { collab_db: db() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,8 +57,11 @@ impl DocumentUser for FakeUser {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn collab_db(&self, _uid: i64) -> Result<std::sync::Arc<RocksCollabDB>, flowy_error::FlowyError> {
|
||||
Ok(self.kv.clone())
|
||||
fn collab_db(
|
||||
&self,
|
||||
_uid: i64,
|
||||
) -> Result<std::sync::Weak<RocksCollabDB>, flowy_error::FlowyError> {
|
||||
Ok(Arc::downgrade(&self.collab_db))
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,21 +110,18 @@ pub fn gen_id() -> String {
|
||||
|
||||
pub struct LocalTestDocumentCloudServiceImpl();
|
||||
impl DocumentCloudService for LocalTestDocumentCloudServiceImpl {
|
||||
fn get_document_updates(&self, _document_id: &str) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
fn get_document_updates(&self, _document_id: &str) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn get_document_latest_snapshot(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
) -> FutureResult<Option<DocumentSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<DocumentSnapshot>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
|
||||
fn get_document_data(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
) -> FutureResult<Option<DocumentData>, FlowyError> {
|
||||
fn get_document_data(&self, _document_id: &str) -> FutureResult<Option<DocumentData>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
}
|
||||
|
@ -22,16 +22,20 @@ flowy-sqlite = { path = "../flowy-sqlite", optional = true}
|
||||
r2d2 = { version = "0.8", optional = true}
|
||||
collab-database = { version = "0.1.0", optional = true }
|
||||
collab-document = { version = "0.1.0", optional = true }
|
||||
tokio-postgres = { version = "0.7.8", optional = true }
|
||||
tokio = { version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
adaptor_dispatch = ["lib-dispatch"]
|
||||
adaptor_serde = ["serde_json"]
|
||||
adaptor_reqwest = ["reqwest"]
|
||||
adaptor_database = ["flowy-sqlite", "r2d2"]
|
||||
adaptor_server_error = ["http-error-code"]
|
||||
impl_from_dispatch_error = ["lib-dispatch"]
|
||||
impl_from_serde = ["serde_json"]
|
||||
impl_from_reqwest = ["reqwest"]
|
||||
impl_from_sqlite = ["flowy-sqlite", "r2d2"]
|
||||
impl_from_appflowy_cloud = ["http-error-code"]
|
||||
impl_from_collab = ["collab-database", "collab-document", "impl_from_reqwest"]
|
||||
impl_from_postgres = ["tokio-postgres"]
|
||||
impl_from_tokio= ["tokio"]
|
||||
dart = ["flowy-codegen/dart"]
|
||||
ts = ["flowy-codegen/ts"]
|
||||
collab = ["collab-database", "collab-document"]
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen = { path = "../../../shared-lib/flowy-codegen", features = ["proto_gen"]}
|
||||
|
@ -57,9 +57,6 @@ pub enum ErrorCode {
|
||||
#[error("View name too long")]
|
||||
ViewNameTooLong = 17,
|
||||
|
||||
#[error("Http server connection error")]
|
||||
HttpServerConnectError = 18,
|
||||
|
||||
#[error("Email can not be empty or whitespace")]
|
||||
EmailIsEmpty = 19,
|
||||
|
||||
@ -179,7 +176,7 @@ pub enum ErrorCode {
|
||||
#[error("Sql error")]
|
||||
SqlError = 58,
|
||||
|
||||
#[error("Http request error")]
|
||||
#[error("Http error")]
|
||||
HttpError = 59,
|
||||
|
||||
#[error("The content should not be empty")]
|
||||
@ -215,8 +212,14 @@ pub enum ErrorCode {
|
||||
#[error("Postgres database error")]
|
||||
PgDatabaseError = 70,
|
||||
|
||||
#[error("Postgres transaction error")]
|
||||
PgTransactionError = 71,
|
||||
|
||||
#[error("Enable supabase sync")]
|
||||
SupabaseSyncRequired = 71,
|
||||
SupabaseSyncRequired = 72,
|
||||
|
||||
#[error("Conflict")]
|
||||
Conflict = 73,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
|
@ -58,7 +58,6 @@ impl FlowyError {
|
||||
static_flowy_error!(view_desc, ErrorCode::ViewDescTooLong);
|
||||
static_flowy_error!(view_data, ErrorCode::ViewDataInvalid);
|
||||
static_flowy_error!(unauthorized, ErrorCode::UserUnauthorized);
|
||||
static_flowy_error!(connection, ErrorCode::HttpServerConnectError);
|
||||
static_flowy_error!(email_empty, ErrorCode::EmailIsEmpty);
|
||||
static_flowy_error!(email_format, ErrorCode::EmailFormatInvalid);
|
||||
static_flowy_error!(email_exist, ErrorCode::EmailAlreadyExists);
|
||||
@ -121,6 +120,7 @@ impl std::convert::From<protobuf::ProtobufError> for FlowyError {
|
||||
|
||||
impl From<anyhow::Error> for FlowyError {
|
||||
fn from(e: anyhow::Error) -> Self {
|
||||
FlowyError::internal().context(e)
|
||||
e.downcast::<FlowyError>()
|
||||
.unwrap_or_else(|err| FlowyError::new(ErrorCode::Internal, err))
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
// #[cfg(feature = "adaptor_ot")]
|
||||
// pub mod ot;
|
||||
|
||||
#[cfg(feature = "adaptor_serde")]
|
||||
pub mod serde;
|
||||
|
||||
#[cfg(feature = "adaptor_dispatch")]
|
||||
pub mod dispatch;
|
||||
|
||||
#[cfg(feature = "adaptor_reqwest")]
|
||||
pub mod reqwest;
|
||||
|
||||
#[cfg(feature = "adaptor_database")]
|
||||
pub mod database;
|
||||
|
||||
#[cfg(feature = "adaptor_server_error")]
|
||||
pub mod http_server;
|
||||
|
||||
#[cfg(feature = "collab")]
|
||||
pub mod collab;
|
@ -9,7 +9,7 @@ impl std::convert::From<ServerErrorCode> for ErrorCode {
|
||||
ServerErrorCode::RecordNotFound => ErrorCode::RecordNotFound,
|
||||
ServerErrorCode::ConnectRefused
|
||||
| ServerErrorCode::ConnectTimeout
|
||||
| ServerErrorCode::ConnectClose => ErrorCode::HttpServerConnectError,
|
||||
| ServerErrorCode::ConnectClose => ErrorCode::HttpError,
|
||||
_ => ErrorCode::Internal,
|
||||
}
|
||||
}
|
26
frontend/rust-lib/flowy-error/src/impl_from/mod.rs
Normal file
26
frontend/rust-lib/flowy-error/src/impl_from/mod.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// #[cfg(feature = "adaptor_ot")]
|
||||
// pub mod ot;
|
||||
|
||||
#[cfg(feature = "impl_from_serde")]
|
||||
pub mod serde;
|
||||
|
||||
#[cfg(feature = "impl_from_dispatch_error")]
|
||||
pub mod dispatch;
|
||||
|
||||
#[cfg(feature = "impl_from_reqwest")]
|
||||
pub mod reqwest;
|
||||
|
||||
#[cfg(feature = "impl_from_sqlite")]
|
||||
pub mod database;
|
||||
|
||||
#[cfg(feature = "impl_from_appflowy_cloud")]
|
||||
pub mod http_server;
|
||||
|
||||
#[cfg(feature = "impl_from_collab")]
|
||||
pub mod collab;
|
||||
|
||||
#[cfg(feature = "impl_from_postgres")]
|
||||
mod postgres;
|
||||
|
||||
#[cfg(feature = "impl_from_tokio")]
|
||||
mod tokio;
|
7
frontend/rust-lib/flowy-error/src/impl_from/postgres.rs
Normal file
7
frontend/rust-lib/flowy-error/src/impl_from/postgres.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use crate::FlowyError;
|
||||
|
||||
impl std::convert::From<tokio_postgres::Error> for FlowyError {
|
||||
fn from(error: tokio_postgres::Error) -> Self {
|
||||
FlowyError::internal().context(error)
|
||||
}
|
||||
}
|
@ -3,6 +3,6 @@ use reqwest::Error;
|
||||
|
||||
impl std::convert::From<reqwest::Error> for FlowyError {
|
||||
fn from(error: Error) -> Self {
|
||||
FlowyError::connection().context(error)
|
||||
FlowyError::http().context(error)
|
||||
}
|
||||
}
|
7
frontend/rust-lib/flowy-error/src/impl_from/tokio.rs
Normal file
7
frontend/rust-lib/flowy-error/src/impl_from/tokio.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use crate::FlowyError;
|
||||
|
||||
// impl<T> std::convert::From<tokio::sync::mpsc::error::SendError<T>> for FlowyError {
|
||||
// fn from(error: tokio::sync::mpsc::error::SendError<T>) -> Self {
|
||||
// FlowyError::internal().context(error)
|
||||
// }
|
||||
// }
|
@ -1,6 +1,6 @@
|
||||
pub mod code;
|
||||
mod errors;
|
||||
mod ext;
|
||||
mod impl_from;
|
||||
pub mod protobuf;
|
||||
|
||||
pub use code::*;
|
||||
|
13
frontend/rust-lib/flowy-folder-deps/Cargo.toml
Normal file
13
frontend/rust-lib/flowy-folder-deps/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "flowy-folder-deps"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
collab-folder = { version = "0.1.0" }
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
anyhow = "1.0.71"
|
33
frontend/rust-lib/flowy-folder-deps/src/cloud.rs
Normal file
33
frontend/rust-lib/flowy-folder-deps/src/cloud.rs
Normal file
@ -0,0 +1,33 @@
|
||||
pub use collab_folder::core::{Folder, FolderData, Workspace};
|
||||
|
||||
pub use anyhow::Error;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// [FolderCloudService] represents the cloud service for folder.
|
||||
pub trait FolderCloudService: Send + Sync + 'static {
|
||||
fn create_workspace(&self, uid: i64, name: &str) -> FutureResult<Workspace, Error>;
|
||||
|
||||
fn get_folder_data(&self, workspace_id: &str) -> FutureResult<Option<FolderData>, Error>;
|
||||
|
||||
fn get_folder_latest_snapshot(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<FolderSnapshot>, Error>;
|
||||
|
||||
fn get_folder_updates(&self, workspace_id: &str, uid: i64) -> FutureResult<Vec<Vec<u8>>, Error>;
|
||||
|
||||
fn service_name(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct FolderSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub database_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
||||
|
||||
pub fn gen_workspace_id() -> Uuid {
|
||||
uuid::Uuid::new_v4()
|
||||
}
|
1
frontend/rust-lib/flowy-folder-deps/src/lib.rs
Normal file
1
frontend/rust-lib/flowy-folder-deps/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod cloud;
|
@ -9,13 +9,14 @@ edition = "2021"
|
||||
collab = { version = "0.1.0" }
|
||||
collab-folder = { version = "0.1.0" }
|
||||
appflowy-integrate = {version = "0.1.0" }
|
||||
flowy-folder-deps = { path = "../flowy-folder-deps" }
|
||||
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
flowy-notification = { path = "../flowy-notification" }
|
||||
parking_lot = "0.12.1"
|
||||
unicode-segmentation = "1.10"
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
flowy-error = { path = "../flowy-error", features = ["adaptor_dispatch"]}
|
||||
flowy-error = { path = "../flowy-error", features = ["impl_from_dispatch_error"]}
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
bytes = { version = "1.4" }
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
@ -23,7 +24,6 @@ tokio = { version = "1.26", features = ["full"] }
|
||||
nanoid = "0.4.0"
|
||||
lazy_static = "1.4.0"
|
||||
chrono = { version = "0.4.22", default-features = false, features = ["clock"] }
|
||||
strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
protobuf = {version = "2.28.0"}
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
|
@ -1,42 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
pub use collab_folder::core::FolderData;
|
||||
pub use collab_folder::core::Workspace;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
/// [FolderUser] represents the user for folder.
|
||||
pub trait FolderUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
/// [FolderCloudService] represents the cloud service for folder.
|
||||
pub trait FolderCloudService: Send + Sync + 'static {
|
||||
fn create_workspace(&self, uid: i64, name: &str) -> FutureResult<Workspace, FlowyError>;
|
||||
|
||||
fn get_folder_data(&self, workspace_id: &str) -> FutureResult<Option<FolderData>, FlowyError>;
|
||||
|
||||
fn get_folder_latest_snapshot(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<FolderSnapshot>, FlowyError>;
|
||||
|
||||
fn get_folder_updates(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
uid: i64,
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError>;
|
||||
|
||||
fn service_name(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct FolderSnapshot {
|
||||
pub snapshot_id: i64,
|
||||
pub database_id: String,
|
||||
pub data: Vec<u8>,
|
||||
pub created_at: i64,
|
||||
}
|
@ -1,17 +1,27 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::manager::FolderManager;
|
||||
use crate::share::ImportParams;
|
||||
|
||||
fn upgrade_folder(
|
||||
folder_manager: AFPluginState<Weak<FolderManager>>,
|
||||
) -> FlowyResult<Arc<FolderManager>> {
|
||||
let folder = folder_manager
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().context("The folder manager is already dropped"))?;
|
||||
Ok(folder)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn create_workspace_handler(
|
||||
data: AFPluginData<CreateWorkspacePayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspacePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: CreateWorkspaceParams = data.into_inner().try_into()?;
|
||||
let workspace = folder.create_workspace(params).await?;
|
||||
data_result_ok(workspace.into())
|
||||
@ -19,8 +29,9 @@ pub(crate) async fn create_workspace_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn get_workspace_views_handler(
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let child_views = folder.get_current_workspace_views().await?;
|
||||
let repeated_view: RepeatedViewPB = child_views.into();
|
||||
data_result_ok(repeated_view)
|
||||
@ -29,8 +40,9 @@ pub(crate) async fn get_workspace_views_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn open_workspace_handler(
|
||||
data: AFPluginData<WorkspaceIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspacePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: WorkspaceIdPB = data.into_inner();
|
||||
match params.value {
|
||||
None => Err(FlowyError::workspace_id().context("workspace id should not be empty")),
|
||||
@ -50,8 +62,9 @@ pub(crate) async fn open_workspace_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn read_workspaces_handler(
|
||||
data: AFPluginData<WorkspaceIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedWorkspacePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: WorkspaceIdPB = data.into_inner();
|
||||
let workspaces = match params.value {
|
||||
None => folder.get_all_workspaces().await,
|
||||
@ -67,8 +80,9 @@ pub(crate) async fn read_workspaces_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub async fn get_current_workspace_setting_handler(
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspaceSettingPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let workspace = folder.get_current_workspace().await?;
|
||||
let latest_view: Option<ViewPB> = folder.get_current_view().await;
|
||||
data_result_ok(WorkspaceSettingPB {
|
||||
@ -79,8 +93,9 @@ pub async fn get_current_workspace_setting_handler(
|
||||
|
||||
pub(crate) async fn create_view_handler(
|
||||
data: AFPluginData<CreateViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<ViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: CreateViewParams = data.into_inner().try_into()?;
|
||||
let set_as_current = params.set_as_current;
|
||||
let view = folder.create_view_with_params(params).await?;
|
||||
@ -92,8 +107,9 @@ pub(crate) async fn create_view_handler(
|
||||
|
||||
pub(crate) async fn create_orphan_view_handler(
|
||||
data: AFPluginData<CreateOrphanViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<ViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: CreateViewParams = data.into_inner().try_into()?;
|
||||
let set_as_current = params.set_as_current;
|
||||
let view = folder.create_orphan_view_with_params(params).await?;
|
||||
@ -105,8 +121,9 @@ pub(crate) async fn create_orphan_view_handler(
|
||||
|
||||
pub(crate) async fn read_view_handler(
|
||||
data: AFPluginData<ViewIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<ViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view_id: ViewIdPB = data.into_inner();
|
||||
let view_pb = folder.get_view(&view_id.value).await?;
|
||||
data_result_ok(view_pb)
|
||||
@ -115,8 +132,9 @@ pub(crate) async fn read_view_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn update_view_handler(
|
||||
data: AFPluginData<UpdateViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: UpdateViewParams = data.into_inner().try_into()?;
|
||||
folder.update_view_with_params(params).await?;
|
||||
Ok(())
|
||||
@ -124,8 +142,9 @@ pub(crate) async fn update_view_handler(
|
||||
|
||||
pub(crate) async fn delete_view_handler(
|
||||
data: AFPluginData<RepeatedViewIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: RepeatedViewIdPB = data.into_inner();
|
||||
for view_id in ¶ms.items {
|
||||
let _ = folder.move_view_to_trash(view_id).await;
|
||||
@ -135,8 +154,9 @@ pub(crate) async fn delete_view_handler(
|
||||
|
||||
pub(crate) async fn set_latest_view_handler(
|
||||
data: AFPluginData<ViewIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view_id: ViewIdPB = data.into_inner();
|
||||
let _ = folder.set_current_view(&view_id.value).await;
|
||||
Ok(())
|
||||
@ -144,8 +164,9 @@ pub(crate) async fn set_latest_view_handler(
|
||||
|
||||
pub(crate) async fn close_view_handler(
|
||||
data: AFPluginData<ViewIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view_id: ViewIdPB = data.into_inner();
|
||||
let _ = folder.close_view(&view_id.value).await;
|
||||
Ok(())
|
||||
@ -154,8 +175,9 @@ pub(crate) async fn close_view_handler(
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn move_view_handler(
|
||||
data: AFPluginData<MoveViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: MoveViewParams = data.into_inner().try_into()?;
|
||||
folder
|
||||
.move_view(¶ms.view_id, params.from, params.to)
|
||||
@ -165,8 +187,9 @@ pub(crate) async fn move_view_handler(
|
||||
|
||||
pub(crate) async fn move_nested_view_handler(
|
||||
data: AFPluginData<MoveNestedViewPayloadPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: MoveNestedViewParams = data.into_inner().try_into()?;
|
||||
folder
|
||||
.move_nested_view(params.view_id, params.new_parent_id, params.prev_view_id)
|
||||
@ -177,8 +200,9 @@ pub(crate) async fn move_nested_view_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn duplicate_view_handler(
|
||||
data: AFPluginData<ViewPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view: ViewPB = data.into_inner();
|
||||
folder.duplicate_view(&view.id).await?;
|
||||
Ok(())
|
||||
@ -186,8 +210,9 @@ pub(crate) async fn duplicate_view_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn read_trash_handler(
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedTrashPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let trash = folder.get_all_trash().await;
|
||||
data_result_ok(trash.into())
|
||||
}
|
||||
@ -195,8 +220,9 @@ pub(crate) async fn read_trash_handler(
|
||||
#[tracing::instrument(level = "debug", skip(identifier, folder), err)]
|
||||
pub(crate) async fn putback_trash_handler(
|
||||
identifier: AFPluginData<TrashIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
folder.restore_trash(&identifier.id).await;
|
||||
Ok(())
|
||||
}
|
||||
@ -204,8 +230,9 @@ pub(crate) async fn putback_trash_handler(
|
||||
#[tracing::instrument(level = "debug", skip(identifiers, folder), err)]
|
||||
pub(crate) async fn delete_trash_handler(
|
||||
identifiers: AFPluginData<RepeatedTrashIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let trash_ids = identifiers.into_inner().items;
|
||||
for trash_id in trash_ids {
|
||||
let _ = folder.delete_trash(&trash_id.id).await;
|
||||
@ -215,16 +242,18 @@ pub(crate) async fn delete_trash_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn restore_all_trash_handler(
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
folder.restore_all_trash().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn delete_all_trash_handler(
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
folder.delete_all_trash().await;
|
||||
Ok(())
|
||||
}
|
||||
@ -232,8 +261,9 @@ pub(crate) async fn delete_all_trash_handler(
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn import_data_handler(
|
||||
data: AFPluginData<ImportPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: ImportParams = data.into_inner().try_into()?;
|
||||
folder.import(params).await?;
|
||||
Ok(())
|
||||
@ -242,8 +272,9 @@ pub(crate) async fn import_data_handler(
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn get_folder_snapshots_handler(
|
||||
data: AFPluginData<WorkspaceIdPB>,
|
||||
folder: AFPluginState<Arc<FolderManager>>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedFolderSnapshotPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
if let Some(workspace_id) = &data.value {
|
||||
let snapshots = folder.get_folder_snapshots(workspace_id).await?;
|
||||
data_result_ok(RepeatedFolderSnapshotPB { items: snapshots })
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
|
||||
use strum_macros::Display;
|
||||
|
||||
@ -8,7 +8,7 @@ use lib_dispatch::prelude::*;
|
||||
use crate::event_handler::*;
|
||||
use crate::manager::FolderManager;
|
||||
|
||||
pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
|
||||
pub fn init(folder: Weak<FolderManager>) -> AFPlugin {
|
||||
AFPlugin::new().name("Flowy-Folder").state(folder)
|
||||
// Workspace
|
||||
.event(FolderEvent::CreateWorkspace, create_workspace_handler)
|
||||
|
@ -1,16 +1,14 @@
|
||||
pub use collab_folder::core::ViewLayout;
|
||||
|
||||
pub mod entities;
|
||||
pub mod event_handler;
|
||||
pub mod event_map;
|
||||
pub mod manager;
|
||||
mod notification;
|
||||
pub mod notification;
|
||||
pub mod protobuf;
|
||||
mod user_default;
|
||||
pub mod view_operation;
|
||||
|
||||
pub mod deps;
|
||||
pub mod share;
|
||||
#[cfg(feature = "test_helper")]
|
||||
mod test_helper;
|
||||
|
||||
pub use collab_folder::core::ViewLayout;
|
||||
pub use user_default::gen_workspace_id;
|
||||
|
@ -3,7 +3,7 @@ use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::{CollabPersistenceConfig, RocksCollabDB};
|
||||
use appflowy_integrate::{CollabPersistenceConfig, CollabType, RocksCollabDB};
|
||||
use collab::core::collab::{CollabRawData, MutexCollab};
|
||||
use collab::core::collab_state::SyncState;
|
||||
use collab_folder::core::{
|
||||
@ -16,8 +16,8 @@ use tokio_stream::StreamExt;
|
||||
use tracing::{event, Level};
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder_deps::cloud::FolderCloudService;
|
||||
|
||||
use crate::deps::{FolderCloudService, FolderUser};
|
||||
use crate::entities::{
|
||||
view_pb_with_child_views, view_pb_without_child_views, ChildViewUpdatePB, CreateViewParams,
|
||||
CreateWorkspaceParams, DeletedViewPB, FolderSnapshotPB, FolderSnapshotStatePB, FolderSyncStatePB,
|
||||
@ -33,6 +33,13 @@ use crate::view_operation::{
|
||||
create_view, gen_view_id, FolderOperationHandler, FolderOperationHandlers,
|
||||
};
|
||||
|
||||
/// [FolderUser] represents the user for folder.
|
||||
pub trait FolderUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct FolderManager {
|
||||
mutex_folder: Arc<MutexFolder>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
@ -172,13 +179,13 @@ impl FolderManager {
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
collab_db: Arc<RocksCollabDB>,
|
||||
collab_db: Weak<RocksCollabDB>,
|
||||
raw_data: CollabRawData,
|
||||
) -> Result<Arc<MutexCollab>, FlowyError> {
|
||||
let collab = self.collab_builder.build_with_config(
|
||||
uid,
|
||||
workspace_id,
|
||||
"workspace",
|
||||
CollabType::Folder,
|
||||
collab_db,
|
||||
raw_data,
|
||||
&CollabPersistenceConfig::new().enable_snapshot(true),
|
||||
@ -186,8 +193,14 @@ impl FolderManager {
|
||||
Ok(collab)
|
||||
}
|
||||
|
||||
/// Initialize the folder with the given workspace id.
|
||||
/// Fetch the folder updates from the cloud service and initialize the folder.
|
||||
#[tracing::instrument(level = "debug", skip(self, user_id), err)]
|
||||
pub async fn initialize_when_sign_in(&self, user_id: i64, workspace_id: &str) -> FlowyResult<()> {
|
||||
pub async fn initialize_with_workspace_id(
|
||||
&self,
|
||||
user_id: i64,
|
||||
workspace_id: &str,
|
||||
) -> FlowyResult<()> {
|
||||
let folder_updates = self
|
||||
.cloud_service
|
||||
.get_folder_updates(workspace_id, user_id)
|
||||
@ -209,7 +222,9 @@ impl FolderManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn initialize_when_sign_up(
|
||||
/// Initialize the folder for the new user.
|
||||
/// Using the [DefaultFolderBuilder] to create the default workspace for the new user.
|
||||
pub async fn initialize_with_new_user(
|
||||
&self,
|
||||
user_id: i64,
|
||||
_token: &str,
|
||||
@ -239,11 +254,6 @@ impl FolderManager {
|
||||
FolderInitializeData::Data(folder_data),
|
||||
)
|
||||
.await?;
|
||||
// send_notification(token, FolderNotification::DidCreateWorkspace)
|
||||
// .payload(RepeatedWorkspacePB {
|
||||
// items: vec![workspace_pb],
|
||||
// })
|
||||
// .send();
|
||||
} else {
|
||||
// The folder data is loaded through the [FolderCloudService]. If the cloud service in use is
|
||||
// [LocalServerFolderCloudServiceImpl], the folder data will be None because the Folder will load
|
||||
@ -310,6 +320,15 @@ impl FolderManager {
|
||||
self.with_folder(None, |folder| folder.workspaces.get_workspace(workspace_id))
|
||||
}
|
||||
|
||||
async fn get_current_workspace_id(&self) -> FlowyResult<String> {
|
||||
self
|
||||
.mutex_folder
|
||||
.lock()
|
||||
.as_ref()
|
||||
.and_then(|folder| folder.get_current_workspace_id())
|
||||
.ok_or(FlowyError::internal().context("Unexpected empty workspace id"))
|
||||
}
|
||||
|
||||
fn with_folder<F, Output>(&self, default_value: Output, f: F) -> Output
|
||||
where
|
||||
F: FnOnce(&Folder) -> Output,
|
||||
@ -327,6 +346,7 @@ impl FolderManager {
|
||||
|
||||
pub async fn create_view_with_params(&self, params: CreateViewParams) -> FlowyResult<View> {
|
||||
let view_layout: ViewLayout = params.layout.clone().into();
|
||||
let _workspace_id = self.get_current_workspace_id().await?;
|
||||
let handler = self.get_handler(&view_layout)?;
|
||||
let user_id = self.user.user_id()?;
|
||||
let meta = params.meta.clone();
|
||||
@ -380,13 +400,10 @@ impl FolderManager {
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
let view = self
|
||||
.with_folder(None, |folder| folder.views.get_view(view_id))
|
||||
.ok_or_else(|| {
|
||||
FlowyError::record_not_found().context("Can't find the view when closing the view")
|
||||
})?;
|
||||
let handler = self.get_handler(&view.layout)?;
|
||||
handler.close_view(view_id).await?;
|
||||
if let Some(view) = self.with_folder(None, |folder| folder.views.get_view(view_id)) {
|
||||
let handler = self.get_handler(&view.layout)?;
|
||||
handler.close_view(view_id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use crate::entities::{view_pb_without_child_views, WorkspacePB, WorkspaceSetting
|
||||
const FOLDER_OBSERVABLE_SOURCE: &str = "Workspace";
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug, Default)]
|
||||
pub(crate) enum FolderNotification {
|
||||
pub enum FolderNotification {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
/// Trigger after creating a workspace
|
||||
|
@ -59,10 +59,6 @@ impl DefaultFolderBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_workspace_id() -> String {
|
||||
uuid::Uuid::new_v4().to_string()
|
||||
}
|
||||
|
||||
impl From<&ParentChildViews> for ViewPB {
|
||||
fn from(value: &ParentChildViews) -> Self {
|
||||
view_pb_with_child_views(
|
||||
|
@ -274,16 +274,19 @@ pub async fn move_view(
|
||||
parent_id: String,
|
||||
prev_view_id: Option<String>,
|
||||
) {
|
||||
let request = MoveNestedViewPayloadPB {
|
||||
let payload = MoveNestedViewPayloadPB {
|
||||
view_id,
|
||||
new_parent_id: parent_id,
|
||||
prev_view_id,
|
||||
};
|
||||
EventBuilder::new(sdk.clone())
|
||||
let error = EventBuilder::new(sdk.clone())
|
||||
.event(MoveNestedView)
|
||||
.payload(request)
|
||||
.payload(payload)
|
||||
.async_send()
|
||||
.await;
|
||||
.await
|
||||
.error();
|
||||
|
||||
assert!(error.is_none());
|
||||
}
|
||||
pub async fn update_view(
|
||||
sdk: &FlowyCoreTest,
|
||||
|
@ -7,25 +7,18 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
lib-dispatch = { path = "../lib-dispatch" }
|
||||
flowy-error = { path = "../flowy-error", features = ["adaptor_reqwest", "adaptor_server_error"] }
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
protobuf = {version = "2.28.0"}
|
||||
anyhow = "1.0"
|
||||
thiserror = "1.0"
|
||||
bytes = { version = "1.4" }
|
||||
strum_macros = "0.21"
|
||||
tracing = { version = "0.1"}
|
||||
|
||||
[features]
|
||||
http_server = []
|
||||
dart = [
|
||||
"flowy-codegen/dart",
|
||||
"flowy-error/dart",
|
||||
]
|
||||
|
||||
ts = [
|
||||
"flowy-codegen/ts",
|
||||
"flowy-error/ts",
|
||||
]
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -1,10 +1,10 @@
|
||||
fn main() {
|
||||
let crate_name = env!("CARGO_PKG_NAME");
|
||||
flowy_codegen::protobuf_file::gen(crate_name);
|
||||
|
||||
#[cfg(feature = "dart")]
|
||||
flowy_codegen::dart_event::gen(crate_name);
|
||||
|
||||
#[cfg(feature = "ts")]
|
||||
flowy_codegen::ts_event::gen(crate_name);
|
||||
// let crate_name = env!("CARGO_PKG_NAME");
|
||||
// flowy_codegen::protobuf_file::gen(crate_name);
|
||||
//
|
||||
// #[cfg(feature = "dart")]
|
||||
// flowy_codegen::dart_event::gen(crate_name);
|
||||
//
|
||||
// #[cfg(feature = "ts")]
|
||||
// flowy_codegen::ts_event::gen(crate_name);
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub enum NetworkTypePB {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
Wifi = 1,
|
||||
Cell = 2,
|
||||
Ethernet = 3,
|
||||
Bluetooth = 4,
|
||||
VPN = 5,
|
||||
}
|
||||
|
||||
impl NetworkTypePB {
|
||||
pub fn is_connect(&self) -> bool {
|
||||
match self {
|
||||
NetworkTypePB::Unknown | NetworkTypePB::Bluetooth => false,
|
||||
NetworkTypePB::Wifi | NetworkTypePB::Cell | NetworkTypePB::Ethernet | NetworkTypePB::VPN => {
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct NetworkStatePB {
|
||||
#[pb(index = 1)]
|
||||
pub ty: NetworkTypePB,
|
||||
}
|
||||
// use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
//
|
||||
// #[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Default)]
|
||||
// pub enum NetworkTypePB {
|
||||
// #[default]
|
||||
// Unknown = 0,
|
||||
// Wifi = 1,
|
||||
// Cell = 2,
|
||||
// Ethernet = 3,
|
||||
// Bluetooth = 4,
|
||||
// VPN = 5,
|
||||
// }
|
||||
//
|
||||
// impl NetworkTypePB {
|
||||
// pub fn is_connect(&self) -> bool {
|
||||
// match self {
|
||||
// NetworkTypePB::Unknown | NetworkTypePB::Bluetooth => false,
|
||||
// NetworkTypePB::Wifi | NetworkTypePB::Cell | NetworkTypePB::Ethernet | NetworkTypePB::VPN => {
|
||||
// true
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[derive(ProtoBuf, Debug, Default, Clone)]
|
||||
// pub struct NetworkStatePB {
|
||||
// #[pb(index = 1)]
|
||||
// pub ty: NetworkTypePB,
|
||||
// }
|
||||
|
@ -1,19 +1,5 @@
|
||||
use strum_macros::Display;
|
||||
|
||||
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||
use lib_dispatch::prelude::*;
|
||||
|
||||
use crate::handlers::*;
|
||||
|
||||
pub fn init() -> AFPlugin {
|
||||
AFPlugin::new()
|
||||
.name("Flowy-Network")
|
||||
.event(NetworkEvent::UpdateNetworkType, update_network_ty)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
||||
#[event_err = "FlowyError"]
|
||||
pub enum NetworkEvent {
|
||||
#[event(input = "NetworkStatePB")]
|
||||
UpdateNetworkType = 0,
|
||||
AFPlugin::new().name("Flowy-Network")
|
||||
}
|
||||
|
@ -1,8 +1,3 @@
|
||||
use flowy_error::FlowyError;
|
||||
use lib_dispatch::prelude::AFPluginData;
|
||||
|
||||
use crate::entities::NetworkStatePB;
|
||||
|
||||
pub async fn update_network_ty(_data: AFPluginData<NetworkStatePB>) -> Result<(), FlowyError> {
|
||||
Ok(())
|
||||
}
|
||||
// pub async fn update_network_ty(_data: AFPluginData<NetworkStatePB>) -> Result<(), FlowyError> {
|
||||
// Ok(())
|
||||
// }
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub mod entities;
|
||||
pub mod event_map;
|
||||
mod handlers;
|
||||
pub mod protobuf;
|
||||
|
@ -5,7 +5,6 @@ use flowy_error::{ErrorCode, FlowyError};
|
||||
pub const ENABLE_SUPABASE_SYNC: &str = "ENABLE_SUPABASE_SYNC";
|
||||
pub const SUPABASE_URL: &str = "SUPABASE_URL";
|
||||
pub const SUPABASE_ANON_KEY: &str = "SUPABASE_ANON_KEY";
|
||||
pub const SUPABASE_KEY: &str = "SUPABASE_KEY";
|
||||
pub const SUPABASE_JWT_SECRET: &str = "SUPABASE_JWT_SECRET";
|
||||
|
||||
pub const SUPABASE_DB: &str = "SUPABASE_DB";
|
||||
@ -13,44 +12,38 @@ pub const SUPABASE_DB_USER: &str = "SUPABASE_DB_USER";
|
||||
pub const SUPABASE_DB_PASSWORD: &str = "SUPABASE_DB_PASSWORD";
|
||||
pub const SUPABASE_DB_PORT: &str = "SUPABASE_DB_PORT";
|
||||
|
||||
/// The configuration for the postgres database. It supports deserializing from the json string that
|
||||
/// passed from the frontend application. [AppFlowyEnv::parser]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
pub struct SupabaseConfiguration {
|
||||
/// The url of the supabase server.
|
||||
pub url: String,
|
||||
|
||||
/// The key of the supabase server.
|
||||
pub key: String,
|
||||
pub anon_key: String,
|
||||
/// The secret used to sign the JWT tokens.
|
||||
pub jwt_secret: String,
|
||||
|
||||
/// Whether to enable the supabase sync.
|
||||
/// User can disable it by injecting the environment variable ENABLE_SUPABASE_SYNC=false
|
||||
pub enable_sync: bool,
|
||||
|
||||
pub postgres_config: PostgresConfiguration,
|
||||
}
|
||||
|
||||
impl SupabaseConfiguration {
|
||||
/// Load the configuration from the environment variables.
|
||||
/// SUPABASE_URL=https://<your-supabase-url>.supabase.co
|
||||
/// SUPABASE_KEY=<your-supabase-key>
|
||||
/// SUPABASE_JWT_SECRET=<your-supabase-jwt-secret>
|
||||
///
|
||||
pub fn from_env() -> Result<Self, FlowyError> {
|
||||
let postgres_config = PostgresConfiguration::from_env()?;
|
||||
Ok(Self {
|
||||
enable_sync: std::env::var(ENABLE_SUPABASE_SYNC)
|
||||
.map(|v| v == "true")
|
||||
.unwrap_or(false),
|
||||
url: std::env::var(SUPABASE_URL)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_URL"))?,
|
||||
key: std::env::var(SUPABASE_KEY)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_KEY"))?,
|
||||
anon_key: std::env::var(SUPABASE_ANON_KEY)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_ANON_KEY"))?,
|
||||
jwt_secret: std::env::var(SUPABASE_JWT_SECRET).map_err(|_| {
|
||||
FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_JWT_SECRET")
|
||||
})?,
|
||||
postgres_config,
|
||||
})
|
||||
}
|
||||
|
||||
/// Write the configuration to the environment variables.
|
||||
pub fn write_env(&self) {
|
||||
if self.enable_sync {
|
||||
std::env::set_var(ENABLE_SUPABASE_SYNC, "true");
|
||||
@ -58,45 +51,7 @@ impl SupabaseConfiguration {
|
||||
std::env::set_var(ENABLE_SUPABASE_SYNC, "false");
|
||||
}
|
||||
std::env::set_var(SUPABASE_URL, &self.url);
|
||||
std::env::set_var(SUPABASE_KEY, &self.key);
|
||||
std::env::set_var(SUPABASE_ANON_KEY, &self.anon_key);
|
||||
std::env::set_var(SUPABASE_JWT_SECRET, &self.jwt_secret);
|
||||
self.postgres_config.write_env();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct PostgresConfiguration {
|
||||
pub url: String,
|
||||
pub user_name: String,
|
||||
pub password: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl PostgresConfiguration {
|
||||
pub fn from_env() -> Result<Self, FlowyError> {
|
||||
let url = std::env::var(SUPABASE_DB)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_DB"))?;
|
||||
let user_name = std::env::var(SUPABASE_DB_USER)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_DB_USER"))?;
|
||||
let password = std::env::var(SUPABASE_DB_PASSWORD)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_DB_PASSWORD"))?;
|
||||
let port = std::env::var(SUPABASE_DB_PORT)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_DB_PORT"))?
|
||||
.parse::<u16>()
|
||||
.map_err(|_e| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing SUPABASE_DB_PORT"))?;
|
||||
|
||||
Ok(Self {
|
||||
url,
|
||||
user_name,
|
||||
password,
|
||||
port,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_env(&self) {
|
||||
std::env::set_var(SUPABASE_DB, &self.url);
|
||||
std::env::set_var(SUPABASE_DB_USER, &self.user_name);
|
||||
std::env::set_var(SUPABASE_DB_PASSWORD, &self.password);
|
||||
std::env::set_var(SUPABASE_DB_PORT, self.port.to_string());
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tracing = { version = "0.1" }
|
||||
futures = "0.3.26"
|
||||
futures-util = "0.3.26"
|
||||
reqwest = "0.11.14"
|
||||
hyper = "0.14"
|
||||
@ -14,40 +15,31 @@ config = { version = "0.10.1", default-features = false, features = ["yaml"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde-aux = "4.2.0"
|
||||
nanoid = "0.4.0"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1.26", features = ["sync"]}
|
||||
parking_lot = "0.12"
|
||||
lazy_static = "1.4.0"
|
||||
bytes = "1.0.1"
|
||||
bytes = { version = "1.0.1", features = ["serde"] }
|
||||
tokio-retry = "0.3"
|
||||
anyhow = "1.0"
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
chrono = { version = "0.4.22", default-features = false, features = ["clock"] }
|
||||
appflowy-integrate = { version = "0.1.0" }
|
||||
|
||||
postgrest = "1.0"
|
||||
tokio-postgres = { version = "0.7.8", optional = true, features = ["with-uuid-1","with-chrono-0_4"] }
|
||||
deadpool-postgres = "0.10.5"
|
||||
refinery= { version = "0.8.10", optional = true, features = ["tokio-postgres"] }
|
||||
async-stream = "0.3.4"
|
||||
futures = "0.3.26"
|
||||
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
flowy-user = { path = "../flowy-user" }
|
||||
flowy-folder2 = { path = "../flowy-folder2" }
|
||||
flowy-database2 = { path = "../flowy-database2" }
|
||||
flowy-document2 = { path = "../flowy-document2" }
|
||||
flowy-error = { path = "../flowy-error" }
|
||||
flowy-server-config = { path = "../flowy-server-config" }
|
||||
collab-folder = { version = "0.1.0" }
|
||||
collab = { version = "0.1.0" }
|
||||
collab-plugins = { version = "0.1.0" }
|
||||
collab-document = { version = "0.1.0" }
|
||||
hex = "0.4.3"
|
||||
postgrest = "1.0"
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
flowy-user-deps = { path = "../flowy-user-deps" }
|
||||
flowy-folder-deps = { path = "../flowy-folder-deps" }
|
||||
flowy-database-deps = { path = "../flowy-database-deps" }
|
||||
flowy-document-deps = { path = "../flowy-document-deps" }
|
||||
flowy-error = { path = "../flowy-error", features = ["impl_from_postgres", "impl_from_serde", "impl_from_reqwest"] }
|
||||
flowy-server-config = { path = "../flowy-server-config" }
|
||||
|
||||
[dev-dependencies]
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
dotenv = "0.15.0"
|
||||
yrs = "0.16.5"
|
||||
|
||||
[features]
|
||||
default = ["postgres_storage"]
|
||||
postgres_storage = ["tokio-postgres", "refinery", ]
|
||||
|
108
frontend/rust-lib/flowy-server/docs/README.md
Normal file
108
frontend/rust-lib/flowy-server/docs/README.md
Normal file
@ -0,0 +1,108 @@
|
||||
# AppFlowy Cloud Architecture
|
||||
|
||||
AppFlowy supports multiple cloud solutions. Users can choose their preferred cloud provider, such as Supabase, Firebase,
|
||||
AWS, or our own AppFlowyCloud (Self-hosted server).
|
||||
|
||||

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

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

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

|
||||
Here's a detailed description for each of these triggers:
|
||||
|
||||
1. `create_af_workspace_trigger`:
|
||||
|
||||
This trigger is designed to automate the process of workspace creation in the `af_workspace` table after a new user is inserted into the `af_user` table. When a new user is added, this trigger fires and inserts a new record into the `af_workspace` table, setting the `owner_uid` to the UID of the new user.
|
||||
|
||||
2. `manage_af_workspace_member_role_trigger`:
|
||||
|
||||
This trigger helps to manage the roles of workspace members. After an insert operation on the `af_workspace` table, this trigger automatically fires and creates a new record in the `af_workspace_member` table. The new record identifies the user as a member of the workspace with the role 'Owner'. This ensures that every new workspace has an owner.
|
||||
|
||||
3. `insert_into_af_collab_trigger`:
|
||||
|
||||
The purpose of this trigger is to ensure consistency between the `af_collab_update` and `af_collab` tables. When an insert operation is about to be performed on the `af_collab_update` table, this trigger fires before the insert operation. It checks if a corresponding collaboration exists in the `af_collab` table using the oid and uid. If a corresponding collaboration does not exist, the trigger creates one, using the oid, uid, and current timestamp. This way, every collab update operation corresponds to a valid collaboration.
|
||||
|
||||
4. `insert_into_af_collab_member_trigger`:
|
||||
|
||||
This trigger helps to manage the membership of users in collaborations. After a new collaboration is inserted into the `af_collab` table, this trigger fires. It checks if a corresponding collaboration member exists in the `af_collab_member` table. If a corresponding member does not exist, the trigger creates one, using the collaboration id and user id. This ensures that every collaboration has at least one member.
|
||||
|
||||
5. `af_collab_snapshot_update_edit_count_trigger`:
|
||||
|
||||
This trigger is designed to keep track of the number of edits on each collaboration snapshot in the `af_collab_snapshot` table. When an update operation is performed on the `af_collab_snapshot` table, this trigger fires. It increments the `edit_count` of the corresponding record in the `af_collab_snapshot` table by one. This ensures that the application can keep track of how many times each collaboration snapshot has been edited.
|
||||
|
||||
|
||||
### Supabase configuration
|
||||
|
||||
#### Test
|
||||
In order to run the test, you need to set up the .env.test file.
|
||||
```dotenv
|
||||
# Supabase configuration
|
||||
SUPABASE_URL="your-supabase-url"
|
||||
SUPABASE_ANON_KEY="your-supabase-anonymous-key"
|
||||
SUPABASE_KEY="your-supabase-key"
|
||||
SUPABASE_JWT_SECRET="your-supabase-jwt-secret"
|
||||
|
||||
# Supabase Database configuration
|
||||
SUPABASE_DB="your-supabase-db-url"
|
||||
SUPABASE_DB_USER="your-db-username"
|
||||
SUPABASE_DB_PORT="your-db-port"
|
||||
SUPABASE_DB_PASSWORD="your-db-password"
|
||||
```
|
||||
|
||||
1. `SUPABASE_URL`: This is the URL of your Supabase server instance. Your application will use this URL to interact with the Supabase service.
|
||||
|
||||
2. `SUPABASE_ANON_KEY`: This is the anonymous API key from Supabase, used for operations that don't require user authentication. Operations performed with this key are done as the anonymous role in the database.
|
||||
|
||||
3. `SUPABASE_KEY`: This is the API key with higher privileges from Supabase. It is generally used for server-side operations that require more permissions than an anonymous user.
|
||||
|
||||
4. `SUPABASE_JWT_SECRET`: This is the secret used to verify JWT tokens generated by Supabase. JWT or JSON Web Token is a standard method for securely transferring data between parties as a JSON object.
|
||||
|
||||
5. `SUPABASE_DB`: This is the URL for the database your Supabase server instance is using.
|
||||
|
||||
6. `SUPABASE_DB_USER`: This is the username used to authenticate with the Supabase database, in this case, it's 'postgres', which is a common default for PostgreSQL.
|
||||
|
||||
7. `SUPABASE_DB_PORT`: This is the port number where your Supabase database service is accessible. The default PostgreSQL port is 5432, and you are using this default port.
|
||||
|
||||
8. `SUPABASE_DB_PASSWORD`: This is the password used to authenticate the `SUPABASE_DB_USER` with the Supabase database.
|
||||
|
||||
For example, if you want to run the supabase tests located in flowy-test crate. You need to put the `.env.test` file under
|
||||
the flowy-test folder.
|
BIN
frontend/rust-lib/flowy-server/docs/architecture-Application.png
Normal file
BIN
frontend/rust-lib/flowy-server/docs/architecture-Application.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
78
frontend/rust-lib/flowy-server/docs/architecture.plantuml
Normal file
78
frontend/rust-lib/flowy-server/docs/architecture.plantuml
Normal file
@ -0,0 +1,78 @@
|
||||
@startuml
|
||||
title "Application"
|
||||
left to right direction
|
||||
package "AppFlowy Application" {
|
||||
[User]
|
||||
}
|
||||
|
||||
cloud "Supabase Server" {
|
||||
[RESTful Component]
|
||||
[Realtime Component]
|
||||
[Postgres DB]
|
||||
}
|
||||
|
||||
database "LocalServer" {
|
||||
[Local Server Component]
|
||||
}
|
||||
|
||||
|
||||
cloud "AppFlowy Cloud Server" {
|
||||
[RESTful Component] as [AppFlowy RESTful Component]
|
||||
[Realtime Component] as [AppFlowy Realtime Component]
|
||||
[Postgres DB] as [AppFlowy Postgres DB]
|
||||
}
|
||||
|
||||
User --> [AppFlowy Application]
|
||||
[AppFlowy Application] --> [Local Server Component] : Connect
|
||||
|
||||
[AppFlowy Application] --> [RESTful Component] : RESTful API Communication
|
||||
[AppFlowy Application] <..> [Realtime Component] : WebSocket Communication
|
||||
|
||||
[AppFlowy Application] --> [AppFlowy RESTful Component] : RESTful API Communication
|
||||
[AppFlowy Application] <..> [AppFlowy Realtime Component] : WebSocket Communication
|
||||
|
||||
@enduml
|
||||
|
||||
|
||||
@startuml
|
||||
left to right direction
|
||||
|
||||
interface AppFlowyServer {
|
||||
+ enable_sync(_enable: bool)
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class SupabaseServer {
|
||||
+ enable_sync(_enable: bool)
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class SelfHostServer {
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
class LocalServer {
|
||||
+ user_service(): Arc<dyn UserService>
|
||||
+ folder_service(): Arc<dyn FolderCloudService>
|
||||
+ database_service(): Arc<dyn DatabaseCloudService>
|
||||
+ document_service(): Arc<dyn DocumentCloudService>
|
||||
+ collab_storage(): Option<Arc<dyn RemoteCollabStorage>>
|
||||
}
|
||||
|
||||
SupabaseServer -u-|> AppFlowyServer
|
||||
SelfHostServer -u-|> AppFlowyServer
|
||||
LocalServer -u-|> AppFlowyServer
|
||||
|
||||
@enduml
|
BIN
frontend/rust-lib/flowy-server/docs/architecture.png
Normal file
BIN
frontend/rust-lib/flowy-server/docs/architecture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
203
frontend/rust-lib/flowy-server/docs/schema.plantuml
Normal file
203
frontend/rust-lib/flowy-server/docs/schema.plantuml
Normal file
@ -0,0 +1,203 @@
|
||||
@startuml
|
||||
left to right direction
|
||||
|
||||
entity "af_roles" as roles {
|
||||
id : SERIAL (PK)
|
||||
name : TEXT
|
||||
}
|
||||
|
||||
entity "af_permissions" as permissions {
|
||||
id : SERIAL (PK)
|
||||
name : VARCHAR(255)
|
||||
access_level : INTEGER
|
||||
description : TEXT
|
||||
}
|
||||
|
||||
entity "af_role_permissions" as role_permissions {
|
||||
role_id : INT (FK af_roles.id)
|
||||
permission_id : INT (FK af_permissions.id)
|
||||
--
|
||||
(role_id, permission_id) : PK
|
||||
}
|
||||
|
||||
entity "af_user" as user {
|
||||
uuid : UUID (PK)
|
||||
email : TEXT
|
||||
uid : BIGSERIAL
|
||||
name : TEXT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
entity "af_workspace" as workspace {
|
||||
workspace_id : UUID (PK)
|
||||
database_storage_id : UUID
|
||||
owner_uid : BIGINT (FK af_user.uid)
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
workspace_type : INTEGER
|
||||
workspace_name : TEXT
|
||||
}
|
||||
|
||||
entity "af_workspace_member" as workspace_member {
|
||||
uid : BIGINT
|
||||
role_id : INT (FK af_roles.id)
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
updated_at : TIMESTAMP WITH TIME ZONE
|
||||
--
|
||||
(uid, workspace_id) : PK
|
||||
}
|
||||
|
||||
entity "af_collab" as collab {
|
||||
oid : TEXT (PK)
|
||||
owner_uid : BIGINT
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
access_level : INTEGER
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
entity "af_collab_update" as collab_update {
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
key : BIGSERIAL
|
||||
value : BYTEA
|
||||
value_size : INTEGER
|
||||
partition_key : INTEGER
|
||||
uid : BIGINT
|
||||
md5 : TEXT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
--
|
||||
(oid, key, partition_key) : PK
|
||||
}
|
||||
|
||||
|
||||
entity "af_collab_update_document" as af_collab_update_document {
|
||||
Inherits af_collab_update (partition_key = 0)
|
||||
}
|
||||
|
||||
entity "af_collab_update_database" as af_collab_update_database {
|
||||
Inherits af_collab_update (partition_key = 1)
|
||||
}
|
||||
|
||||
entity "af_collab_update_w_database" as af_collab_update_w_database {
|
||||
Inherits af_collab_update (partition_key = 2)
|
||||
}
|
||||
|
||||
entity "af_collab_update_folder" as af_collab_update_folder {
|
||||
Inherits af_collab_update (partition_key = 3)
|
||||
}
|
||||
|
||||
af_collab_update_document -u-|> collab_update
|
||||
af_collab_update_database -u-|> collab_update
|
||||
af_collab_update_w_database -u-|> collab_update
|
||||
af_collab_update_folder -u-|> collab_update
|
||||
|
||||
entity "af_database_row_update" as database_row_update {
|
||||
oid : TEXT
|
||||
key : BIGSERIAL
|
||||
value : BYTEA
|
||||
value_size : INTEGER
|
||||
partition_key : INTEGER
|
||||
uid : BIGINT
|
||||
md5 : TEXT
|
||||
workspace_id : UUID (FK af_workspace.workspace_id)
|
||||
--
|
||||
(oid, key) : PK
|
||||
}
|
||||
|
||||
entity "af_collab_member" as collab_member {
|
||||
uid : BIGINT (FK af_user.uid)
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
role_id : INTEGER (FK af_roles.id)
|
||||
--
|
||||
(uid, oid) : PK
|
||||
}
|
||||
|
||||
entity "af_collab_statistics" as collab_statistics {
|
||||
oid : TEXT (PK)
|
||||
edit_count : BIGINT
|
||||
}
|
||||
|
||||
entity "af_collab_snapshot" as collab_snapshot {
|
||||
sid : BIGSERIAL (PK)
|
||||
oid : TEXT (FK af_collab.oid)
|
||||
name : TEXT
|
||||
blob : BYTEA
|
||||
blob_size : INTEGER
|
||||
edit_count : BIGINT
|
||||
created_at : TIMESTAMP WITH TIME ZONE
|
||||
}
|
||||
|
||||
|
||||
roles <-- role_permissions : FK
|
||||
permissions <-u- role_permissions : FK
|
||||
user <-- collab : FK
|
||||
user <-- workspace : FK
|
||||
user <-- collab_member : FK
|
||||
roles <-- workspace_member : FK
|
||||
workspace <-- workspace_member : FK
|
||||
workspace <-- collab : FK
|
||||
workspace <-- database_row_update : FK
|
||||
collab <-- collab_update : FK
|
||||
collab <-- collab_snapshot: FK
|
||||
collab <-u- collab_member : FK
|
||||
collab <-- collab_statistics : PK
|
||||
roles <-- collab_member : FK
|
||||
|
||||
|
||||
@enduml
|
||||
|
||||
@startuml
|
||||
title Triggers in Database Schema
|
||||
|
||||
participant "af_user" as A
|
||||
participant "af_workspace" as B
|
||||
participant "af_workspace_member" as C
|
||||
participant "af_collab" as D
|
||||
participant "af_collab_update" as E
|
||||
participant "af_collab_member" as F
|
||||
participant "af_collab_statistics" as G
|
||||
participant "af_collab_snapshot" as H
|
||||
|
||||
A -> B: create_af_workspace_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_user. It automatically creates a workspace
|
||||
with the uid of the new user as the owner_uid.
|
||||
end note
|
||||
|
||||
B -> C: manage_af_workspace_member_role_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_workspace. It automatically
|
||||
creates a workspace member in the af_workspace_member table with the
|
||||
role 'Owner'.
|
||||
end note
|
||||
|
||||
E -> D: insert_into_af_collab_trigger
|
||||
note right
|
||||
This trigger fires before an insert on af_collab_update.
|
||||
It checks if a corresponding collab exists in the af_collab table.
|
||||
If not, it creates one with the oid, uid, and current timestamp.
|
||||
end note
|
||||
|
||||
D -> F: insert_into_af_collab_member_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab.
|
||||
It automatically adds the collab's owner to the af_collab_member
|
||||
table with the role 'Owner'.
|
||||
end note
|
||||
|
||||
E -> G: af_collab_update_edit_count_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab_update.
|
||||
It increments the edit_count of the corresponding collab in
|
||||
the af_collab_statistics table.
|
||||
end note
|
||||
|
||||
H -> G: af_collab_snapshot_update_edit_count_trigger
|
||||
note right
|
||||
This trigger fires after an insert on af_collab_snapshot.
|
||||
It sets the edit_count of the new snapshot to the current
|
||||
edit_count of the collab in the af_collab_statistics table.
|
||||
end note
|
||||
|
||||
@enduml
|
||||
|
BIN
frontend/rust-lib/flowy-server/docs/schema.png
Normal file
BIN
frontend/rust-lib/flowy-server/docs/schema.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
@ -1,11 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RemoteCollabStorage;
|
||||
use collab_plugins::cloud_storage::RemoteCollabStorage;
|
||||
|
||||
use flowy_database2::deps::DatabaseCloudService;
|
||||
use flowy_document2::deps::DocumentCloudService;
|
||||
use flowy_folder2::deps::FolderCloudService;
|
||||
use flowy_user::event_map::UserAuthService;
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_document_deps::cloud::DocumentCloudService;
|
||||
use flowy_folder_deps::cloud::FolderCloudService;
|
||||
use flowy_user_deps::cloud::UserService;
|
||||
|
||||
pub mod local_server;
|
||||
mod request;
|
||||
@ -14,23 +14,9 @@ pub mod self_host;
|
||||
pub mod supabase;
|
||||
pub mod util;
|
||||
|
||||
/// In order to run this the supabase test, you need to create a .env file in the root directory of this project
|
||||
/// and add the following environment variables:
|
||||
/// - SUPABASE_URL
|
||||
/// - SUPABASE_ANON_KEY
|
||||
/// - SUPABASE_KEY
|
||||
/// - SUPABASE_JWT_SECRET
|
||||
///
|
||||
/// the .env file should look like this:
|
||||
/// SUPABASE_URL=https://<your-supabase-url>.supabase.co
|
||||
/// SUPABASE_ANON_KEY=<your-supabase-anon-key>
|
||||
/// SUPABASE_KEY=<your-supabase-key>
|
||||
/// SUPABASE_JWT_SECRET=<your-supabase-jwt-secret>
|
||||
///
|
||||
|
||||
pub trait AppFlowyServer: Send + Sync + 'static {
|
||||
fn enable_sync(&self, _enable: bool) {}
|
||||
fn user_service(&self) -> Arc<dyn UserAuthService>;
|
||||
fn user_service(&self) -> Arc<dyn UserService>;
|
||||
fn folder_service(&self) -> Arc<dyn FolderCloudService>;
|
||||
fn database_service(&self) -> Arc<dyn DatabaseCloudService>;
|
||||
fn document_service(&self) -> Arc<dyn DocumentCloudService>;
|
||||
|
@ -1,27 +1,35 @@
|
||||
use flowy_database2::deps::{
|
||||
use anyhow::Error;
|
||||
use collab_plugins::cloud_storage::CollabType;
|
||||
|
||||
use flowy_database_deps::cloud::{
|
||||
CollabObjectUpdate, CollabObjectUpdateByOid, DatabaseCloudService, DatabaseSnapshot,
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub(crate) struct LocalServerDatabaseCloudServiceImpl();
|
||||
|
||||
impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
|
||||
fn get_collab_update(&self, _object_id: &str) -> FutureResult<CollabObjectUpdate, FlowyError> {
|
||||
fn get_collab_update(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
_object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdate, Error> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn batch_get_collab_updates(
|
||||
&self,
|
||||
_object_ids: Vec<String>,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, FlowyError> {
|
||||
_object_ty: CollabType,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, Error> {
|
||||
FutureResult::new(async move { Ok(CollabObjectUpdateByOid::default()) })
|
||||
}
|
||||
|
||||
fn get_collab_latest_snapshot(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,23 @@
|
||||
use flowy_document2::deps::{DocumentCloudService, DocumentData, DocumentSnapshot};
|
||||
use flowy_error::FlowyError;
|
||||
use anyhow::Error;
|
||||
use flowy_document_deps::cloud::*;
|
||||
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub(crate) struct LocalServerDocumentCloudServiceImpl();
|
||||
|
||||
impl DocumentCloudService for LocalServerDocumentCloudServiceImpl {
|
||||
fn get_document_updates(&self, _document_id: &str) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
fn get_document_updates(&self, _document_id: &str) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn get_document_latest_snapshot(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
) -> FutureResult<Option<DocumentSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<DocumentSnapshot>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
|
||||
fn get_document_data(
|
||||
&self,
|
||||
_document_id: &str,
|
||||
) -> FutureResult<Option<DocumentData>, FlowyError> {
|
||||
fn get_document_data(&self, _document_id: &str) -> FutureResult<Option<DocumentData>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
use anyhow::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder2::deps::{FolderCloudService, FolderData, FolderSnapshot, Workspace};
|
||||
use flowy_folder2::gen_workspace_id;
|
||||
use flowy_folder_deps::cloud::{
|
||||
gen_workspace_id, FolderCloudService, FolderData, FolderSnapshot, Workspace,
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
@ -13,11 +14,11 @@ pub(crate) struct LocalServerFolderCloudServiceImpl {
|
||||
}
|
||||
|
||||
impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
||||
fn create_workspace(&self, _uid: i64, name: &str) -> FutureResult<Workspace, FlowyError> {
|
||||
fn create_workspace(&self, _uid: i64, name: &str) -> FutureResult<Workspace, Error> {
|
||||
let name = name.to_string();
|
||||
FutureResult::new(async move {
|
||||
Ok(Workspace {
|
||||
id: gen_workspace_id(),
|
||||
id: gen_workspace_id().to_string(),
|
||||
name: name.to_string(),
|
||||
child_views: Default::default(),
|
||||
created_at: timestamp(),
|
||||
@ -25,22 +26,18 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_folder_data(&self, _workspace_id: &str) -> FutureResult<Option<FolderData>, FlowyError> {
|
||||
fn get_folder_data(&self, _workspace_id: &str) -> FutureResult<Option<FolderData>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
|
||||
fn get_folder_latest_snapshot(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
) -> FutureResult<Option<FolderSnapshot>, FlowyError> {
|
||||
) -> FutureResult<Option<FolderSnapshot>, Error> {
|
||||
FutureResult::new(async move { Ok(None) })
|
||||
}
|
||||
|
||||
fn get_folder_updates(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
uid: i64,
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
fn get_folder_updates(&self, workspace_id: &str, uid: i64) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
let weak_db = Arc::downgrade(&self.db);
|
||||
let workspace_id = workspace_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
|
@ -1,13 +1,11 @@
|
||||
use anyhow::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_user::entities::{
|
||||
SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile,
|
||||
};
|
||||
use flowy_user::event_map::{UserAuthService, UserCredentials};
|
||||
use flowy_user_deps::cloud::UserService;
|
||||
use flowy_user_deps::entities::*;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
@ -19,19 +17,22 @@ lazy_static! {
|
||||
}
|
||||
|
||||
pub(crate) struct LocalServerUserAuthServiceImpl {
|
||||
#[allow(dead_code)]
|
||||
pub db: Arc<dyn LocalServerDB>,
|
||||
}
|
||||
|
||||
impl UserAuthService for LocalServerUserAuthServiceImpl {
|
||||
fn sign_up(&self, params: BoxAny) -> FutureResult<SignUpResponse, FlowyError> {
|
||||
impl UserService for LocalServerUserAuthServiceImpl {
|
||||
fn sign_up(&self, params: BoxAny) -> FutureResult<SignUpResponse, Error> {
|
||||
FutureResult::new(async move {
|
||||
let params = params.unbox_or_error::<SignUpParams>()?;
|
||||
let uid = ID_GEN.lock().next_id();
|
||||
let workspace_id = uuid::Uuid::new_v4().to_string();
|
||||
let user_workspace = UserWorkspace::new(&workspace_id, uid);
|
||||
Ok(SignUpResponse {
|
||||
user_id: uid,
|
||||
name: params.name,
|
||||
workspace_id,
|
||||
latest_workspace: user_workspace.clone(),
|
||||
user_workspaces: vec![user_workspace],
|
||||
is_new: true,
|
||||
email: Some(params.email),
|
||||
token: None,
|
||||
@ -39,8 +40,8 @@ impl UserAuthService for LocalServerUserAuthServiceImpl {
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_in(&self, params: BoxAny) -> FutureResult<SignInResponse, FlowyError> {
|
||||
let weak_db = Arc::downgrade(&self.db);
|
||||
fn sign_in(&self, params: BoxAny) -> FutureResult<SignInResponse, Error> {
|
||||
let db = self.db.clone();
|
||||
FutureResult::new(async move {
|
||||
let params: SignInParams = params.unbox_or_error::<SignInParams>()?;
|
||||
let uid = match params.uid {
|
||||
@ -48,24 +49,21 @@ impl UserAuthService for LocalServerUserAuthServiceImpl {
|
||||
Some(uid) => uid,
|
||||
};
|
||||
|
||||
// Get the workspace id from the database if it exists, otherwise generate a new one.
|
||||
let workspace_id = weak_db
|
||||
.upgrade()
|
||||
.and_then(|db| db.get_user_profile(uid).ok())
|
||||
.and_then(|user_profile| user_profile.map(|user_profile| user_profile.workspace_id))
|
||||
.unwrap_or(uuid::Uuid::new_v4().to_string());
|
||||
|
||||
let user_workspace = db
|
||||
.get_user_workspace(uid)?
|
||||
.unwrap_or_else(make_user_workspace);
|
||||
Ok(SignInResponse {
|
||||
user_id: uid,
|
||||
name: params.name,
|
||||
workspace_id,
|
||||
latest_workspace: user_workspace.clone(),
|
||||
user_workspaces: vec![user_workspace],
|
||||
email: Some(params.email),
|
||||
token: None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), FlowyError> {
|
||||
fn sign_out(&self, _token: Option<String>) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
@ -73,18 +71,47 @@ impl UserAuthService for LocalServerUserAuthServiceImpl {
|
||||
&self,
|
||||
_credential: UserCredentials,
|
||||
_params: UpdateUserProfileParams,
|
||||
) -> FutureResult<(), FlowyError> {
|
||||
) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn get_user_profile(
|
||||
&self,
|
||||
_credential: UserCredentials,
|
||||
) -> FutureResult<Option<UserProfile>, FlowyError> {
|
||||
) -> FutureResult<Option<UserProfile>, Error> {
|
||||
FutureResult::new(async { Ok(None) })
|
||||
}
|
||||
|
||||
fn check_user(&self, _credential: UserCredentials) -> FutureResult<(), FlowyError> {
|
||||
fn get_user_workspaces(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
FutureResult::new(async { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn check_user(&self, _credential: UserCredentials) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn add_workspace_member(
|
||||
&self,
|
||||
_user_email: String,
|
||||
_workspace_id: String,
|
||||
) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn remove_workspace_member(
|
||||
&self,
|
||||
_user_email: String,
|
||||
_workspace_id: String,
|
||||
) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
}
|
||||
|
||||
fn make_user_workspace() -> UserWorkspace {
|
||||
UserWorkspace {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
name: "My Workspace".to_string(),
|
||||
created_at: Default::default(),
|
||||
database_storage_id: uuid::Uuid::new_v4().to_string(),
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RemoteCollabStorage;
|
||||
use collab_document::YrsDocAction;
|
||||
use collab_plugins::cloud_storage::RemoteCollabStorage;
|
||||
use parking_lot::RwLock;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use flowy_database2::deps::DatabaseCloudService;
|
||||
use flowy_document2::deps::DocumentCloudService;
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_document_deps::cloud::DocumentCloudService;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder2::deps::FolderCloudService;
|
||||
use flowy_user::entities::UserProfile;
|
||||
use flowy_user::event_map::UserAuthService;
|
||||
use flowy_user::services::database::{get_user_profile, open_collab_db, open_user_db};
|
||||
use flowy_folder_deps::cloud::FolderCloudService;
|
||||
// use flowy_user::services::database::{
|
||||
// get_user_profile, get_user_workspace, open_collab_db, open_user_db,
|
||||
// };
|
||||
use flowy_user_deps::cloud::UserService;
|
||||
use flowy_user_deps::entities::*;
|
||||
|
||||
use crate::local_server::impls::{
|
||||
LocalServerDatabaseCloudServiceImpl, LocalServerDocumentCloudServiceImpl,
|
||||
@ -21,18 +22,19 @@ use crate::AppFlowyServer;
|
||||
|
||||
pub trait LocalServerDB: Send + Sync + 'static {
|
||||
fn get_user_profile(&self, uid: i64) -> Result<Option<UserProfile>, FlowyError>;
|
||||
fn get_user_workspace(&self, uid: i64) -> Result<Option<UserWorkspace>, FlowyError>;
|
||||
fn get_collab_updates(&self, uid: i64, object_id: &str) -> Result<Vec<Vec<u8>>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct LocalServer {
|
||||
storage_path: String,
|
||||
local_db: Arc<dyn LocalServerDB>,
|
||||
stop_tx: RwLock<Option<mpsc::Sender<()>>>,
|
||||
}
|
||||
|
||||
impl LocalServer {
|
||||
pub fn new(storage_path: &str) -> Self {
|
||||
pub fn new(local_db: Arc<dyn LocalServerDB>) -> Self {
|
||||
Self {
|
||||
storage_path: storage_path.to_string(),
|
||||
local_db,
|
||||
stop_tx: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -46,18 +48,16 @@ impl LocalServer {
|
||||
}
|
||||
|
||||
impl AppFlowyServer for LocalServer {
|
||||
fn user_service(&self) -> Arc<dyn UserAuthService> {
|
||||
let db = LocalServerDBImpl {
|
||||
storage_path: self.storage_path.clone(),
|
||||
};
|
||||
Arc::new(LocalServerUserAuthServiceImpl { db: Arc::new(db) })
|
||||
fn user_service(&self) -> Arc<dyn UserService> {
|
||||
Arc::new(LocalServerUserAuthServiceImpl {
|
||||
db: self.local_db.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
||||
let db = LocalServerDBImpl {
|
||||
storage_path: self.storage_path.clone(),
|
||||
};
|
||||
Arc::new(LocalServerFolderCloudServiceImpl { db: Arc::new(db) })
|
||||
Arc::new(LocalServerFolderCloudServiceImpl {
|
||||
db: self.local_db.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
||||
@ -72,25 +72,3 @@ impl AppFlowyServer for LocalServer {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalServerDBImpl {
|
||||
storage_path: String,
|
||||
}
|
||||
|
||||
impl LocalServerDB for LocalServerDBImpl {
|
||||
fn get_user_profile(&self, uid: i64) -> Result<Option<UserProfile>, FlowyError> {
|
||||
let sqlite_db = open_user_db(&self.storage_path, uid)?;
|
||||
let user_profile = get_user_profile(&sqlite_db, uid).ok();
|
||||
Ok(user_profile)
|
||||
}
|
||||
|
||||
fn get_collab_updates(&self, uid: i64, object_id: &str) -> Result<Vec<Vec<u8>>, FlowyError> {
|
||||
let collab_db = open_collab_db(&self.storage_path, uid)?;
|
||||
let read_txn = collab_db.read_txn();
|
||||
let updates = read_txn
|
||||
.get_all_updates(uid, object_id)
|
||||
.map_err(|e| FlowyError::internal().context(format!("Failed to open collab db: {:?}", e)))?;
|
||||
|
||||
Ok(updates)
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user