mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: af cloud sync auth (#3873)
* feat: open workspace * chore: update env docs * fix: invalid user callback * fix: token invalid * chore: update * chore: update * chore: update * chore: fix test * chore: fix tauri build
This commit is contained in:
parent
b35d6131d4
commit
1025b6d553
@ -1,23 +1,33 @@
|
||||
# Initial Setup
|
||||
# 1. Copy the dev.env file to .env:
|
||||
# cp dev.env .env
|
||||
# 2. Alternatively, you can generate the .env file using the "Generate Env File" task in VSCode.
|
||||
|
||||
# Configuring Cloud Type
|
||||
# This configuration file is used to specify the cloud type and the necessary configurations for each cloud type. The available options are:
|
||||
# 1. Copy the dev.env file to .env:
|
||||
# cp dev.env .env
|
||||
# Update the environment parameters as needed.
|
||||
|
||||
# 2. Generate the env.dart from this .env file:
|
||||
# You can use the "Generate Env File" task in VSCode.
|
||||
# Alternatively, execute the following commands:
|
||||
# cd appflowy_flutter
|
||||
# dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
|
||||
# Cloud Type Configuration
|
||||
# Use this configuration file to specify the cloud type and its associated settings. The available cloud types are:
|
||||
# Local: 0
|
||||
# Supabase: 1
|
||||
# AppFlowy Cloud: 2
|
||||
|
||||
# By default, it's set to Local.
|
||||
CLOUD_TYPE=0
|
||||
|
||||
# Supabase Configuration
|
||||
# If you're using Supabase (CLOUD_TYPE=1), you need to provide the following configurations:
|
||||
# If using Supabase (CLOUD_TYPE=1), provide the following details:
|
||||
SUPABASE_URL=replace-with-your-supabase-url
|
||||
SUPABASE_ANON_KEY=replace-with-your-supabase-key
|
||||
|
||||
# AppFlowy Cloud Configuration
|
||||
# If you're using AppFlowy Cloud (CLOUD_TYPE=2), you need to provide the following configurations:
|
||||
# If using AppFlowy Cloud (CLOUD_TYPE=2), provide the following details:
|
||||
APPFLOWY_CLOUD_BASE_URL=replace-with-your-appflowy-cloud-url
|
||||
APPFLOWY_CLOUD_WS_BASE_URL=replace-with-your-appflowy-cloud-ws-url
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=replace-with-your-appflowy-cloud-gotrue-url
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=replace-with-your-appflowy-cloud-gotrue-url
|
||||
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
|
||||
// Run `dart run build_runner build` to generate the json serialization If the
|
||||
// file `env_serde.g.dart` is existed, delete it first.
|
||||
//
|
||||
// the file `env_serde.g.dart` will be generated in the same directory.
|
||||
part 'env_serde.g.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
part 'backend_env.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AppFlowyEnv {
|
@ -1,8 +1,9 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/env/backend_env.dart';
|
||||
import 'package:appflowy/env/env.dart';
|
||||
import 'package:appflowy_backend/appflowy_backend.dart';
|
||||
import 'package:appflowy_backend/env_serde.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
@ -23,8 +24,10 @@ class InitRustSDKTask extends LaunchTask {
|
||||
Future<void> initialize(LaunchContext context) async {
|
||||
final dir = directory ?? await appFlowyApplicationDataDirectory();
|
||||
|
||||
// Pass the environment variables to the Rust SDK
|
||||
final env = getAppFlowyEnv();
|
||||
context.getIt<FlowySDK>().setEnv(env);
|
||||
context.getIt<FlowySDK>().setEnv(jsonEncode(env.toJson()));
|
||||
|
||||
await context.getIt<FlowySDK>().init(dir);
|
||||
}
|
||||
|
||||
|
@ -100,14 +100,9 @@ class UserBackendService {
|
||||
return Future.value(left([]));
|
||||
}
|
||||
|
||||
Future<Either<WorkspacePB, FlowyError>> openWorkspace(String workspaceId) {
|
||||
final request = WorkspaceIdPB.create()..value = workspaceId;
|
||||
return FolderEventOpenWorkspace(request).send().then((result) {
|
||||
return result.fold(
|
||||
(workspace) => left(workspace),
|
||||
(error) => right(error),
|
||||
);
|
||||
});
|
||||
Future<Either<Unit, FlowyError>> openWorkspace(String workspaceId) {
|
||||
final payload = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
|
||||
return UserEventOpenWorkspace(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<WorkspacePB, FlowyError>> getCurrentWorkspace() {
|
||||
|
@ -101,6 +101,5 @@ Widget _renderCreateButton(BuildContext context) {
|
||||
|
||||
// same method as in mobile
|
||||
void _popToWorkspace(BuildContext context, WorkspacePB workspace) {
|
||||
context.read<WorkspaceBloc>().add(WorkspaceEvent.openWorkspace(workspace));
|
||||
context.pop(workspace.id);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
// TODO(yijing): needs refactor when multiple workspaces are supported
|
||||
@ -139,6 +138,5 @@ class _MobileWorkspaceStartScreenState
|
||||
|
||||
// same method as in desktop
|
||||
void _popToWorkspace(BuildContext context, WorkspacePB workspace) {
|
||||
context.read<WorkspaceBloc>().add(WorkspaceEvent.openWorkspace(workspace));
|
||||
context.pop(workspace.id);
|
||||
}
|
||||
|
@ -19,9 +19,6 @@ class WorkspaceBloc extends Bloc<WorkspaceEvent, WorkspaceState> {
|
||||
initial: (e) async {
|
||||
await _fetchWorkspaces(emit);
|
||||
},
|
||||
openWorkspace: (e) async {
|
||||
await _openWorkspace(e.workspace, emit);
|
||||
},
|
||||
createWorkspace: (e) async {
|
||||
await _createWorkspace(e.name, e.desc, emit);
|
||||
},
|
||||
@ -57,22 +54,6 @@ class WorkspaceBloc extends Bloc<WorkspaceEvent, WorkspaceState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openWorkspace(
|
||||
WorkspacePB workspace,
|
||||
Emitter<WorkspaceState> emit,
|
||||
) async {
|
||||
final result = await userService.openWorkspace(workspace.id);
|
||||
emit(
|
||||
result.fold(
|
||||
(workspaces) => state.copyWith(successOrFailure: left(unit)),
|
||||
(error) {
|
||||
Log.error(error);
|
||||
return state.copyWith(successOrFailure: right(error));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _createWorkspace(
|
||||
String name,
|
||||
String desc,
|
||||
@ -98,8 +79,6 @@ class WorkspaceEvent with _$WorkspaceEvent {
|
||||
const factory WorkspaceEvent.initial() = Initial;
|
||||
const factory WorkspaceEvent.createWorkspace(String name, String desc) =
|
||||
CreateWorkspace;
|
||||
const factory WorkspaceEvent.openWorkspace(WorkspacePB workspace) =
|
||||
OpenWorkspace;
|
||||
const factory WorkspaceEvent.workspacesReveived(
|
||||
Either<List<WorkspacePB>, FlowyError> workspacesOrFail,
|
||||
) = WorkspacesReceived;
|
||||
|
@ -1,11 +1,9 @@
|
||||
export 'package:async/async.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:async';
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:ffi';
|
||||
import 'env_serde.dart';
|
||||
import 'ffi.dart' as ffi;
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
@ -37,8 +35,7 @@ class FlowySDK {
|
||||
ffi.init_sdk(sdkDir.path.toNativeUtf8());
|
||||
}
|
||||
|
||||
void setEnv(AppFlowyEnv env) {
|
||||
final jsonStr = jsonEncode(env.toJson());
|
||||
ffi.set_env(jsonStr.toNativeUtf8());
|
||||
void setEnv(String envStr) {
|
||||
ffi.set_env(envStr.toNativeUtf8());
|
||||
}
|
||||
}
|
||||
|
76
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
76
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -135,6 +135,21 @@ version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "appflowy_tauri"
|
||||
version = "0.0.0"
|
||||
@ -445,7 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"hashbrown 0.12.3",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -753,9 +768,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
@ -845,7 +861,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -864,7 +880,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -894,7 +910,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -906,7 +922,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -926,7 +942,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -940,7 +956,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -982,7 +998,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
@ -1003,7 +1019,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1030,7 +1046,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1429,9 +1445,10 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"chrono",
|
||||
"collab-entity",
|
||||
"serde",
|
||||
@ -2064,7 +2081,7 @@ dependencies = [
|
||||
"nanoid",
|
||||
"parking_lot",
|
||||
"protobuf",
|
||||
"scraper 0.18.0",
|
||||
"scraper 0.18.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum_macros 0.21.1",
|
||||
@ -2778,7 +2795,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2794,9 +2811,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"jsonwebtoken",
|
||||
"lazy_static",
|
||||
"reqwest",
|
||||
@ -3229,7 +3247,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -3479,7 +3497,6 @@ dependencies = [
|
||||
"tracing-appender",
|
||||
"tracing-bunyan-formatter",
|
||||
"tracing-core",
|
||||
"tracing-log 0.2.0",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@ -4904,8 +4921,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "realtime-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
@ -5358,9 +5376,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "scraper"
|
||||
version = "0.18.0"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3693f9a0203d49a7ba8f38aa915316b3d535c1862d03dae7009cb71a3408b36a"
|
||||
checksum = "585480e3719b311b78a573db1c9d9c4c1f8010c2dee4cc59c2efe58ea4dbc3e1"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"cssparser 0.31.2",
|
||||
@ -5642,9 +5660,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared_entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"collab-entity",
|
||||
"database-entity",
|
||||
"gotrue-entity",
|
||||
@ -6689,7 +6708,7 @@ dependencies = [
|
||||
"time",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log 0.1.3",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@ -6714,17 +6733,6 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-serde"
|
||||
version = "0.1.3"
|
||||
@ -6752,7 +6760,7 @@ dependencies = [
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log 0.1.3",
|
||||
"tracing-log",
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
|
@ -38,7 +38,7 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87d0f05e988a02e9272a42722b304289be320e4" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c739029d99517282d2ec1593523a47b51a85231b" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -48,14 +48,14 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
|
||||
|
||||
|
||||
|
@ -15,13 +15,11 @@ import {
|
||||
SignInPayloadPB,
|
||||
SignUpPayloadPB,
|
||||
UpdateUserProfilePayloadPB,
|
||||
WorkspaceIdPB,
|
||||
WorkspacePB,
|
||||
WorkspaceSettingPB,
|
||||
} from '@/services/backend';
|
||||
import {
|
||||
FolderEventCreateWorkspace,
|
||||
FolderEventOpenWorkspace,
|
||||
FolderEventGetCurrentWorkspaceSetting,
|
||||
FolderEventReadCurrentWorkspace,
|
||||
} from '@/services/backend/events/flowy-folder2';
|
||||
@ -67,12 +65,6 @@ export class UserBackendService {
|
||||
return FolderEventReadCurrentWorkspace();
|
||||
};
|
||||
|
||||
openWorkspace = (workspaceId: string) => {
|
||||
const payload = WorkspaceIdPB.fromObject({ value: workspaceId });
|
||||
|
||||
return FolderEventOpenWorkspace(payload);
|
||||
};
|
||||
|
||||
createWorkspace = async (params: { name: string; desc: string }): Promise<WorkspacePB> => {
|
||||
const payload = CreateWorkspacePayloadPB.fromObject({ name: params.name, desc: params.desc });
|
||||
const result = await FolderEventCreateWorkspace(payload);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import {
|
||||
FolderEventCreateWorkspace,
|
||||
CreateWorkspacePayloadPB,
|
||||
FolderEventOpenWorkspace,
|
||||
FolderEventDeleteWorkspace,
|
||||
WorkspaceIdPB,
|
||||
FolderEventReadWorkspaceViews,
|
||||
FolderEventReadCurrentWorkspace,
|
||||
} from '@/services/backend/events/flowy-folder2';
|
||||
import { UserEventOpenWorkspace, UserWorkspaceIdPB } from '@/services/backend/events/flowy-user';
|
||||
|
||||
export class WorkspaceBackendService {
|
||||
constructor() {
|
||||
@ -24,11 +24,11 @@ export class WorkspaceBackendService {
|
||||
};
|
||||
|
||||
openWorkspace = async (workspaceId: string) => {
|
||||
const payload = new WorkspaceIdPB({
|
||||
value: workspaceId,
|
||||
const payload = new UserWorkspaceIdPB({
|
||||
workspace_id: workspaceId,
|
||||
});
|
||||
|
||||
return FolderEventOpenWorkspace(payload);
|
||||
return UserEventOpenWorkspace(payload);
|
||||
};
|
||||
|
||||
deleteWorkspace = async (workspaceId: string) => {
|
||||
|
80
frontend/rust-lib/Cargo.lock
generated
80
frontend/rust-lib/Cargo.lock
generated
@ -121,6 +121,21 @@ version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
@ -452,7 +467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"hashbrown 0.12.3",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -651,9 +666,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
@ -712,7 +728,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -731,7 +747,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -761,7 +777,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -773,7 +789,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -793,7 +809,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -807,7 +823,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -849,7 +865,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
@ -870,7 +886,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -897,7 +913,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=01f92f7bb#01f92f7bb204a3aeed24b345d504dfd36d3d9fcb"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bab20052#bab200529ef0306194fa8618cc8708878b01ce04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1256,9 +1272,10 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"chrono",
|
||||
"collab-entity",
|
||||
"serde",
|
||||
@ -1885,7 +1902,7 @@ dependencies = [
|
||||
"nanoid",
|
||||
"parking_lot",
|
||||
"protobuf",
|
||||
"scraper 0.18.0",
|
||||
"scraper 0.18.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum_macros 0.21.1",
|
||||
@ -2437,7 +2454,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2453,9 +2470,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"jsonwebtoken",
|
||||
"lazy_static",
|
||||
"reqwest",
|
||||
@ -2813,7 +2831,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -2979,7 +2997,6 @@ dependencies = [
|
||||
"tracing-appender",
|
||||
"tracing-bunyan-formatter",
|
||||
"tracing-core",
|
||||
"tracing-log 0.2.0",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@ -4254,8 +4271,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "realtime-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
@ -4705,9 +4723,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "scraper"
|
||||
version = "0.18.0"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3693f9a0203d49a7ba8f38aa915316b3d535c1862d03dae7009cb71a3408b36a"
|
||||
checksum = "585480e3719b311b78a573db1c9d9c4c1f8010c2dee4cc59c2efe58ea4dbc3e1"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"cssparser",
|
||||
@ -4810,9 +4828,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -4891,9 +4909,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared_entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c739029d99517282d2ec1593523a47b51a85231b#c739029d99517282d2ec1593523a47b51a85231b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
"collab-entity",
|
||||
"database-entity",
|
||||
"gotrue-entity",
|
||||
@ -5654,7 +5673,7 @@ dependencies = [
|
||||
"time",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log 0.1.3",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@ -5679,17 +5698,6 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-serde"
|
||||
version = "0.1.3"
|
||||
@ -5717,7 +5725,7 @@ dependencies = [
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log 0.1.3",
|
||||
"tracing-log",
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
|
@ -82,7 +82,7 @@ incremental = false
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87d0f05e988a02e9272a42722b304289be320e4" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c739029d99517282d2ec1593523a47b51a85231b" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -92,11 +92,11 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "01f92f7bb" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "bab20052" }
|
||||
|
@ -144,19 +144,10 @@ pub struct ViewTest {
|
||||
pub workspace: WorkspacePB,
|
||||
pub child_view: ViewPB,
|
||||
}
|
||||
|
||||
impl ViewTest {
|
||||
#[allow(dead_code)]
|
||||
pub async fn new(sdk: &EventIntegrationTest, layout: ViewLayoutPB, data: Vec<u8>) -> Self {
|
||||
let workspace = sdk.folder_manager.get_current_workspace().await.unwrap();
|
||||
let payload = WorkspaceIdPB {
|
||||
value: workspace.id.clone(),
|
||||
};
|
||||
let _ = EventBuilder::new(sdk.clone())
|
||||
.event(OpenWorkspace)
|
||||
.payload(payload)
|
||||
.async_send()
|
||||
.await;
|
||||
|
||||
let payload = CreateViewPayloadPB {
|
||||
parent_view_id: workspace.id.clone(),
|
||||
|
@ -22,7 +22,7 @@ async fn af_cloud_edit_document_test() {
|
||||
let rx = test
|
||||
.notification_sender
|
||||
.subscribe_with_condition::<DocumentSyncStatePB, _>(&document_id, |pb| pb.is_finish);
|
||||
receive_with_timeout(rx, Duration::from_secs(15))
|
||||
receive_with_timeout(rx, Duration::from_secs(25))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -5,7 +5,6 @@ use std::sync::{Arc, Weak};
|
||||
use parking_lot::RwLock;
|
||||
use serde_repr::*;
|
||||
|
||||
use collab_integrate::YrsDocAction;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_server::af_cloud::AFCloudServer;
|
||||
use flowy_server::local_server::{LocalServer, LocalServerDB};
|
||||
@ -14,9 +13,7 @@ use flowy_server::{AppFlowyEncryption, AppFlowyServer, EncryptionImpl};
|
||||
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||
use flowy_server_config::supabase_config::SupabaseConfiguration;
|
||||
use flowy_sqlite::kv::StorePreferences;
|
||||
use flowy_user::services::database::{
|
||||
get_user_profile, get_user_workspace, open_collab_db, open_user_db,
|
||||
};
|
||||
use flowy_user::services::database::{get_user_profile, get_user_workspace, open_user_db};
|
||||
use flowy_user_deps::cloud::UserCloudService;
|
||||
use flowy_user_deps::entities::*;
|
||||
|
||||
@ -195,14 +192,4 @@ impl LocalServerDB for LocalServerDBImpl {
|
||||
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().with_context(format!("Failed to open collab db: {:?}", e))
|
||||
})?;
|
||||
|
||||
Ok(updates)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,9 @@ use flowy_database_deps::cloud::{
|
||||
use flowy_document2::deps::DocumentData;
|
||||
use flowy_document_deps::cloud::{DocumentCloudService, DocumentSnapshot};
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder_deps::cloud::{FolderCloudService, FolderData, FolderSnapshot, Workspace};
|
||||
use flowy_folder_deps::cloud::{
|
||||
FolderCloudService, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
|
||||
};
|
||||
use flowy_storage::{FileStorageService, StorageObject};
|
||||
use flowy_user::event_map::UserCloudServiceProvider;
|
||||
use flowy_user_deps::cloud::UserCloudService;
|
||||
@ -140,6 +142,17 @@ impl FolderCloudService for ServerProvider {
|
||||
FutureResult::new(async move { server?.folder_service().create_workspace(uid, &name).await })
|
||||
}
|
||||
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<(), Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let server = self.get_server(&self.get_server_type());
|
||||
FutureResult::new(async move { server?.folder_service().open_workspace(&workspace_id).await })
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error> {
|
||||
let server = self.get_server(&self.get_server_type());
|
||||
FutureResult::new(async move { server?.folder_service().get_all_workspace().await })
|
||||
}
|
||||
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
@ -245,7 +258,7 @@ impl DocumentCloudService for ServerProvider {
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let document_id = document_id.to_string();
|
||||
let server = self.get_server(&self.get_server_type());
|
||||
@ -308,7 +321,7 @@ impl CollabStorageProvider for ServerProvider {
|
||||
to_fut(async move {
|
||||
let mut plugins: Vec<Arc<dyn CollabPlugin>> = vec![];
|
||||
match server.collab_ws_channel(&collab_object.object_id).await {
|
||||
Ok(Some((channel, ws_connect_state))) => {
|
||||
Ok(Some((channel, ws_connect_state, is_connected))) => {
|
||||
let origin = CollabOrigin::Client(CollabClient::new(
|
||||
collab_object.uid,
|
||||
collab_object.device_id.clone(),
|
||||
@ -316,7 +329,7 @@ impl CollabStorageProvider for ServerProvider {
|
||||
let sync_object = SyncObject::from(collab_object);
|
||||
let (sink, stream) = (channel.sink(), channel.stream());
|
||||
let sink_config = SinkConfig::new()
|
||||
.send_timeout(6)
|
||||
.send_timeout(8)
|
||||
.with_strategy(SinkStrategy::FixInterval(Duration::from_secs(2)));
|
||||
let sync_plugin = SyncPlugin::new(
|
||||
origin,
|
||||
@ -326,6 +339,7 @@ impl CollabStorageProvider for ServerProvider {
|
||||
sink_config,
|
||||
stream,
|
||||
Some(channel),
|
||||
!is_connected,
|
||||
ws_connect_state,
|
||||
);
|
||||
plugins.push(Arc::new(sync_plugin));
|
||||
|
@ -1,12 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use tracing::event;
|
||||
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder2::manager::{FolderInitializeDataSource, FolderManager};
|
||||
use flowy_folder2::manager::{FolderInitDataSource, FolderManager};
|
||||
use flowy_user::event_map::{UserCloudServiceProvider, UserStatusCallback};
|
||||
use flowy_user_deps::cloud::UserCloudConfig;
|
||||
use flowy_user_deps::entities::{AuthType, UserProfile, UserWorkspace};
|
||||
@ -59,7 +60,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
.initialize(
|
||||
user_id,
|
||||
&user_workspace.id,
|
||||
FolderInitializeDataSource::LocalDisk {
|
||||
FolderInitDataSource::LocalDisk {
|
||||
create_if_not_exist: false,
|
||||
},
|
||||
)
|
||||
@ -82,8 +83,9 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
&self,
|
||||
user_id: i64,
|
||||
user_workspace: &UserWorkspace,
|
||||
_device_id: &str,
|
||||
device_id: &str,
|
||||
) -> Fut<FlowyResult<()>> {
|
||||
let device_id = device_id.to_owned();
|
||||
let user_id = user_id.to_owned();
|
||||
let user_workspace = user_workspace.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
@ -91,6 +93,13 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
event!(
|
||||
tracing::Level::TRACE,
|
||||
"Notify did sign in: latest_workspace: {:?}, device_id: {}",
|
||||
user_workspace,
|
||||
device_id
|
||||
);
|
||||
|
||||
folder_manager
|
||||
.initialize_with_workspace_id(user_id, &user_workspace.id)
|
||||
.await?;
|
||||
@ -113,8 +122,9 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
is_new_user: bool,
|
||||
user_profile: &UserProfile,
|
||||
user_workspace: &UserWorkspace,
|
||||
_device_id: &str,
|
||||
device_id: &str,
|
||||
) -> Fut<FlowyResult<()>> {
|
||||
let device_id = device_id.to_owned();
|
||||
let user_profile = user_profile.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
@ -122,12 +132,20 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
event!(
|
||||
tracing::Level::TRACE,
|
||||
"Notify did sign up: is new: {} user_workspace: {:?}, device_id: {}",
|
||||
is_new_user,
|
||||
user_workspace,
|
||||
device_id
|
||||
);
|
||||
|
||||
folder_manager
|
||||
.initialize_with_new_user(
|
||||
user_profile.uid,
|
||||
&user_profile.token,
|
||||
is_new_user,
|
||||
FolderInitializeDataSource::LocalDisk {
|
||||
FolderInitDataSource::LocalDisk {
|
||||
create_if_not_exist: true,
|
||||
},
|
||||
&user_workspace.id,
|
||||
|
@ -196,7 +196,6 @@ impl AppFlowyCore {
|
||||
|
||||
let cloned_user_session = Arc::downgrade(&user_manager);
|
||||
if let Some(user_session) = cloned_user_session.upgrade() {
|
||||
event!(tracing::Level::DEBUG, "init user session",);
|
||||
if let Err(err) = user_session
|
||||
.init(user_status_callback, collab_interact_impl)
|
||||
.await
|
||||
|
@ -13,7 +13,7 @@ use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLay
|
||||
use collab_entity::CollabType;
|
||||
use futures::executor::block_on;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{instrument, trace};
|
||||
use tracing::{event, instrument, trace};
|
||||
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::{CollabPersistenceConfig, RocksCollabDB};
|
||||
@ -80,6 +80,11 @@ impl DatabaseManager {
|
||||
workspace_id: String,
|
||||
database_views_aggregate_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
// Clear all existing tasks
|
||||
self.task_scheduler.write().await.clear_task();
|
||||
// Release all existing editors
|
||||
self.editors.write().await.clear();
|
||||
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
let collab_builder = UserDatabaseCollabServiceImpl {
|
||||
workspace_id: workspace_id.clone(),
|
||||
@ -114,7 +119,11 @@ impl DatabaseManager {
|
||||
}
|
||||
|
||||
// Construct the workspace database.
|
||||
trace!("open workspace database: {}", &database_views_aggregate_id);
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"open aggregate database views object: {}",
|
||||
&database_views_aggregate_id
|
||||
);
|
||||
let collab = collab_builder.build_collab_with_config(
|
||||
uid,
|
||||
&database_views_aggregate_id,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use anyhow::Error;
|
||||
pub use collab_document::blocks::DocumentData;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
/// A trait for document cloud service.
|
||||
@ -11,7 +12,7 @@ pub trait DocumentCloudService: Send + Sync + 'static {
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error>;
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError>;
|
||||
|
||||
fn get_document_snapshots(
|
||||
&self,
|
||||
|
@ -1,14 +1,14 @@
|
||||
use std::sync::Weak;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab::core::collab::{CollabRawData, MutexCollab};
|
||||
use collab_document::blocks::DocumentData;
|
||||
use collab_document::document::Document;
|
||||
use collab_document::document_data::default_document_data;
|
||||
use collab_document::document_data::{default_document_collab_data, default_document_data};
|
||||
use collab_document::YrsDocAction;
|
||||
use collab_entity::CollabType;
|
||||
use parking_lot::RwLock;
|
||||
use tracing::instrument;
|
||||
use tracing::{event, instrument};
|
||||
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::RocksCollabDB;
|
||||
@ -109,10 +109,29 @@ impl DocumentManager {
|
||||
let mut updates = vec![];
|
||||
if !self.is_doc_exist(doc_id)? {
|
||||
// Try to get the document from the cloud service
|
||||
updates = self
|
||||
let result: Result<CollabRawData, FlowyError> = self
|
||||
.cloud_service
|
||||
.get_document_updates(&self.user.workspace_id()?, doc_id)
|
||||
.await?;
|
||||
.get_document_updates(doc_id, &self.user.workspace_id()?)
|
||||
.await;
|
||||
|
||||
updates = match result {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
if err.is_record_not_found() {
|
||||
// The document's ID exists in the cloud, but its content does not.
|
||||
// This occurs when user A's document hasn't finished syncing and user B tries to open it.
|
||||
// As a result, a blank document is created for user B.
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"can't find the document in the cloud, doc_id: {}",
|
||||
doc_id
|
||||
);
|
||||
default_document_collab_data(doc_id)
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let uid = self.user.user_id()?;
|
||||
|
@ -129,7 +129,7 @@ impl DocumentCloudService for LocalTestDocumentCloudServiceImpl {
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
|
@ -98,9 +98,6 @@ pub enum ErrorCode {
|
||||
#[error("user id is empty or whitespace")]
|
||||
UserIdInvalid = 30,
|
||||
|
||||
#[error("User not exist")]
|
||||
UserNotExist = 31,
|
||||
|
||||
#[error("Text is too long")]
|
||||
TextTooLong = 32,
|
||||
|
||||
|
@ -55,6 +55,10 @@ impl FlowyError {
|
||||
self.code == ErrorCode::RecordNotFound
|
||||
}
|
||||
|
||||
pub fn is_unauthorized(&self) -> bool {
|
||||
self.code == ErrorCode::UserUnauthorized || self.code == ErrorCode::RecordNotFound
|
||||
}
|
||||
|
||||
static_flowy_error!(internal, ErrorCode::Internal);
|
||||
static_flowy_error!(record_not_found, ErrorCode::RecordNotFound);
|
||||
static_flowy_error!(workspace_name, ErrorCode::WorkspaceNameInvalid);
|
||||
@ -87,7 +91,6 @@ impl FlowyError {
|
||||
);
|
||||
static_flowy_error!(name_empty, ErrorCode::UserNameIsEmpty);
|
||||
static_flowy_error!(user_id, ErrorCode::UserIdInvalid);
|
||||
static_flowy_error!(user_not_exist, ErrorCode::UserNotExist);
|
||||
static_flowy_error!(text_too_long, ErrorCode::TextTooLong);
|
||||
static_flowy_error!(invalid_data, ErrorCode::InvalidParams);
|
||||
static_flowy_error!(out_of_bounds, ErrorCode::OutOfBounds);
|
||||
|
@ -1,26 +1,25 @@
|
||||
use client_api::error::AppError;
|
||||
use client_api::error::{AppResponseError, ErrorCode as AppErrorCode};
|
||||
|
||||
use crate::{ErrorCode, FlowyError};
|
||||
|
||||
impl From<AppError> for FlowyError {
|
||||
fn from(error: AppError) -> Self {
|
||||
impl From<AppResponseError> for FlowyError {
|
||||
fn from(error: AppResponseError) -> Self {
|
||||
let code = match error.code {
|
||||
client_api::error::ErrorCode::Ok => ErrorCode::Internal,
|
||||
client_api::error::ErrorCode::Unhandled => ErrorCode::Internal,
|
||||
client_api::error::ErrorCode::RecordNotFound => ErrorCode::RecordNotFound,
|
||||
client_api::error::ErrorCode::RecordAlreadyExists => ErrorCode::RecordAlreadyExists,
|
||||
client_api::error::ErrorCode::InvalidEmail => ErrorCode::EmailFormatInvalid,
|
||||
client_api::error::ErrorCode::InvalidPassword => ErrorCode::PasswordFormatInvalid,
|
||||
client_api::error::ErrorCode::OAuthError => ErrorCode::UserUnauthorized,
|
||||
client_api::error::ErrorCode::MissingPayload => ErrorCode::MissingPayload,
|
||||
client_api::error::ErrorCode::OpenError => ErrorCode::Internal,
|
||||
client_api::error::ErrorCode::InvalidUrl => ErrorCode::InvalidURL,
|
||||
client_api::error::ErrorCode::InvalidRequestParams => ErrorCode::InvalidParams,
|
||||
client_api::error::ErrorCode::UrlMissingParameter => ErrorCode::InvalidParams,
|
||||
client_api::error::ErrorCode::InvalidOAuthProvider => ErrorCode::InvalidAuthConfig,
|
||||
client_api::error::ErrorCode::NotLoggedIn => ErrorCode::UserUnauthorized,
|
||||
client_api::error::ErrorCode::NotEnoughPermissions => ErrorCode::NotEnoughPermissions,
|
||||
client_api::error::ErrorCode::UserNameIsEmpty => ErrorCode::UserNameIsEmpty,
|
||||
AppErrorCode::Ok => ErrorCode::Internal,
|
||||
AppErrorCode::Unhandled => ErrorCode::Internal,
|
||||
AppErrorCode::RecordNotFound => ErrorCode::RecordNotFound,
|
||||
AppErrorCode::RecordAlreadyExists => ErrorCode::RecordAlreadyExists,
|
||||
AppErrorCode::InvalidEmail => ErrorCode::EmailFormatInvalid,
|
||||
AppErrorCode::InvalidPassword => ErrorCode::PasswordFormatInvalid,
|
||||
AppErrorCode::OAuthError => ErrorCode::UserUnauthorized,
|
||||
AppErrorCode::MissingPayload => ErrorCode::MissingPayload,
|
||||
AppErrorCode::OpenError => ErrorCode::Internal,
|
||||
AppErrorCode::InvalidUrl => ErrorCode::InvalidURL,
|
||||
AppErrorCode::InvalidRequestParams => ErrorCode::InvalidParams,
|
||||
AppErrorCode::UrlMissingParameter => ErrorCode::InvalidParams,
|
||||
AppErrorCode::InvalidOAuthProvider => ErrorCode::InvalidAuthConfig,
|
||||
AppErrorCode::NotLoggedIn => ErrorCode::UserUnauthorized,
|
||||
AppErrorCode::NotEnoughPermissions => ErrorCode::NotEnoughPermissions,
|
||||
_ => ErrorCode::Internal,
|
||||
};
|
||||
|
||||
|
@ -6,8 +6,16 @@ use lib_infra::future::FutureResult;
|
||||
|
||||
/// [FolderCloudService] represents the cloud service for folder.
|
||||
pub trait FolderCloudService: Send + Sync + 'static {
|
||||
/// Creates a new workspace for the user.
|
||||
/// Returns error if the cloud service doesn't support multiple workspaces
|
||||
fn create_workspace(&self, uid: i64, name: &str) -> FutureResult<Workspace, Error>;
|
||||
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<(), Error>;
|
||||
|
||||
/// Returns all workspaces of the user.
|
||||
/// Returns vec![] if the cloud service doesn't support multiple workspaces
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error>;
|
||||
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
@ -39,3 +47,10 @@ pub fn gen_workspace_id() -> Uuid {
|
||||
pub fn gen_view_id() -> Uuid {
|
||||
uuid::Uuid::new_v4()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WorkspaceRecord {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub created_at: i64,
|
||||
}
|
||||
|
@ -38,6 +38,14 @@ pub(crate) async fn create_workspace_handler(
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn get_all_workspace_handler(
|
||||
_data: AFPluginData<CreateWorkspacePayloadPB>,
|
||||
_folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedWorkspacePB, FlowyError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn get_workspace_views_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
@ -48,32 +56,12 @@ pub(crate) async fn get_workspace_views_handler(
|
||||
data_result_ok(repeated_view)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn open_workspace_handler(
|
||||
data: AFPluginData<WorkspaceIdPB>,
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspacePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let workspace_id = data.into_inner().value;
|
||||
if workspace_id.is_empty() {
|
||||
Err(FlowyError::workspace_id().with_context("workspace id should not be empty"))
|
||||
} else {
|
||||
let workspace = folder.open_workspace(&workspace_id).await?;
|
||||
let views = folder.get_workspace_views(&workspace_id).await?;
|
||||
let workspace_pb: WorkspacePB = (workspace, views).into();
|
||||
data_result_ok(workspace_pb)
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn read_current_workspace_setting_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspaceSettingPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let setting = folder
|
||||
.get_workspace_setting_pb()
|
||||
.await
|
||||
.ok_or(FlowyError::record_not_found())?;
|
||||
let setting = folder.get_workspace_setting_pb().await?;
|
||||
data_result_ok(setting)
|
||||
}
|
||||
|
||||
@ -82,10 +70,7 @@ pub(crate) async fn read_current_workspace_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<WorkspacePB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let workspace = folder
|
||||
.get_workspace_pb()
|
||||
.await
|
||||
.ok_or(FlowyError::record_not_found())?;
|
||||
let workspace = folder.get_workspace_pb().await?;
|
||||
data_result_ok(workspace)
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,8 @@ pub fn init(folder: Weak<FolderManager>) -> AFPlugin {
|
||||
AFPlugin::new().name("Flowy-Folder").state(folder)
|
||||
// Workspace
|
||||
.event(FolderEvent::CreateWorkspace, create_workspace_handler)
|
||||
.event(FolderEvent::GetCurrentWorkspaceSetting, read_current_workspace_setting_handler)
|
||||
.event(FolderEvent::GetCurrentWorkspaceSetting, read_current_workspace_setting_handler)
|
||||
.event(FolderEvent::ReadCurrentWorkspace, read_current_workspace_handler)
|
||||
.event(FolderEvent::OpenWorkspace, open_workspace_handler)
|
||||
.event(FolderEvent::ReadWorkspaceViews, get_workspace_views_handler)
|
||||
// View
|
||||
.event(FolderEvent::CreateView, create_view_handler)
|
||||
@ -59,10 +58,6 @@ pub enum FolderEvent {
|
||||
#[event(input = "WorkspaceIdPB")]
|
||||
DeleteWorkspace = 3,
|
||||
|
||||
/// Open the workspace and mark it as the current workspace
|
||||
#[event(input = "WorkspaceIdPB", output = "WorkspacePB")]
|
||||
OpenWorkspace = 4,
|
||||
|
||||
/// Return a list of views of the current workspace.
|
||||
/// Only the first level of child views are included.
|
||||
#[event(input = "WorkspaceIdPB", output = "RepeatedViewPB")]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
@ -124,68 +125,50 @@ impl FolderManager {
|
||||
Ok(views)
|
||||
}
|
||||
|
||||
/// Called immediately after the application launched fi the user already sign in/sign up.
|
||||
/// Called immediately after the application launched if the user already sign in/sign up.
|
||||
#[tracing::instrument(level = "info", skip(self, initial_data), err)]
|
||||
pub async fn initialize(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: &str,
|
||||
initial_data: FolderInitializeDataSource,
|
||||
initial_data: FolderInitDataSource,
|
||||
) -> FlowyResult<()> {
|
||||
// Update the workspace id
|
||||
event!(
|
||||
Level::INFO,
|
||||
"Init current workspace: {} from: {}",
|
||||
workspace_id,
|
||||
initial_data
|
||||
);
|
||||
*self.workspace_id.write() = Some(workspace_id.to_string());
|
||||
let workspace_id = workspace_id.to_string();
|
||||
if let Ok(collab_db) = self.user.collab_db(uid) {
|
||||
let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
|
||||
let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
|
||||
let folder_notifier = FolderNotify {
|
||||
view_change_tx: view_tx,
|
||||
trash_change_tx: trash_tx,
|
||||
};
|
||||
|
||||
let folder = match initial_data {
|
||||
FolderInitializeDataSource::LocalDisk {
|
||||
create_if_not_exist,
|
||||
} => {
|
||||
let is_exist = is_exist_in_local_disk(&self.user, &workspace_id).unwrap_or(false);
|
||||
if is_exist {
|
||||
event!(Level::INFO, "Restore folder from local disk");
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||
.await?;
|
||||
Folder::open(UserId::from(uid), collab, Some(folder_notifier))?
|
||||
} else if create_if_not_exist {
|
||||
event!(Level::INFO, "Create folder with default folder builder");
|
||||
let folder_data =
|
||||
DefaultFolderBuilder::build(uid, workspace_id.to_string(), &self.operation_handlers)
|
||||
.await;
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||
.await?;
|
||||
Folder::create(
|
||||
UserId::from(uid),
|
||||
collab,
|
||||
Some(folder_notifier),
|
||||
folder_data,
|
||||
)
|
||||
} else {
|
||||
return Err(FlowyError::new(
|
||||
ErrorCode::RecordNotFound,
|
||||
"Can't find any workspace data",
|
||||
));
|
||||
}
|
||||
},
|
||||
FolderInitializeDataSource::Cloud(raw_data) => {
|
||||
event!(Level::INFO, "Restore folder from cloud service");
|
||||
if raw_data.is_empty() {
|
||||
return Err(workspace_data_not_sync_error(uid, &workspace_id));
|
||||
}
|
||||
// Get the collab db for the user with given user id.
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
|
||||
let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
|
||||
let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
|
||||
let folder_notifier = FolderNotify {
|
||||
view_change_tx: view_tx,
|
||||
trash_change_tx: trash_tx,
|
||||
};
|
||||
|
||||
let folder = match initial_data {
|
||||
FolderInitDataSource::LocalDisk {
|
||||
create_if_not_exist,
|
||||
} => {
|
||||
let is_exist = is_exist_in_local_disk(&self.user, &workspace_id).unwrap_or(false);
|
||||
if is_exist {
|
||||
event!(Level::INFO, "Restore folder from local disk");
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, raw_data)
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||
.await?;
|
||||
Folder::open(UserId::from(uid), collab, Some(folder_notifier))?
|
||||
},
|
||||
FolderInitializeDataSource::FolderData(folder_data) => {
|
||||
event!(Level::INFO, "Restore folder with passed-in folder data");
|
||||
} else if create_if_not_exist {
|
||||
event!(Level::INFO, "Create folder with default folder builder");
|
||||
let folder_data =
|
||||
DefaultFolderBuilder::build(uid, workspace_id.to_string(), &self.operation_handlers)
|
||||
.await;
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||
.await?;
|
||||
@ -195,24 +178,45 @@ impl FolderManager {
|
||||
Some(folder_notifier),
|
||||
folder_data,
|
||||
)
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return Err(FlowyError::new(
|
||||
ErrorCode::RecordNotFound,
|
||||
"Can't find any workspace data",
|
||||
));
|
||||
}
|
||||
},
|
||||
FolderInitDataSource::Cloud(raw_data) => {
|
||||
event!(Level::INFO, "Restore folder from cloud service");
|
||||
if raw_data.is_empty() {
|
||||
return Err(workspace_data_not_sync_error(uid, &workspace_id));
|
||||
}
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, raw_data)
|
||||
.await?;
|
||||
Folder::open(UserId::from(uid), collab, Some(folder_notifier))?
|
||||
},
|
||||
FolderInitDataSource::FolderData(folder_data) => {
|
||||
event!(Level::INFO, "Restore folder with passed-in folder data");
|
||||
let collab = self
|
||||
.collab_for_folder(uid, &workspace_id, collab_db, vec![])
|
||||
.await?;
|
||||
Folder::create(
|
||||
UserId::from(uid),
|
||||
collab,
|
||||
Some(folder_notifier),
|
||||
folder_data,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
tracing::debug!("Current workspace_id: {}", workspace_id);
|
||||
let folder_state_rx = folder.subscribe_sync_state();
|
||||
*self.mutex_folder.lock() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
subscribe_folder_sync_state_changed(
|
||||
workspace_id.clone(),
|
||||
folder_state_rx,
|
||||
&weak_mutex_folder,
|
||||
);
|
||||
subscribe_folder_snapshot_state_changed(workspace_id, &weak_mutex_folder);
|
||||
subscribe_folder_trash_changed(trash_rx, &weak_mutex_folder);
|
||||
subscribe_folder_view_changed(view_rx, &weak_mutex_folder);
|
||||
}
|
||||
let folder_state_rx = folder.subscribe_sync_state();
|
||||
*self.mutex_folder.lock() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder);
|
||||
subscribe_folder_snapshot_state_changed(workspace_id, &weak_mutex_folder);
|
||||
subscribe_folder_trash_changed(trash_rx, &weak_mutex_folder);
|
||||
subscribe_folder_view_changed(view_rx, &weak_mutex_folder);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -239,7 +243,7 @@ impl FolderManager {
|
||||
|
||||
/// 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)]
|
||||
#[tracing::instrument(skip(self, user_id), err)]
|
||||
pub async fn initialize_with_workspace_id(
|
||||
&self,
|
||||
user_id: i64,
|
||||
@ -250,7 +254,8 @@ impl FolderManager {
|
||||
.get_folder_updates(workspace_id, user_id)
|
||||
.await?;
|
||||
|
||||
info!(
|
||||
event!(
|
||||
Level::INFO,
|
||||
"Get folder updates via {}, number of updates: {}",
|
||||
self.cloud_service.service_name(),
|
||||
folder_updates.len()
|
||||
@ -260,7 +265,7 @@ impl FolderManager {
|
||||
.initialize(
|
||||
user_id,
|
||||
workspace_id,
|
||||
FolderInitializeDataSource::Cloud(folder_updates),
|
||||
FolderInitDataSource::Cloud(folder_updates),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
@ -268,18 +273,13 @@ impl FolderManager {
|
||||
|
||||
/// Initialize the folder for the new user.
|
||||
/// Using the [DefaultFolderBuilder] to create the default workspace for the new user.
|
||||
#[instrument(
|
||||
name = "folder_initialize_with_new_user",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
err
|
||||
)]
|
||||
#[instrument(level = "info", skip_all, err)]
|
||||
pub async fn initialize_with_new_user(
|
||||
&self,
|
||||
user_id: i64,
|
||||
_token: &str,
|
||||
is_new: bool,
|
||||
data_source: FolderInitializeDataSource,
|
||||
data_source: FolderInitDataSource,
|
||||
workspace_id: &str,
|
||||
) -> FlowyResult<()> {
|
||||
// Create the default workspace if the user is new
|
||||
@ -306,7 +306,7 @@ impl FolderManager {
|
||||
.initialize(
|
||||
user_id,
|
||||
workspace_id,
|
||||
FolderInitializeDataSource::Cloud(folder_updates),
|
||||
FolderInitDataSource::Cloud(folder_updates),
|
||||
)
|
||||
.await?;
|
||||
},
|
||||
@ -348,20 +348,24 @@ impl FolderManager {
|
||||
self.with_folder(|| None, |folder| folder.get_current_workspace())
|
||||
}
|
||||
|
||||
pub async fn get_workspace_setting_pb(&self) -> Option<WorkspaceSettingPB> {
|
||||
let workspace_id = self.get_current_workspace_id().await.ok()?;
|
||||
pub async fn get_workspace_setting_pb(&self) -> FlowyResult<WorkspaceSettingPB> {
|
||||
let workspace_id = self.get_current_workspace_id().await?;
|
||||
let latest_view = self.get_current_view().await;
|
||||
Some(WorkspaceSettingPB {
|
||||
Ok(WorkspaceSettingPB {
|
||||
workspace_id,
|
||||
latest_view,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_workspace_pb(&self) -> Option<WorkspacePB> {
|
||||
pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> {
|
||||
let workspace_pb = {
|
||||
let guard = self.mutex_folder.lock();
|
||||
let folder = guard.as_ref()?;
|
||||
let workspace = folder.get_current_workspace()?;
|
||||
let folder = guard
|
||||
.as_ref()
|
||||
.ok_or(FlowyError::internal().with_context("folder is not initialized"))?;
|
||||
let workspace = folder.get_current_workspace().ok_or(
|
||||
FlowyError::record_not_found().with_context("Can't find the current workspace id "),
|
||||
)?;
|
||||
|
||||
let views = folder
|
||||
.views
|
||||
@ -378,7 +382,7 @@ impl FolderManager {
|
||||
}
|
||||
};
|
||||
|
||||
Some(workspace_pb)
|
||||
Ok(workspace_pb)
|
||||
}
|
||||
|
||||
async fn get_current_workspace_id(&self) -> FlowyResult<String> {
|
||||
@ -1274,7 +1278,7 @@ impl Deref for MutexFolder {
|
||||
unsafe impl Sync for MutexFolder {}
|
||||
unsafe impl Send for MutexFolder {}
|
||||
|
||||
pub enum FolderInitializeDataSource {
|
||||
pub enum FolderInitDataSource {
|
||||
/// It means using the data stored on local disk to initialize the folder
|
||||
LocalDisk { create_if_not_exist: bool },
|
||||
/// If there is no data stored on local disk, we will use the data from the server to initialize the folder
|
||||
@ -1283,6 +1287,16 @@ pub enum FolderInitializeDataSource {
|
||||
FolderData(FolderData),
|
||||
}
|
||||
|
||||
impl Display for FolderInitDataSource {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FolderInitDataSource::LocalDisk { .. } => f.write_fmt(format_args!("LocalDisk")),
|
||||
FolderInitDataSource::Cloud(_) => f.write_fmt(format_args!("Cloud")),
|
||||
FolderInitDataSource::FolderData(_) => f.write_fmt(format_args!("Custom FolderData")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_exist_in_local_disk(user: &Arc<dyn FolderUser>, doc_id: &str) -> FlowyResult<bool> {
|
||||
let uid = user.user_id()?;
|
||||
if let Some(collab_db) = user.collab_db(uid)?.upgrade() {
|
||||
|
@ -20,7 +20,7 @@ where
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let document_id = document_id.to_string();
|
||||
|
@ -4,7 +4,9 @@ use collab::core::origin::CollabOrigin;
|
||||
use collab_entity::CollabType;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder_deps::cloud::{Folder, FolderCloudService, FolderData, FolderSnapshot, Workspace};
|
||||
use flowy_folder_deps::cloud::{
|
||||
Folder, FolderCloudService, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::af_cloud::AFServer;
|
||||
@ -19,6 +21,35 @@ where
|
||||
FutureResult::new(async move { Err(anyhow!("Not support yet")) })
|
||||
}
|
||||
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<(), Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let _ = client.open_workspace(&workspace_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error> {
|
||||
let try_get_client = self.0.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let records = client
|
||||
.get_user_workspace_info()
|
||||
.await?
|
||||
.workspaces
|
||||
.into_iter()
|
||||
.map(|af_workspace| WorkspaceRecord {
|
||||
id: af_workspace.workspace_id.to_string(),
|
||||
name: af_workspace.workspace_name,
|
||||
created_at: af_workspace.created_at.timestamp(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Ok(records)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
|
@ -113,7 +113,17 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_user_workspaces(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let af_workspace = client.open_workspace(&workspace_id).await?;
|
||||
Ok(to_user_workspace(af_workspace))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let workspaces = try_get_client?.get_workspaces().await?;
|
||||
|
@ -4,12 +4,12 @@ use std::sync::Arc;
|
||||
use anyhow::Error;
|
||||
use client_api::notify::{TokenState, TokenStateReceiver};
|
||||
use client_api::ws::{
|
||||
BusinessID, WSClient, WSClientConfig, WSConnectStateReceiver, WebSocketChannel,
|
||||
BusinessID, ConnectState, WSClient, WSClientConfig, WSConnectStateReceiver, WebSocketChannel,
|
||||
};
|
||||
use client_api::Client;
|
||||
use tokio::sync::watch;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::{error, info};
|
||||
use tracing::{error, event, info};
|
||||
|
||||
use flowy_database_deps::cloud::DatabaseCloudService;
|
||||
use flowy_document_deps::cloud::DocumentCloudService;
|
||||
@ -145,7 +145,8 @@ impl AppFlowyServer for AFCloudServer {
|
||||
fn collab_ws_channel(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> FutureResult<Option<(Arc<WebSocketChannel>, WSConnectStateReceiver)>, anyhow::Error> {
|
||||
) -> FutureResult<Option<(Arc<WebSocketChannel>, WSConnectStateReceiver, bool)>, anyhow::Error>
|
||||
{
|
||||
if self.enable_sync.load(Ordering::SeqCst) {
|
||||
let object_id = object_id.to_string();
|
||||
let weak_ws_client = Arc::downgrade(&self.ws_client);
|
||||
@ -155,7 +156,7 @@ impl AppFlowyServer for AFCloudServer {
|
||||
Some(ws_client) => {
|
||||
let channel = ws_client.subscribe(BusinessID::CollabId, object_id).ok();
|
||||
let connect_state_recv = ws_client.subscribe_connect_state();
|
||||
Ok(channel.map(|c| (c, connect_state_recv)))
|
||||
Ok(channel.map(|c| (c, connect_state_recv, ws_client.is_connected())))
|
||||
},
|
||||
}
|
||||
})
|
||||
@ -190,24 +191,33 @@ fn spawn_ws_conn(
|
||||
if let Some(ws_client) = weak_ws_client.upgrade() {
|
||||
let mut state_recv = ws_client.subscribe_connect_state();
|
||||
while let Ok(state) = state_recv.recv().await {
|
||||
if !state.is_timeout() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to reconnect if the connection is timed out.
|
||||
if let (Some(api_client), Some(device_id)) =
|
||||
(weak_api_client.upgrade(), weak_device_id.upgrade())
|
||||
{
|
||||
if enable_sync.load(Ordering::SeqCst) {
|
||||
info!("🟢websocket state: {:?}, reconnecting", state);
|
||||
let device_id = device_id.read().clone();
|
||||
match api_client.ws_url(&device_id) {
|
||||
Ok(ws_addr) => {
|
||||
let _ = ws_client.connect(ws_addr).await;
|
||||
},
|
||||
Err(err) => error!("Failed to get ws url: {}", err),
|
||||
info!("[websocket] state: {:?}", state);
|
||||
match state {
|
||||
ConnectState::PingTimeout => {
|
||||
// Try to reconnect if the connection is timed out.
|
||||
if let (Some(api_client), Some(device_id)) =
|
||||
(weak_api_client.upgrade(), weak_device_id.upgrade())
|
||||
{
|
||||
if enable_sync.load(Ordering::SeqCst) {
|
||||
let device_id = device_id.read().clone();
|
||||
match api_client.ws_url(&device_id) {
|
||||
Ok(ws_addr) => {
|
||||
event!(tracing::Level::INFO, "🟢reconnecting websocket");
|
||||
let _ = ws_client.connect(ws_addr).await;
|
||||
},
|
||||
Err(err) => error!("Failed to get ws url: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ConnectState::Unauthorized => {
|
||||
if let Some(api_client) = weak_api_client.upgrade() {
|
||||
if enable_sync.load(Ordering::SeqCst) {
|
||||
let _ = api_client.refresh().await;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use anyhow::Error;
|
||||
|
||||
use flowy_document_deps::cloud::*;
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub(crate) struct LocalServerDocumentCloudServiceImpl();
|
||||
@ -10,7 +11,7 @@ impl DocumentCloudService for LocalServerDocumentCloudServiceImpl {
|
||||
&self,
|
||||
_document_id: &str,
|
||||
_workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use anyhow::Error;
|
||||
|
||||
use flowy_folder_deps::cloud::{
|
||||
gen_workspace_id, FolderCloudService, FolderData, FolderSnapshot, Workspace,
|
||||
gen_workspace_id, FolderCloudService, FolderData, FolderSnapshot, Workspace, WorkspaceRecord,
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_infra::util::timestamp;
|
||||
@ -11,6 +11,7 @@ use lib_infra::util::timestamp;
|
||||
use crate::local_server::LocalServerDB;
|
||||
|
||||
pub(crate) struct LocalServerFolderCloudServiceImpl {
|
||||
#[allow(dead_code)]
|
||||
pub db: Arc<dyn LocalServerDB>,
|
||||
}
|
||||
|
||||
@ -27,6 +28,14 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
||||
})
|
||||
}
|
||||
|
||||
fn open_workspace(&self, _workspace_id: &str) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error> {
|
||||
FutureResult::new(async { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
@ -43,18 +52,12 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
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 {
|
||||
match weak_db.upgrade() {
|
||||
None => Ok(vec![]),
|
||||
Some(db) => {
|
||||
let updates = db.get_collab_updates(uid, &workspace_id)?;
|
||||
Ok(updates)
|
||||
},
|
||||
}
|
||||
})
|
||||
fn get_folder_updates(
|
||||
&self,
|
||||
_workspace_id: &str,
|
||||
_uid: i64,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn service_name(&self) -> String {
|
||||
|
@ -116,7 +116,13 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
||||
FutureResult::new(async { result })
|
||||
}
|
||||
|
||||
fn get_all_user_workspaces(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
fn open_workspace(&self, _workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError> {
|
||||
FutureResult::new(async {
|
||||
Err(FlowyError::not_support().with_context("local server doesn't support open workspace"))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self, _uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
FutureResult::new(async { Ok(vec![]) })
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ use crate::AppFlowyServer;
|
||||
pub trait LocalServerDB: Send + Sync + 'static {
|
||||
fn get_user_profile(&self, uid: i64) -> Result<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 {
|
||||
|
@ -104,7 +104,8 @@ pub trait AppFlowyServer: Send + Sync + 'static {
|
||||
fn collab_ws_channel(
|
||||
&self,
|
||||
_object_id: &str,
|
||||
) -> FutureResult<Option<(Arc<WebSocketChannel>, WSConnectStateReceiver)>, anyhow::Error> {
|
||||
) -> FutureResult<Option<(Arc<WebSocketChannel>, WSConnectStateReceiver, bool)>, anyhow::Error>
|
||||
{
|
||||
FutureResult::new(async { Ok(None) })
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ where
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Vec<Vec<u8>>, Error> {
|
||||
) -> FutureResult<Vec<Vec<u8>>, FlowyError> {
|
||||
let try_get_postgrest = self.server.try_get_weak_postgrest();
|
||||
let document_id = document_id.to_string();
|
||||
let (tx, rx) = channel();
|
||||
@ -43,7 +43,7 @@ where
|
||||
let action = FetchObjectUpdateAction::new(document_id, CollabType::Document, postgrest);
|
||||
let updates = action.run_with_fix_interval(5, 10).await?;
|
||||
if updates.is_empty() {
|
||||
return Err(FlowyError::collab_not_sync().into());
|
||||
return Err(FlowyError::collab_not_sync());
|
||||
}
|
||||
Ok(updates)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use tokio::sync::oneshot::channel;
|
||||
|
||||
use flowy_folder_deps::cloud::{
|
||||
gen_workspace_id, Folder, FolderCloudService, FolderData, FolderSnapshot, Workspace,
|
||||
WorkspaceRecord,
|
||||
};
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use lib_infra::future::FutureResult;
|
||||
@ -69,6 +70,14 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn open_workspace(&self, _workspace_id: &str) -> FutureResult<(), Error> {
|
||||
FutureResult::new(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error> {
|
||||
FutureResult::new(async { Ok(vec![]) })
|
||||
}
|
||||
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
|
@ -226,7 +226,13 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_user_workspaces(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
fn open_workspace(&self, _workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError> {
|
||||
FutureResult::new(async {
|
||||
Err(FlowyError::not_support().with_context("supabase server doesn't support open workspace"))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error> {
|
||||
let try_get_postgrest = self.server.try_get_postgrest();
|
||||
FutureResult::new(async move {
|
||||
let postgrest = try_get_postgrest?;
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::queue::TaskQueue;
|
||||
use crate::store::TaskStore;
|
||||
use crate::{Task, TaskContent, TaskId, TaskState};
|
||||
use anyhow::Error;
|
||||
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Error;
|
||||
use tokio::sync::{watch, RwLock};
|
||||
use tokio::time::interval;
|
||||
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
|
||||
use crate::queue::TaskQueue;
|
||||
use crate::store::TaskStore;
|
||||
use crate::{Task, TaskContent, TaskId, TaskState};
|
||||
|
||||
pub struct TaskDispatcher {
|
||||
queue: TaskQueue,
|
||||
store: TaskStore,
|
||||
@ -122,6 +122,9 @@ impl TaskDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_task(&mut self) {
|
||||
self.store.clear();
|
||||
}
|
||||
pub fn next_task_id(&self) -> TaskId {
|
||||
self.store.next_task_id()
|
||||
}
|
||||
|
@ -93,8 +93,10 @@ pub trait UserCloudService: Send + Sync + 'static {
|
||||
/// return None if the user is not found
|
||||
fn get_user_profile(&self, credential: UserCredentials) -> FutureResult<UserProfile, FlowyError>;
|
||||
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError>;
|
||||
|
||||
/// Return the all the workspaces of the user
|
||||
fn get_all_user_workspaces(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error>;
|
||||
fn get_all_workspace(&self, uid: i64) -> FutureResult<Vec<UserWorkspace>, Error>;
|
||||
|
||||
fn add_workspace_member(
|
||||
&self,
|
||||
|
@ -138,7 +138,7 @@ pub struct UserWorkspace {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
/// The database storage id is used indexing all the database in current workspace.
|
||||
/// The database storage id is used indexing all the database views in current workspace.
|
||||
#[serde(rename = "database_storage_id")]
|
||||
pub database_views_aggregate_id: String,
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use validator::Validate;
|
||||
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_user_deps::entities::*;
|
||||
|
||||
use crate::entities::parser::{UserEmail, UserIcon, UserName, UserOpenaiKey, UserPassword};
|
||||
use crate::entities::required_not_empty_str;
|
||||
use crate::entities::AuthTypePB;
|
||||
use crate::errors::ErrorCode;
|
||||
use crate::services::entities::HistoricalUser;
|
||||
@ -217,10 +220,11 @@ impl From<Vec<UserWorkspace>> for RepeatedUserWorkspacePB {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default, Debug, Clone)]
|
||||
#[derive(ProtoBuf, Default, Debug, Clone, Validate)]
|
||||
pub struct UserWorkspacePB {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
#[validate(custom = "required_not_empty_str")]
|
||||
pub workspace_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub name: String,
|
||||
@ -229,7 +233,7 @@ pub struct UserWorkspacePB {
|
||||
impl From<UserWorkspace> for UserWorkspacePB {
|
||||
fn from(value: UserWorkspace) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
workspace_id: value.id,
|
||||
name: value.name,
|
||||
}
|
||||
}
|
||||
|
@ -103,3 +103,10 @@ impl From<Role> for AFRolePB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default, Clone, Validate)]
|
||||
pub struct UserWorkspaceIdPB {
|
||||
#[pb(index = 1)]
|
||||
#[validate(custom = "required_not_empty_str")]
|
||||
pub workspace_id: String,
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ use std::sync::Weak;
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
|
||||
use serde_json::Value;
|
||||
use tracing::event;
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_sqlite::kv::StorePreferences;
|
||||
@ -105,17 +104,11 @@ pub async fn get_user_profile_handler(
|
||||
user_profile.email = "".to_string();
|
||||
}
|
||||
|
||||
event!(
|
||||
tracing::Level::DEBUG,
|
||||
"Get user profile: {:?}",
|
||||
user_profile
|
||||
);
|
||||
|
||||
data_result_ok(user_profile.into())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(manager))]
|
||||
pub async fn sign_out(manager: AFPluginState<Weak<UserManager>>) -> Result<(), FlowyError> {
|
||||
pub async fn sign_out_handler(manager: AFPluginState<Weak<UserManager>>) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
manager.sign_out().await?;
|
||||
Ok(())
|
||||
@ -425,7 +418,7 @@ pub async fn get_cloud_config_handler(
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(manager), err)]
|
||||
pub async fn get_all_user_workspace_handler(
|
||||
pub async fn get_all_workspace_handler(
|
||||
manager: AFPluginState<Weak<UserManager>>,
|
||||
) -> DataResult<RepeatedUserWorkspacePB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
@ -436,12 +429,12 @@ pub async fn get_all_user_workspace_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub async fn open_workspace_handler(
|
||||
data: AFPluginData<UserWorkspacePB>,
|
||||
data: AFPluginData<UserWorkspaceIdPB>,
|
||||
manager: AFPluginState<Weak<UserManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.into_inner();
|
||||
manager.open_workspace(¶ms.id).await?;
|
||||
let params = data.validate()?.into_inner();
|
||||
manager.open_workspace(¶ms.workspace_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
||||
.event(UserEvent::SignUp, sign_up)
|
||||
.event(UserEvent::InitUser, init_user_handler)
|
||||
.event(UserEvent::GetUserProfile, get_user_profile_handler)
|
||||
.event(UserEvent::SignOut, sign_out)
|
||||
.event(UserEvent::SignOut, sign_out_handler)
|
||||
.event(UserEvent::UpdateUserProfile, update_user_profile_handler)
|
||||
.event(UserEvent::SetAppearanceSetting, set_appearance_setting)
|
||||
.event(UserEvent::GetAppearanceSetting, get_appearance_setting)
|
||||
@ -41,7 +41,7 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
||||
.event(UserEvent::OauthSignIn, oauth_handler)
|
||||
.event(UserEvent::GetSignInURL, get_sign_in_url_handler)
|
||||
.event(UserEvent::GetOauthURLWithProvider, sign_in_with_provider_handler)
|
||||
.event(UserEvent::GetAllUserWorkspaces, get_all_user_workspace_handler)
|
||||
.event(UserEvent::GetAllWorkspace, get_all_workspace_handler)
|
||||
.event(UserEvent::OpenWorkspace, open_workspace_handler)
|
||||
.event(UserEvent::UpdateNetworkState, update_network_state_handler)
|
||||
.event(UserEvent::GetHistoricalUsers, get_historical_users_handler)
|
||||
@ -60,7 +60,7 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
||||
.event(UserEvent::AddWorkspaceMember, add_workspace_member_handler)
|
||||
.event(UserEvent::RemoveWorkspaceMember, delete_workspace_member_handler)
|
||||
.event(UserEvent::GetWorkspaceMember, get_workspace_member_handler)
|
||||
.event(UserEvent::UpdateWorkspaceMember, update_workspace_member_handler,)
|
||||
.event(UserEvent::UpdateWorkspaceMember, update_workspace_member_handler)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
||||
@ -129,10 +129,10 @@ pub enum UserEvent {
|
||||
CheckEncryptionSign = 16,
|
||||
|
||||
/// Return the all the workspaces of the user
|
||||
#[event()]
|
||||
GetAllUserWorkspaces = 20,
|
||||
#[event(output = "RepeatedUserWorkspacePB")]
|
||||
GetAllWorkspace = 17,
|
||||
|
||||
#[event(input = "UserWorkspacePB")]
|
||||
#[event(input = "UserWorkspaceIdPB")]
|
||||
OpenWorkspace = 21,
|
||||
|
||||
#[event(input = "NetworkStatePB")]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::string::ToString;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use collab_user::core::MutexUserAwareness;
|
||||
@ -55,7 +56,7 @@ impl UserSessionConfig {
|
||||
}
|
||||
|
||||
pub struct UserManager {
|
||||
database: UserDB,
|
||||
database: Arc<UserDB>,
|
||||
session_config: UserSessionConfig,
|
||||
pub(crate) cloud_services: Arc<dyn UserCloudServiceProvider>,
|
||||
pub(crate) store_preferences: Arc<StorePreferences>,
|
||||
@ -64,7 +65,8 @@ pub struct UserManager {
|
||||
pub(crate) collab_builder: Weak<AppFlowyCollabBuilder>,
|
||||
pub(crate) collab_interact: RwLock<Arc<dyn CollabInteract>>,
|
||||
resumable_sign_up: Mutex<Option<ResumableSignUp>>,
|
||||
current_session: parking_lot::RwLock<Option<Session>>,
|
||||
current_session: Arc<parking_lot::RwLock<Option<Session>>>,
|
||||
refresh_user_profile_since: AtomicI64,
|
||||
}
|
||||
|
||||
impl UserManager {
|
||||
@ -74,10 +76,11 @@ impl UserManager {
|
||||
store_preferences: Arc<StorePreferences>,
|
||||
collab_builder: Weak<AppFlowyCollabBuilder>,
|
||||
) -> Arc<Self> {
|
||||
let database = UserDB::new(&session_config.root_dir);
|
||||
let database = Arc::new(UserDB::new(&session_config.root_dir));
|
||||
let user_status_callback: RwLock<Arc<dyn UserStatusCallback>> =
|
||||
RwLock::new(Arc::new(DefaultUserStatusCallback));
|
||||
|
||||
let refresh_user_profile_since = AtomicI64::new(0);
|
||||
let user_manager = Arc::new(Self {
|
||||
database,
|
||||
session_config,
|
||||
@ -89,6 +92,7 @@ impl UserManager {
|
||||
collab_interact: RwLock::new(Arc::new(DefaultCollabInteract)),
|
||||
resumable_sign_up: Default::default(),
|
||||
current_session: Default::default(),
|
||||
refresh_user_profile_since,
|
||||
});
|
||||
|
||||
let weak_user_manager = Arc::downgrade(&user_manager);
|
||||
@ -120,13 +124,28 @@ impl UserManager {
|
||||
/// a local data migration for the user. After ensuring the user's data is migrated and up-to-date,
|
||||
/// the function will set up the collaboration configuration and initialize the user's awareness. Upon successful
|
||||
/// completion, a user status callback is invoked to signify that the initialization process is complete.
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub async fn init<C: UserStatusCallback + 'static, I: CollabInteract>(
|
||||
&self,
|
||||
user_status_callback: C,
|
||||
collab_interact: I,
|
||||
) -> Result<(), FlowyError> {
|
||||
let user_status_callback = Arc::new(user_status_callback);
|
||||
*self.user_status_callback.write().await = user_status_callback.clone();
|
||||
*self.collab_interact.write().await = Arc::new(collab_interact);
|
||||
|
||||
if let Ok(session) = self.get_session() {
|
||||
let user = self.get_user_profile(session.user_id).await?;
|
||||
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"init user session: {}:{}",
|
||||
user.uid,
|
||||
user.email
|
||||
);
|
||||
|
||||
// Set the token if the current cloud service using token to authenticate
|
||||
// Currently, only the AppFlowy cloud using token to init the client api.
|
||||
if let Err(err) = self.cloud_services.set_token(&user.token) {
|
||||
error!("Set token failed: {}", err);
|
||||
}
|
||||
@ -134,10 +153,13 @@ impl UserManager {
|
||||
// Subscribe the token state
|
||||
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
|
||||
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
|
||||
event!(tracing::Level::DEBUG, "Listen token state change");
|
||||
af_spawn(async move {
|
||||
while let Some(token_state) = token_state_rx.next().await {
|
||||
debug!("Token state changed: {:?}", token_state);
|
||||
match token_state {
|
||||
UserTokenState::Refresh { token } => {
|
||||
// Only save the token if the token is different from the current token
|
||||
if token != user.token {
|
||||
if let Some(pool) = weak_pool.upgrade() {
|
||||
// Save the new token
|
||||
@ -147,19 +169,14 @@ impl UserManager {
|
||||
}
|
||||
}
|
||||
},
|
||||
UserTokenState::Invalid => {
|
||||
send_auth_state_notification(AuthStateChangedPB {
|
||||
state: AuthStatePB::InvalidAuth,
|
||||
message: "Token is invalid".to_string(),
|
||||
})
|
||||
.send();
|
||||
},
|
||||
UserTokenState::Invalid => {},
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Do the user data migration if needed
|
||||
event!(tracing::Level::INFO, "Prepare user data migration");
|
||||
match (
|
||||
self.database.get_collab_db(session.user_id),
|
||||
self.database.get_pool(session.user_id),
|
||||
@ -202,8 +219,6 @@ impl UserManager {
|
||||
error!("Failed to call did_init callback: {:?}", e);
|
||||
}
|
||||
}
|
||||
*self.user_status_callback.write().await = Arc::new(user_status_callback);
|
||||
*self.collab_interact.write().await = Arc::new(collab_interact);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -380,6 +395,7 @@ impl UserManager {
|
||||
self
|
||||
.save_auth_data(&response, auth_type, &new_session)
|
||||
.await?;
|
||||
|
||||
self
|
||||
.user_status_callback
|
||||
.read()
|
||||
@ -445,14 +461,28 @@ impl UserManager {
|
||||
pub async fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> {
|
||||
let user: UserProfile = user_table::dsl::user_table
|
||||
.filter(user_table::id.eq(&uid.to_string()))
|
||||
.first::<UserTable>(&*(self.db_connection(uid)?))?
|
||||
.first::<UserTable>(&*(self.db_connection(uid)?))
|
||||
.map_err(|err| {
|
||||
FlowyError::record_not_found().with_context(format!(
|
||||
"Can't find the user profile for user id: {}, error: {:?}",
|
||||
uid, err
|
||||
))
|
||||
})?
|
||||
.into();
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
#[tracing::instrument(level = "info", skip_all, err)]
|
||||
pub async fn refresh_user_profile(&self, old_user_profile: &UserProfile) -> FlowyResult<()> {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
|
||||
// Add debounce to avoid too many requests
|
||||
if now - self.refresh_user_profile_since.load(Ordering::SeqCst) < 5 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.refresh_user_profile_since.store(now, Ordering::SeqCst);
|
||||
let uid = old_user_profile.uid;
|
||||
let result: Result<UserProfile, FlowyError> = self
|
||||
.cloud_services
|
||||
@ -494,12 +524,12 @@ impl UserManager {
|
||||
},
|
||||
Err(err) => {
|
||||
// If the user is not found, notify the frontend to logout
|
||||
if err.is_record_not_found() {
|
||||
if err.is_unauthorized() {
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"User is not found on the server when refreshing profile"
|
||||
tracing::Level::ERROR,
|
||||
"User is unauthorized, sign out the user"
|
||||
);
|
||||
|
||||
self.sign_out().await?;
|
||||
send_auth_state_notification(AuthStateChangedPB {
|
||||
state: AuthStatePB::InvalidAuth,
|
||||
message: "User is not found on the server".to_string(),
|
||||
@ -641,6 +671,7 @@ impl UserManager {
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all, err)]
|
||||
async fn save_auth_data(
|
||||
&self,
|
||||
response: &impl UserAuthResponse,
|
||||
|
@ -5,11 +5,13 @@ use collab::core::origin::{CollabClient, CollabOrigin};
|
||||
use collab_document::document::Document;
|
||||
use collab_document::document_data::default_document_data;
|
||||
use collab_folder::Folder;
|
||||
use tracing::{event, instrument};
|
||||
|
||||
use collab_integrate::{RocksCollabDB, YrsDocAction};
|
||||
use flowy_error::{internal_error, FlowyResult};
|
||||
|
||||
use crate::migrations::migration::UserDataMigration;
|
||||
use crate::migrations::util::load_collab;
|
||||
use crate::services::entities::Session;
|
||||
|
||||
/// Migrate the first level documents of the workspace by inserting documents
|
||||
@ -20,39 +22,42 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration {
|
||||
"historical_empty_document"
|
||||
}
|
||||
|
||||
#[instrument(name = "HistoricalEmptyDocumentMigration", skip_all, err)]
|
||||
fn run(&self, session: &Session, collab_db: &Arc<RocksCollabDB>) -> FlowyResult<()> {
|
||||
let write_txn = collab_db.write_txn();
|
||||
if let Ok(updates) = write_txn.get_all_updates(session.user_id, &session.user_workspace.id) {
|
||||
let origin = CollabOrigin::Client(CollabClient::new(session.user_id, "phantom"));
|
||||
// Deserialize the folder from the raw data
|
||||
let folder = Folder::from_collab_raw_data(
|
||||
session.user_id,
|
||||
origin.clone(),
|
||||
updates,
|
||||
&session.user_workspace.id,
|
||||
vec![],
|
||||
)?;
|
||||
let origin = CollabOrigin::Client(CollabClient::new(session.user_id, "phantom"));
|
||||
// Deserialize the folder from the raw data
|
||||
if let Ok(folder_collab) = load_collab(session.user_id, &write_txn, &session.user_workspace.id)
|
||||
{
|
||||
let folder = Folder::open(session.user_id, folder_collab, None)?;
|
||||
|
||||
// Migration the first level documents of the workspace
|
||||
// Migration the first level documents of the workspace. The first level documents do not have
|
||||
// any updates. So when calling load_collab, it will return error.
|
||||
let migration_views = folder.get_workspace_views(&session.user_workspace.id);
|
||||
for view in migration_views {
|
||||
// Read all updates of the view
|
||||
if let Ok(view_updates) = write_txn.get_all_updates(session.user_id, &view.id) {
|
||||
if Document::from_updates(origin.clone(), view_updates, &view.id, vec![]).is_err() {
|
||||
// Create a document with default data
|
||||
let document_data = default_document_data();
|
||||
let collab = Arc::new(MutexCollab::new(origin.clone(), &view.id, vec![]));
|
||||
if let Ok(document) = Document::create_with_data(collab.clone(), document_data) {
|
||||
// Remove all old updates and then insert the new update
|
||||
let (doc_state, sv) = document.get_collab().encode_as_update_v1();
|
||||
write_txn
|
||||
.flush_doc_with(session.user_id, &view.id, &doc_state, &sv)
|
||||
.map_err(internal_error)?;
|
||||
if load_collab(session.user_id, &write_txn, &view.id).is_err() {
|
||||
// Create a document with default data
|
||||
let document_data = default_document_data();
|
||||
let collab = Arc::new(MutexCollab::new(origin.clone(), &view.id, vec![]));
|
||||
if let Ok(document) = Document::create_with_data(collab.clone(), document_data) {
|
||||
// Remove all old updates and then insert the new update
|
||||
let (doc_state, sv) = document.get_collab().encode_as_update_v1();
|
||||
if let Err(err) = write_txn.flush_doc_with(session.user_id, &view.id, &doc_state, &sv) {
|
||||
event!(
|
||||
tracing::Level::ERROR,
|
||||
"Failed to migrate document {}, error: {}",
|
||||
view.id,
|
||||
err
|
||||
);
|
||||
} else {
|
||||
event!(tracing::Level::INFO, "Did migrate document {}", view.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event!(tracing::Level::INFO, "Save all migrated documents");
|
||||
write_txn.commit_transaction().map_err(internal_error)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ use std::sync::Arc;
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::{RunQueryDsl, SqliteConnection};
|
||||
use tracing::event;
|
||||
|
||||
use collab_integrate::RocksCollabDB;
|
||||
use flowy_error::FlowyResult;
|
||||
@ -55,12 +54,6 @@ impl UserLocalDataMigration {
|
||||
{
|
||||
let migration_name = migration.name().to_string();
|
||||
if !duplicated_names.contains(&migration_name) {
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"Running migration {}",
|
||||
migration.name()
|
||||
);
|
||||
|
||||
migration.run(&self.session, &self.collab_db)?;
|
||||
applied_migrations.push(migration.name().to_string());
|
||||
save_record(&conn, &migration_name);
|
||||
|
@ -3,4 +3,5 @@ pub use define::*;
|
||||
mod define;
|
||||
pub mod document_empty_content;
|
||||
pub mod migration;
|
||||
mod util;
|
||||
pub mod workspace_and_favorite_v1;
|
||||
|
23
frontend/rust-lib/flowy-user/src/migrations/util.rs
Normal file
23
frontend/rust-lib/flowy-user/src/migrations/util.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab::preclude::Collab;
|
||||
|
||||
use collab_integrate::{PersistenceError, YrsDocAction};
|
||||
use flowy_error::{internal_error, FlowyResult};
|
||||
|
||||
pub fn load_collab<'a, R>(
|
||||
uid: i64,
|
||||
collab_r_txn: &R,
|
||||
object_id: &str,
|
||||
) -> FlowyResult<Arc<MutexCollab>>
|
||||
where
|
||||
R: YrsDocAction<'a>,
|
||||
PersistenceError: From<R::Error>,
|
||||
{
|
||||
let collab = Collab::new(uid, object_id, "phantom", vec![]);
|
||||
collab
|
||||
.with_origin_transact_mut(|txn| collab_r_txn.load_doc_with_txn(uid, &object_id, txn))
|
||||
.map_err(internal_error)?;
|
||||
Ok(Arc::new(MutexCollab::from_collab(collab)))
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab::core::origin::{CollabClient, CollabOrigin};
|
||||
use collab_folder::Folder;
|
||||
use tracing::instrument;
|
||||
|
||||
use collab_integrate::{RocksCollabDB, YrsDocAction};
|
||||
use flowy_error::{internal_error, FlowyResult};
|
||||
|
||||
use crate::migrations::migration::UserDataMigration;
|
||||
use crate::migrations::util::load_collab;
|
||||
use crate::services::entities::Session;
|
||||
|
||||
/// 1. Migrate the workspace: { favorite: [view_id] } to { favorite: { uid: [view_id] } }
|
||||
@ -19,19 +20,11 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration {
|
||||
"workspace_favorite_v1_and_workspace_array_migration"
|
||||
}
|
||||
|
||||
#[instrument(name = "FavoriteV1AndWorkspaceArrayMigration", skip_all, err)]
|
||||
fn run(&self, session: &Session, collab_db: &Arc<RocksCollabDB>) -> FlowyResult<()> {
|
||||
let write_txn = collab_db.write_txn();
|
||||
if let Ok(updates) = write_txn.get_all_updates(session.user_id, &session.user_workspace.id) {
|
||||
let origin = CollabOrigin::Client(CollabClient::new(session.user_id, "phantom"));
|
||||
// Deserialize the folder from the raw data
|
||||
let folder = Folder::from_collab_raw_data(
|
||||
session.user_id,
|
||||
origin,
|
||||
updates,
|
||||
&session.user_workspace.id,
|
||||
vec![],
|
||||
)?;
|
||||
|
||||
if let Ok(collab) = load_collab(session.user_id, &write_txn, &session.user_workspace.id) {
|
||||
let folder = Folder::open(session.user_id, collab, None)?;
|
||||
folder.migrate_workspace_to_view();
|
||||
|
||||
let favorite_view_ids = folder
|
||||
@ -48,8 +41,9 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration {
|
||||
write_txn
|
||||
.flush_doc_with(session.user_id, &session.user_workspace.id, &doc_state, &sv)
|
||||
.map_err(internal_error)?;
|
||||
write_txn.commit_transaction().map_err(internal_error)?;
|
||||
}
|
||||
|
||||
write_txn.commit_transaction().map_err(internal_error)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_entity::{CollabObject, CollabType};
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sqlite::schema::user_workspace_table;
|
||||
@ -15,8 +16,14 @@ use crate::notification::{send_notification, UserNotification};
|
||||
use crate::services::user_workspace_sql::UserWorkspaceTable;
|
||||
|
||||
impl UserManager {
|
||||
#[instrument(skip(self), err)]
|
||||
pub async fn open_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||
let uid = self.user_id()?;
|
||||
let _ = self
|
||||
.cloud_services
|
||||
.get_user_service()?
|
||||
.open_workspace(workspace_id)
|
||||
.await;
|
||||
if let Some(user_workspace) = self.get_user_workspace(uid, workspace_id) {
|
||||
if let Err(err) = self
|
||||
.user_status_callback
|
||||
@ -25,7 +32,7 @@ impl UserManager {
|
||||
.open_workspace(uid, &user_workspace)
|
||||
.await
|
||||
{
|
||||
tracing::error!("Open workspace failed: {:?}", err);
|
||||
error!("Open workspace failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -101,7 +108,7 @@ impl UserManager {
|
||||
if let Ok(service) = self.cloud_services.get_user_service() {
|
||||
if let Ok(pool) = self.db_pool(uid) {
|
||||
af_spawn(async move {
|
||||
if let Ok(new_user_workspaces) = service.get_all_user_workspaces(uid).await {
|
||||
if let Ok(new_user_workspaces) = service.get_all_workspace(uid).await {
|
||||
let _ = save_user_workspaces(uid, pool, &new_user_workspaces);
|
||||
let repeated_workspace_pbs = RepeatedUserWorkspacePB::from(new_user_workspaces);
|
||||
send_notification(&uid.to_string(), UserNotification::DidUpdateUserWorkspaces)
|
||||
|
@ -7,7 +7,6 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
tracing-log = { version = "0.2"}
|
||||
tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter", "ansi", "json"] }
|
||||
tracing-bunyan-formatter = "0.3.9"
|
||||
tracing-appender = "0.2.2"
|
||||
|
@ -1,9 +1,11 @@
|
||||
use std::sync::RwLock;
|
||||
|
||||
use chrono::Local;
|
||||
use lazy_static::lazy_static;
|
||||
use tracing::subscriber::set_global_default;
|
||||
use tracing_appender::{non_blocking::WorkerGuard, rolling::RollingFileAppender};
|
||||
use tracing_bunyan_formatter::JsonStorageLayer;
|
||||
use tracing_subscriber::fmt::format::Writer;
|
||||
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
|
||||
|
||||
use crate::layer::FlowyFormattingLayer;
|
||||
@ -43,12 +45,12 @@ impl Builder {
|
||||
|
||||
let (non_blocking, guard) = tracing_appender::non_blocking(self.file_appender);
|
||||
let subscriber = tracing_subscriber::fmt()
|
||||
.with_timer(CustomTime)
|
||||
.with_ansi(true)
|
||||
.with_target(true)
|
||||
.with_target(false)
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
.with_thread_ids(false)
|
||||
.with_file(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.with_writer(std::io::stdout)
|
||||
.pretty()
|
||||
.with_env_filter(env_filter)
|
||||
.finish()
|
||||
@ -56,7 +58,15 @@ impl Builder {
|
||||
.with(FlowyFormattingLayer::new(non_blocking));
|
||||
|
||||
set_global_default(subscriber).map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
*LOG_GUARD.write().unwrap() = Some(guard);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomTime;
|
||||
impl tracing_subscriber::fmt::time::FormatTime for CustomTime {
|
||||
fn format_time(&self, w: &mut Writer<'_>) -> std::fmt::Result {
|
||||
write!(w, "{}", Local::now().format("%Y-%m-%d %H:%M:%S"))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user