mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: adding suffix for user data folder when current cloud type is appflowy cloud (#3918)
* fix: load database fail caused by spawning long run task * chore: yield long run task * chore: fmt * chore: update client api * feat: copy data between server * ci: fix af cloud test
This commit is contained in:
parent
3c7e636b65
commit
7eb20b232a
8
frontend/.vscode/tasks.json
vendored
8
frontend/.vscode/tasks.json
vendored
@ -314,13 +314,5 @@
|
||||
"cwd": "${workspaceFolder}/appflowy_flutter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "AF: Generate AppFlowyEnv",
|
||||
"type": "shell",
|
||||
"command": "dart run build_runner build --delete-conflicting-outputs",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/appflowy_flutter/packages/appflowy_backend"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -21,13 +21,21 @@ CLOUD_TYPE=0
|
||||
|
||||
# Supabase Configuration
|
||||
# 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
|
||||
SUPABASE_URL=
|
||||
SUPABASE_ANON_KEY=
|
||||
|
||||
# AppFlowy Cloud Configuration
|
||||
# If using AppFlowy Cloud (CLOUD_TYPE=2), provide the following details:
|
||||
APPFLOWY_CLOUD_BASE_URL=https://xxxxxxxxx
|
||||
APPFLOWY_CLOUD_WS_BASE_URL=wss://xxxxxxxxx
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=https://xxxxxxxxx
|
||||
|
||||
# For instance:
|
||||
# APPFLOWY_CLOUD_BASE_URL=https://xxxxxxxxx
|
||||
# APPFLOWY_CLOUD_WS_BASE_URL=wss://xxxxxxxxx
|
||||
# APPFLOWY_CLOUD_GOTRUE_URL=https://xxxxxxxxx
|
||||
#
|
||||
# Local host machine(For local develop)
|
||||
# APPFLOWY_CLOUD_BASE_URL=http://localhost:8000
|
||||
# APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws
|
||||
# APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998
|
||||
|
||||
APPFLOWY_CLOUD_BASE_URL=
|
||||
APPFLOWY_CLOUD_WS_BASE_URL=
|
||||
APPFLOWY_CLOUD_GOTRUE_URL=
|
||||
|
14
frontend/appflowy_flutter/lib/env/env.dart
vendored
14
frontend/appflowy_flutter/lib/env/env.dart
vendored
@ -101,7 +101,10 @@ CloudType currentCloudType() {
|
||||
final value = Env.cloudType;
|
||||
if (value == 1) {
|
||||
if (Env.supabaseUrl.isEmpty || Env.supabaseAnonKey.isEmpty) {
|
||||
Log.error("Supabase is not configured");
|
||||
Log.error(
|
||||
"Supabase is not configured correctly. The values are: "
|
||||
"url: ${Env.supabaseUrl}, anonKey: ${Env.supabaseAnonKey}",
|
||||
);
|
||||
return CloudType.unknown;
|
||||
} else {
|
||||
return CloudType.supabase;
|
||||
@ -109,8 +112,13 @@ CloudType currentCloudType() {
|
||||
}
|
||||
|
||||
if (value == 2) {
|
||||
if (Env.afCloudBaseUrl.isEmpty || Env.afCloudWSBaseUrl.isEmpty) {
|
||||
Log.error("AppFlowy cloud is not configured");
|
||||
if (Env.afCloudBaseUrl.isEmpty ||
|
||||
Env.afCloudWSBaseUrl.isEmpty ||
|
||||
Env.afCloudGoTrueUrl.isEmpty) {
|
||||
Log.error(
|
||||
"AppFlowy cloud is not configured correctly. The values are: "
|
||||
"baseUrl: ${Env.afCloudBaseUrl}, wsBaseUrl: ${Env.afCloudWSBaseUrl}, gotrueUrl: ${Env.afCloudGoTrueUrl}",
|
||||
);
|
||||
return CloudType.unknown;
|
||||
} else {
|
||||
return CloudType.appflowyCloud;
|
||||
|
@ -26,9 +26,7 @@ class InitRustSDKTask extends LaunchTask {
|
||||
|
||||
// Pass the environment variables to the Rust SDK
|
||||
final env = getAppFlowyEnv();
|
||||
context.getIt<FlowySDK>().setEnv(jsonEncode(env.toJson()));
|
||||
|
||||
await context.getIt<FlowySDK>().init(dir);
|
||||
await context.getIt<FlowySDK>().init(dir, jsonEncode(env.toJson()));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -27,15 +27,12 @@ class FlowySDK {
|
||||
|
||||
void dispose() {}
|
||||
|
||||
Future<void> init(Directory sdkDir) async {
|
||||
Future<void> init(Directory sdkDir, String env) async {
|
||||
final port = RustStreamReceiver.shared.port;
|
||||
ffi.set_stream_port(port);
|
||||
|
||||
ffi.store_dart_post_cobject(NativeApi.postCObject);
|
||||
ffi.set_env(env.toNativeUtf8());
|
||||
ffi.init_sdk(sdkDir.path.toNativeUtf8());
|
||||
}
|
||||
|
||||
void setEnv(String envStr) {
|
||||
ffi.set_env(envStr.toNativeUtf8());
|
||||
}
|
||||
}
|
||||
|
89
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
89
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -138,7 +138,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -195,7 +195,7 @@ checksum = "7150fb5d9cc4eb0184af43ce75a89620dc3747d3c816e8b0ba200682d0155c05"
|
||||
dependencies = [
|
||||
"async-convert",
|
||||
"backoff",
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"derive_builder",
|
||||
"futures",
|
||||
"rand 0.8.5",
|
||||
@ -365,9 +365,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
@ -460,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]]
|
||||
@ -768,7 +768,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -863,7 +863,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -883,11 +883,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-derive",
|
||||
@ -913,7 +913,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -925,7 +925,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -945,7 +945,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -959,7 +959,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -1001,8 +1001,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1022,7 +1023,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1049,7 +1050,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1302,7 +1303,7 @@ dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa 1.0.6",
|
||||
"phf 0.11.2",
|
||||
"phf 0.8.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@ -1448,7 +1449,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -1932,6 +1933,7 @@ name = "flowy-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"client-api",
|
||||
"collab",
|
||||
@ -1969,6 +1971,7 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2107,7 +2110,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"rand 0.8.5",
|
||||
@ -2298,7 +2301,7 @@ name = "flowy-user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
@ -2804,7 +2807,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2820,7 +2823,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -3256,7 +3259,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -3408,7 +3411,7 @@ version = "8.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde",
|
||||
@ -4338,7 +4341,6 @@ version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_macros 0.11.2",
|
||||
"phf_shared 0.11.2",
|
||||
]
|
||||
|
||||
@ -4430,19 +4432,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||
dependencies = [
|
||||
"phf_generator 0.11.2",
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
@ -4515,7 +4504,7 @@ version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"indexmap 1.9.3",
|
||||
"line-wrap",
|
||||
"quick-xml 0.28.2",
|
||||
@ -4554,7 +4543,7 @@ version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
@ -4684,7 +4673,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck 0.4.1",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@ -4705,7 +4694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
@ -5000,7 +4989,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "realtime-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -5097,7 +5086,7 @@ version = "0.11.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
@ -5344,7 +5333,7 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5641,7 +5630,7 @@ version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
@ -5744,7 +5733,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared_entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -6309,7 +6298,7 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54ad2d49fdeab4a08717f5b49a163bdc72efc3b1950b6758245fcde79b645e1a"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"base64 0.21.5",
|
||||
"brotli",
|
||||
"ico",
|
||||
"json-patch",
|
||||
@ -7141,9 +7130,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.3"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
|
@ -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 = "d37fbbf486dc44336c87acd59cf8b6feff57b330" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0873b582d61d787e20c6a7193fdcbad2ea90de0e" }
|
||||
# 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 = "d37
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
|
||||
|
||||
|
||||
|
129
frontend/rust-lib/Cargo.lock
generated
129
frontend/rust-lib/Cargo.lock
generated
@ -124,7 +124,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -175,7 +175,7 @@ checksum = "7150fb5d9cc4eb0184af43ce75a89620dc3747d3c816e8b0ba200682d0155c05"
|
||||
dependencies = [
|
||||
"async-convert",
|
||||
"backoff",
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"derive_builder",
|
||||
"futures",
|
||||
"rand 0.8.5",
|
||||
@ -372,9 +372,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.3"
|
||||
version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@ -666,7 +666,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -683,7 +683,7 @@ dependencies = [
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"parking_lot",
|
||||
"prost 0.12.1",
|
||||
"prost",
|
||||
"realtime-entity",
|
||||
"reqwest",
|
||||
"scraper 0.17.1",
|
||||
@ -730,7 +730,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -750,11 +750,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-derive",
|
||||
@ -780,7 +780,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -792,7 +792,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -812,7 +812,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -826,7 +826,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -868,8 +868,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -889,7 +890,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -916,7 +917,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6e30a5b9#6e30a5b9415dc934c845047730a3df6988b864ba"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=27575c570b3a6975d2efb577367a9c56cbf5a6e1#27575c570b3a6975d2efb577367a9c56cbf5a6e1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -958,29 +959,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e"
|
||||
checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787"
|
||||
dependencies = [
|
||||
"prost 0.11.9",
|
||||
"prost-types 0.11.9",
|
||||
"futures-core",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tonic",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-subscriber"
|
||||
version = "0.1.10"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4cf42660ac07fcebed809cfe561dd8730bcd35b075215e6479c516bcd0d11cb"
|
||||
checksum = "7481d4c57092cd1c19dd541b92bdce883de840df30aa5d03fd48a3935c01842e"
|
||||
dependencies = [
|
||||
"console-api",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-utils",
|
||||
"futures",
|
||||
"futures-task",
|
||||
"hdrhistogram",
|
||||
"humantime",
|
||||
"prost-types 0.11.9",
|
||||
"prost-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thread_local",
|
||||
@ -1275,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -1751,6 +1753,7 @@ name = "flowy-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"client-api",
|
||||
"collab",
|
||||
@ -1789,6 +1792,7 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1930,7 +1934,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"hmac",
|
||||
"pbkdf2 0.12.2",
|
||||
"rand 0.8.5",
|
||||
@ -2130,7 +2134,7 @@ name = "flowy-user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
@ -2463,7 +2467,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2479,7 +2483,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2840,7 +2844,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -2920,7 +2924,7 @@ version = "8.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde",
|
||||
@ -3838,7 +3842,7 @@ version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
@ -3940,16 +3944,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.11.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.12.1"
|
||||
@ -3957,7 +3951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.12.1",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3974,27 +3968,14 @@ dependencies = [
|
||||
"once_cell",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost 0.12.1",
|
||||
"prost-types 0.12.1",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn 2.0.31",
|
||||
"tempfile",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.12.1"
|
||||
@ -4008,22 +3989,13 @@ dependencies = [
|
||||
"syn 2.0.31",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13"
|
||||
dependencies = [
|
||||
"prost 0.11.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf"
|
||||
dependencies = [
|
||||
"prost 0.12.1",
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4350,14 +4322,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "realtime-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-entity",
|
||||
"prost 0.12.1",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"protoc-bin-vendored",
|
||||
"serde",
|
||||
@ -4468,7 +4440,7 @@ version = "0.11.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
@ -4703,7 +4675,7 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4993,7 +4965,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared_entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d37fbbf486dc44336c87acd59cf8b6feff57b330#d37fbbf486dc44336c87acd59cf8b6feff57b330"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0873b582d61d787e20c6a7193fdcbad2ea90de0e#0873b582d61d787e20c6a7193fdcbad2ea90de0e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -5650,16 +5622,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.9.2"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
|
||||
checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.21.3",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
@ -5667,7 +5638,7 @@ dependencies = [
|
||||
"hyper-timeout",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost 0.11.9",
|
||||
"prost",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
|
@ -83,7 +83,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 = "d37fbbf486dc44336c87acd59cf8b6feff57b330" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0873b582d61d787e20c6a7193fdcbad2ea90de0e" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -93,11 +93,11 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d37
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6e30a5b9" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "27575c570b3a6975d2efb577367a9c56cbf5a6e1" }
|
||||
|
@ -195,6 +195,8 @@ impl AppFlowyCollabBuilder {
|
||||
{
|
||||
let cloud_storage_type = self.cloud_storage.read().await.storage_source();
|
||||
let collab_object = self.collab_object(uid, object_id, object_type)?;
|
||||
let span = tracing::span!(tracing::Level::TRACE, "collab_builder", object_id = %object_id);
|
||||
let _enter = span.enter();
|
||||
match cloud_storage_type {
|
||||
CollabSource::AFCloud => {
|
||||
#[cfg(feature = "appflowy_cloud_integrate")]
|
||||
@ -259,6 +261,7 @@ impl AppFlowyCollabBuilder {
|
||||
}
|
||||
|
||||
collab.lock().initialize();
|
||||
trace!("collab initialized: {}", object_id);
|
||||
Ok(collab)
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ tracing = { version = "0.1", features = ["log"] }
|
||||
|
||||
# workspace
|
||||
lib-dispatch = { workspace = true }
|
||||
#flowy-core = { workspace = true, features = ["profiling"] }
|
||||
flowy-core = { workspace = true }
|
||||
flowy-notification = { workspace = true }
|
||||
flowy-server = { workspace = true }
|
||||
flowy-server-config = { workspace = true }
|
||||
flowy-server-config = { workspace = true}
|
||||
collab-integrate = { workspace = true }
|
||||
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct AppFlowyEnv {
|
||||
impl AppFlowyEnv {
|
||||
/// Parse the environment variable from the frontend application. The frontend will
|
||||
/// pass the environment variable as a json string after launching.
|
||||
pub fn parser(env_str: &str) {
|
||||
pub fn write_env_from(env_str: &str) {
|
||||
if let Ok(env) = serde_json::from_str::<AppFlowyEnv>(env_str) {
|
||||
env.supabase_config.write_env();
|
||||
env.appflowy_cloud_config.write_env();
|
||||
|
@ -163,5 +163,5 @@ pub extern "C" fn backend_log(level: i64, data: *const c_char) {
|
||||
pub extern "C" fn set_env(data: *const c_char) {
|
||||
let c_str = unsafe { CStr::from_ptr(data) };
|
||||
let serde_str = c_str.to_str().unwrap();
|
||||
AppFlowyEnv::parser(serde_str);
|
||||
AppFlowyEnv::write_env_from(serde_str);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ async fn update_group_name_test() {
|
||||
assert_eq!(groups.len(), 4);
|
||||
assert_eq!(groups[1].group_name, "To Do");
|
||||
assert_eq!(groups[2].group_name, "Doing");
|
||||
assert_eq!(groups[3].group_name, "Done");
|
||||
|
||||
test
|
||||
.update_group(
|
||||
|
@ -28,7 +28,7 @@ use flowy_user::errors::FlowyError;
|
||||
use flowy_user::event_map::UserCloudServiceProvider;
|
||||
use flowy_user::event_map::UserEvent::*;
|
||||
use flowy_user_deps::cloud::UserCloudService;
|
||||
use flowy_user_deps::entities::AuthType;
|
||||
use flowy_user_deps::entities::Authenticator;
|
||||
|
||||
pub fn get_supabase_config() -> Option<SupabaseConfiguration> {
|
||||
dotenv::from_path(".env.ci").ok()?;
|
||||
@ -44,7 +44,9 @@ impl FlowySupabaseTest {
|
||||
let _ = get_supabase_config()?;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.set_auth_type(AuthTypePB::Supabase);
|
||||
test.server_provider.set_auth_type(AuthType::Supabase);
|
||||
test
|
||||
.server_provider
|
||||
.set_authenticator(Authenticator::Supabase);
|
||||
|
||||
Some(Self { inner: test })
|
||||
}
|
||||
@ -209,7 +211,9 @@ impl AFCloudTest {
|
||||
let _ = get_af_cloud_config()?;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
test.set_auth_type(AuthTypePB::AFCloud);
|
||||
test.server_provider.set_auth_type(AuthType::AFCloud);
|
||||
test
|
||||
.server_provider
|
||||
.set_authenticator(Authenticator::AFCloud);
|
||||
|
||||
Some(Self { inner: test })
|
||||
}
|
||||
@ -227,6 +231,14 @@ pub fn generate_test_email() -> String {
|
||||
format!("{}@test.com", Uuid::new_v4())
|
||||
}
|
||||
|
||||
/// To run the test, create a .env.ci file in the 'event-integration' directory and set the following environment variables:
|
||||
///
|
||||
/// - `APPFLOWY_CLOUD_BASE_URL=http://localhost:8000`
|
||||
/// - `APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws`
|
||||
/// - `APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998`
|
||||
///
|
||||
/// - `GOTRUE_ADMIN_EMAIL=admin@example.com`
|
||||
/// - `GOTRUE_ADMIN_PASSWORD=password`
|
||||
pub fn get_af_cloud_config() -> Option<AFCloudConfiguration> {
|
||||
dotenv::from_filename("./.env.ci").ok()?;
|
||||
AFCloudConfiguration::from_env().ok()
|
||||
|
@ -38,15 +38,17 @@ futures-core = { version = "0.3", default-features = false }
|
||||
bytes = "1.5"
|
||||
tokio = { version = "1.26", features = ["full"] }
|
||||
tokio-stream = {version = "0.1.14", features = ["sync"]}
|
||||
console-subscriber = { version = "0.1.8", optional = true }
|
||||
console-subscriber = { version = "0.2", optional = true }
|
||||
parking_lot = "0.12.1"
|
||||
anyhow = "1.0.75"
|
||||
base64 = "0.21.5"
|
||||
|
||||
lib-infra = { path = "../../../shared-lib/lib-infra" }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_repr = "0.1"
|
||||
futures = "0.3.28"
|
||||
walkdir = "2.4.0"
|
||||
|
||||
[features]
|
||||
default = ["rev-sqlite"]
|
||||
|
@ -47,7 +47,7 @@ impl SnapshotPersistence for SnapshotDBImpl {
|
||||
{
|
||||
let conn = pool
|
||||
.get()
|
||||
.map_err(|e| PersistenceError::Internal(Box::new(e)))?;
|
||||
.map_err(|e| PersistenceError::Internal(e.into()))?;
|
||||
|
||||
let desc = match CollabSnapshotTableSql::get_latest_snapshot(&object_id, &conn) {
|
||||
None => Ok("".to_string()),
|
||||
@ -70,7 +70,7 @@ impl SnapshotPersistence for SnapshotDBImpl {
|
||||
},
|
||||
&conn,
|
||||
)
|
||||
.map_err(|e| PersistenceError::Internal(Box::new(e)));
|
||||
.map_err(|e| PersistenceError::Internal(e.into()));
|
||||
|
||||
if let Err(e) = result {
|
||||
tracing::warn!("create snapshot error: {:?}", e);
|
||||
|
@ -7,7 +7,7 @@ pub(crate) fn init_log(config: &AppFlowyCoreConfig) {
|
||||
if !INIT_LOG.load(Ordering::SeqCst) {
|
||||
INIT_LOG.store(true, Ordering::SeqCst);
|
||||
|
||||
let _ = lib_log::Builder::new("AppFlowy-Client", &config.storage_path)
|
||||
let _ = lib_log::Builder::new("log", &config.storage_path)
|
||||
.env_filter(&config.log_filter)
|
||||
.build();
|
||||
}
|
||||
|
@ -3,3 +3,4 @@ pub(crate) mod log;
|
||||
pub(crate) mod server;
|
||||
mod trait_impls;
|
||||
pub(crate) mod user;
|
||||
pub(crate) mod util;
|
||||
|
@ -46,7 +46,7 @@ impl Display for ServerType {
|
||||
}
|
||||
}
|
||||
|
||||
/// The [ServerProvider] provides list of [AppFlowyServer] base on the [AuthType]. Using
|
||||
/// The [ServerProvider] provides list of [AppFlowyServer] base on the [Authenticator]. Using
|
||||
/// the auth type, the [ServerProvider] will create a new [AppFlowyServer] if it doesn't
|
||||
/// exist.
|
||||
/// Each server implements the [AppFlowyServer] trait, which provides the [UserCloudService], etc.
|
||||
@ -66,13 +66,13 @@ pub struct ServerProvider {
|
||||
impl ServerProvider {
|
||||
pub fn new(
|
||||
config: AppFlowyCoreConfig,
|
||||
provider_type: ServerType,
|
||||
server_type: ServerType,
|
||||
store_preferences: Weak<StorePreferences>,
|
||||
) -> Self {
|
||||
let encryption = EncryptionImpl::new(None);
|
||||
Self {
|
||||
config,
|
||||
server_type: RwLock::new(provider_type),
|
||||
server_type: RwLock::new(server_type),
|
||||
device_id: Arc::new(RwLock::new(uuid::Uuid::new_v4().to_string())),
|
||||
providers: RwLock::new(HashMap::new()),
|
||||
enable_sync: RwLock::new(true),
|
||||
@ -115,7 +115,6 @@ impl ServerProvider {
|
||||
},
|
||||
ServerType::AFCloud => {
|
||||
let config = AFCloudConfiguration::from_env()?;
|
||||
tracing::trace!("🔑AppFlowy cloud config: {:?}", config);
|
||||
let server = Arc::new(AFCloudServer::new(
|
||||
config,
|
||||
*self.enable_sync.read(),
|
||||
@ -153,23 +152,32 @@ impl ServerProvider {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuthType> for ServerType {
|
||||
fn from(auth_provider: AuthType) -> Self {
|
||||
impl From<Authenticator> for ServerType {
|
||||
fn from(auth_provider: Authenticator) -> Self {
|
||||
match auth_provider {
|
||||
AuthType::Local => ServerType::Local,
|
||||
AuthType::AFCloud => ServerType::AFCloud,
|
||||
AuthType::Supabase => ServerType::Supabase,
|
||||
Authenticator::Local => ServerType::Local,
|
||||
Authenticator::AFCloud => ServerType::AFCloud,
|
||||
Authenticator::Supabase => ServerType::Supabase,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AuthType> for ServerType {
|
||||
fn from(auth_provider: &AuthType) -> Self {
|
||||
impl From<ServerType> for Authenticator {
|
||||
fn from(ty: ServerType) -> Self {
|
||||
match ty {
|
||||
ServerType::Local => Authenticator::Local,
|
||||
ServerType::AFCloud => Authenticator::AFCloud,
|
||||
ServerType::Supabase => Authenticator::Supabase,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<&Authenticator> for ServerType {
|
||||
fn from(auth_provider: &Authenticator) -> Self {
|
||||
Self::from(auth_provider.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_server_provider(store_preferences: &Arc<StorePreferences>) -> ServerType {
|
||||
pub fn current_server_type(store_preferences: &Arc<StorePreferences>) -> ServerType {
|
||||
match store_preferences.get_object::<ServerType>(SERVER_PROVIDER_TYPE_KEY) {
|
||||
None => ServerType::Local,
|
||||
Some(provider_type) => provider_type,
|
||||
|
@ -8,6 +8,7 @@ use collab::core::origin::{CollabClient, CollabOrigin};
|
||||
use collab::preclude::CollabPlugin;
|
||||
use collab_entity::CollabType;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::instrument;
|
||||
|
||||
use collab_integrate::collab_builder::{CollabPluginContext, CollabSource, CollabStorageProvider};
|
||||
use collab_integrate::postgres::SupabaseDBPlugin;
|
||||
@ -23,7 +24,7 @@ use flowy_folder_deps::cloud::{
|
||||
use flowy_storage::{FileStorageService, StorageObject};
|
||||
use flowy_user::event_map::UserCloudServiceProvider;
|
||||
use flowy_user_deps::cloud::UserCloudService;
|
||||
use flowy_user_deps::entities::{AuthType, UserTokenState};
|
||||
use flowy_user_deps::entities::{Authenticator, UserTokenState};
|
||||
use lib_infra::future::{to_fut, Fut, FutureResult};
|
||||
|
||||
use crate::integrate::server::{ServerProvider, ServerType, SERVER_PROVIDER_TYPE_KEY};
|
||||
@ -82,21 +83,21 @@ impl UserCloudServiceProvider for ServerProvider {
|
||||
self.encryption.write().set_secret(secret);
|
||||
}
|
||||
|
||||
/// When user login, the provider type is set by the [AuthType] and save to disk for next use.
|
||||
/// When user login, the provider type is set by the [Authenticator] and save to disk for next use.
|
||||
///
|
||||
/// Each [AuthType] has a corresponding [ServerType]. The [ServerType] is used
|
||||
/// Each [Authenticator] has a corresponding [ServerType]. The [ServerType] is used
|
||||
/// to create a new [AppFlowyServer] if it doesn't exist. Once the [ServerType] is set,
|
||||
/// it will be used when user open the app again.
|
||||
///
|
||||
fn set_auth_type(&self, auth_type: AuthType) {
|
||||
let server_type: ServerType = auth_type.into();
|
||||
fn set_authenticator(&self, authenticator: Authenticator) {
|
||||
let server_type: ServerType = authenticator.into();
|
||||
self.set_server_type(server_type.clone());
|
||||
|
||||
match self.store_preferences.upgrade() {
|
||||
None => tracing::error!("🔴Failed to update server provider type: store preferences is drop"),
|
||||
Some(store_preferences) => {
|
||||
match store_preferences.set_object(SERVER_PROVIDER_TYPE_KEY, server_type.clone()) {
|
||||
Ok(_) => tracing::trace!("Update server provider type to: {:?}", server_type),
|
||||
Ok(_) => tracing::trace!("Set server provider: {:?}", server_type),
|
||||
Err(e) => {
|
||||
tracing::error!("🔴Failed to update server provider type: {:?}", e);
|
||||
},
|
||||
@ -105,6 +106,11 @@ impl UserCloudServiceProvider for ServerProvider {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_authenticator(&self) -> Authenticator {
|
||||
let server_type = self.get_server_type();
|
||||
Authenticator::from(server_type)
|
||||
}
|
||||
|
||||
fn set_device_id(&self, device_id: &str) {
|
||||
if device_id.is_empty() {
|
||||
tracing::error!("🔴Device id is empty");
|
||||
@ -309,6 +315,7 @@ impl CollabStorageProvider for ServerProvider {
|
||||
self.get_server_type().into()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, context), fields(server_type = %self.get_server_type()))]
|
||||
fn get_plugins(&self, context: CollabPluginContext) -> Fut<Vec<Arc<dyn CollabPlugin>>> {
|
||||
match context {
|
||||
CollabPluginContext::Local => to_fut(async move { vec![] }),
|
||||
@ -331,7 +338,7 @@ impl CollabStorageProvider for ServerProvider {
|
||||
let sink_config = SinkConfig::new()
|
||||
.send_timeout(8)
|
||||
.with_max_payload_size(1024 * 10)
|
||||
.with_strategy(SinkStrategy::FixInterval(Duration::from_secs(2)));
|
||||
.with_strategy(SinkStrategy::FixInterval(Duration::from_millis(600)));
|
||||
let sync_plugin = SyncPlugin::new(
|
||||
origin,
|
||||
sync_object,
|
||||
|
@ -10,7 +10,7 @@ use flowy_error::FlowyResult;
|
||||
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};
|
||||
use flowy_user_deps::entities::{Authenticator, UserProfile, UserWorkspace};
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::integrate::server::ServerProvider;
|
||||
@ -27,7 +27,7 @@ pub(crate) struct UserStatusCallbackImpl {
|
||||
}
|
||||
|
||||
impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
fn auth_type_did_changed(&self, _auth_type: AuthType) {}
|
||||
fn authenticator_did_changed(&self, _auth_type: Authenticator) {}
|
||||
|
||||
fn did_init(
|
||||
&self,
|
||||
|
20
frontend/rust-lib/flowy-core/src/integrate/util.rs
Normal file
20
frontend/rust-lib/flowy-core/src/integrate/util.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use std::fs::{self};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub fn copy_dir_recursive(src: &Path, dst: &Path) -> io::Result<()> {
|
||||
for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
|
||||
let path = entry.path();
|
||||
let relative_path = path.strip_prefix(src).unwrap();
|
||||
let target_path = dst.join(relative_path);
|
||||
|
||||
if path.is_dir() {
|
||||
fs::create_dir_all(&target_path)?;
|
||||
} else {
|
||||
fs::copy(path, target_path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -1,21 +1,24 @@
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Weak;
|
||||
use std::time::Duration;
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
use base64::Engine;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{error, event, instrument};
|
||||
use tracing::{debug, error, event, info, instrument};
|
||||
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabSource};
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document2::manager::DocumentManager;
|
||||
use flowy_folder2::manager::FolderManager;
|
||||
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||
use flowy_sqlite::kv::StorePreferences;
|
||||
use flowy_storage::FileStorageService;
|
||||
use flowy_task::{TaskDispatcher, TaskRunner};
|
||||
use flowy_user::event_map::UserCloudServiceProvider;
|
||||
use flowy_user::manager::{UserManager, UserSessionConfig};
|
||||
use flowy_user::manager::{UserManager, UserSessionConfig, URL_SAFE_ENGINE};
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_dispatch::runtime::AFPluginRuntime;
|
||||
use module::make_plugins;
|
||||
@ -24,8 +27,9 @@ pub use module::*;
|
||||
use crate::deps_resolve::*;
|
||||
use crate::integrate::collab_interact::CollabInteractImpl;
|
||||
use crate::integrate::log::{create_log_filter, init_log};
|
||||
use crate::integrate::server::{current_server_provider, ServerProvider, ServerType};
|
||||
use crate::integrate::server::{current_server_type, ServerProvider, ServerType};
|
||||
use crate::integrate::user::UserStatusCallbackImpl;
|
||||
use crate::integrate::util::copy_dir_recursive;
|
||||
|
||||
mod deps_resolve;
|
||||
mod integrate;
|
||||
@ -42,22 +46,56 @@ pub struct AppFlowyCoreConfig {
|
||||
/// Panics if the `root` path is not existing
|
||||
pub storage_path: String,
|
||||
log_filter: String,
|
||||
cloud_config: Option<AFCloudConfiguration>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for AppFlowyCoreConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AppFlowyCoreConfig")
|
||||
.field("storage_path", &self.storage_path)
|
||||
.finish()
|
||||
let mut debug = f.debug_struct("AppFlowy Configuration");
|
||||
debug.field("storage_path", &self.storage_path);
|
||||
if let Some(config) = &self.cloud_config {
|
||||
debug.field("base_url", &config.base_url);
|
||||
debug.field("ws_url", &config.ws_base_url);
|
||||
}
|
||||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AppFlowyCoreConfig {
|
||||
pub fn new(root: &str, name: String) -> Self {
|
||||
let cloud_config = AFCloudConfiguration::from_env().ok();
|
||||
let storage_path = match &cloud_config {
|
||||
None => root.to_string(),
|
||||
Some(config) => {
|
||||
// Isolate the user data folder by the base url of AppFlowy cloud. This is to avoid
|
||||
// the user data folder being shared by different AppFlowy cloud.
|
||||
let server_base64 = URL_SAFE_ENGINE.encode(&config.base_url);
|
||||
let storage_path = format!("{}_{}", root, server_base64);
|
||||
|
||||
// Copy the user data folder from the root path to the isolated path
|
||||
// The root path only exists when using the local version of appflowy
|
||||
if !Path::new(&storage_path).exists() && Path::new(root).exists() {
|
||||
info!("Copy dir from {} to {}", root, storage_path);
|
||||
let src = Path::new(root);
|
||||
match copy_dir_recursive(&src, Path::new(&storage_path)) {
|
||||
Ok(_) => storage_path,
|
||||
Err(err) => {
|
||||
// when the copy dir failed, use the root path as the storage path
|
||||
error!("Copy dir failed: {}", err);
|
||||
root.to_string()
|
||||
},
|
||||
}
|
||||
} else {
|
||||
storage_path
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AppFlowyCoreConfig {
|
||||
name,
|
||||
storage_path: root.to_owned(),
|
||||
storage_path,
|
||||
log_filter: create_log_filter("info".to_owned(), vec![]),
|
||||
cloud_config: AFCloudConfiguration::from_env().ok(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,28 +135,33 @@ impl AppFlowyCore {
|
||||
|
||||
#[instrument(skip(config, runtime))]
|
||||
async fn init(config: AppFlowyCoreConfig, runtime: Arc<AFPluginRuntime>) -> Self {
|
||||
/// The profiling can be used to tracing the performance of the application.
|
||||
/// Check out the [Link](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/profiling)
|
||||
/// for more information.
|
||||
#[cfg(feature = "profiling")]
|
||||
console_subscriber::init();
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if cfg!(debug_assertions) {
|
||||
/// The profiling can be used to tracing the performance of the application.
|
||||
/// Check out the [Link](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/profiling)
|
||||
/// for more information.
|
||||
#[cfg(feature = "profiling")]
|
||||
console_subscriber::init();
|
||||
|
||||
// Init the logger before anything else
|
||||
init_log(&config);
|
||||
// Init the logger before anything else
|
||||
#[cfg(not(feature = "profiling"))]
|
||||
init_log(&config);
|
||||
} else {
|
||||
init_log(&config);
|
||||
}
|
||||
|
||||
// Init the key value database
|
||||
let store_preference = Arc::new(StorePreferences::new(&config.storage_path).unwrap());
|
||||
|
||||
tracing::info!("🔥db {:?}", &config);
|
||||
tracing::debug!("🔥{}", runtime);
|
||||
info!("🔥{:?}", &config);
|
||||
let task_scheduler = TaskDispatcher::new(Duration::from_secs(2));
|
||||
let task_dispatcher = Arc::new(RwLock::new(task_scheduler));
|
||||
runtime.spawn(TaskRunner::run(task_dispatcher.clone()));
|
||||
|
||||
let provider_type = current_server_provider(&store_preference);
|
||||
let server_type = current_server_type(&store_preference);
|
||||
debug!("🔥runtime:{}, server:{}", runtime, server_type);
|
||||
let server_provider = Arc::new(ServerProvider::new(
|
||||
config.clone(),
|
||||
provider_type,
|
||||
server_type,
|
||||
Arc::downgrade(&store_preference),
|
||||
));
|
||||
|
||||
|
@ -71,7 +71,7 @@ impl std::convert::From<&RowDetail> for RowMetaPB {
|
||||
document_id: row_detail.document_id.clone(),
|
||||
icon: row_detail.meta.icon_url.clone(),
|
||||
cover: row_detail.meta.cover_url.clone(),
|
||||
is_document_empty: row_detail.meta.is_document_empty.clone(),
|
||||
is_document_empty: row_detail.meta.is_document_empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1275,14 +1275,42 @@ impl DatabaseViewOperation for DatabaseViewOperationImpl {
|
||||
}
|
||||
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>> {
|
||||
let database = self.database.lock();
|
||||
let rows = database.get_rows_for_view(view_id);
|
||||
let row_details = rows
|
||||
.into_iter()
|
||||
.flat_map(|row| database.get_row_detail(&row.id))
|
||||
.collect::<Vec<RowDetail>>();
|
||||
let database = self.database.clone();
|
||||
let view_id = view_id.to_string();
|
||||
to_fut(async move {
|
||||
let cloned_database = database.clone();
|
||||
// offloads the blocking operation to a thread where blocking is acceptable. This prevents
|
||||
// blocking the main asynchronous runtime
|
||||
let row_orders = tokio::task::spawn_blocking(move || {
|
||||
cloned_database.lock().get_row_orders_for_view(&view_id)
|
||||
})
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
tokio::task::yield_now().await;
|
||||
|
||||
to_fut(async move { row_details.into_iter().map(Arc::new).collect() })
|
||||
let mut all_rows = vec![];
|
||||
|
||||
// Loading the rows in chunks of 10 rows in order to prevent blocking the main asynchronous runtime
|
||||
for chunk in row_orders.chunks(10) {
|
||||
let cloned_database = database.clone();
|
||||
let chunk = chunk.to_vec();
|
||||
let rows = tokio::task::spawn_blocking(move || {
|
||||
let orders = cloned_database.lock().get_rows_from_row_orders(&chunk);
|
||||
let lock_guard = cloned_database.lock();
|
||||
orders
|
||||
.into_iter()
|
||||
.flat_map(|row| lock_guard.get_row_detail(&row.id))
|
||||
.collect::<Vec<RowDetail>>()
|
||||
})
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
all_rows.extend(rows);
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
all_rows.into_iter().map(Arc::new).collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Fut<Vec<Arc<RowCell>>> {
|
||||
|
@ -7,6 +7,7 @@ use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cells, Row, RowDetail, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
@ -256,6 +257,7 @@ impl DatabaseViewEditor {
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip(self))]
|
||||
pub async fn v_get_rows(&self) -> Vec<Arc<RowDetail>> {
|
||||
let mut rows = self.delegate.get_rows(&self.view_id).await;
|
||||
self.v_filter_rows(&mut rows).await;
|
||||
|
@ -7,7 +7,6 @@ use collab_database::views::{
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::entities::FieldVisibility;
|
||||
|
||||
use crate::services::field_settings::{FieldSettings, VISIBILITY};
|
||||
|
||||
/// Helper struct to create a new field setting
|
||||
@ -52,7 +51,7 @@ pub fn default_field_visibility(layout_type: DatabaseLayout) -> FieldVisibility
|
||||
}
|
||||
|
||||
pub fn default_field_settings_for_fields(
|
||||
fields: &Vec<Field>,
|
||||
fields: &[Field],
|
||||
layout_type: DatabaseLayout,
|
||||
) -> FieldSettingsByFieldIdMap {
|
||||
fields
|
||||
|
@ -462,14 +462,20 @@ fn merge_groups(
|
||||
) -> MergeGroupResult {
|
||||
let mut merge_result = MergeGroupResult::new();
|
||||
// group_map is a helper map is used to filter out the new groups.
|
||||
let mut new_group_map: IndexMap<String, Group> = IndexMap::new();
|
||||
new_groups.into_iter().for_each(|group_rev| {
|
||||
new_group_map.insert(group_rev.id.clone(), group_rev);
|
||||
});
|
||||
let mut new_group_map: IndexMap<String, Group> = new_groups
|
||||
.into_iter()
|
||||
.map(|group| (group.id.clone(), group))
|
||||
.collect();
|
||||
|
||||
// The group is ordered in old groups. Add them before adding the new groups
|
||||
for old in old_groups {
|
||||
if let Some(new) = new_group_map.remove(&old.id) {
|
||||
if let Some(index) = new_group_map.get_index_of(&old.id) {
|
||||
let right = new_group_map.split_off(index);
|
||||
merge_result.all_groups.extend(new_group_map.into_values());
|
||||
new_group_map = right;
|
||||
}
|
||||
|
||||
if let Some(new) = new_group_map.shift_remove(&old.id) {
|
||||
merge_result.all_groups.push(new.clone());
|
||||
} else {
|
||||
merge_result.deleted_groups.push(old);
|
||||
|
@ -162,6 +162,7 @@ impl DocumentManager {
|
||||
.map_err(internal_error)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), err)]
|
||||
pub fn close_document(&self, doc_id: &str) -> FlowyResult<()> {
|
||||
self.documents.write().remove(doc_id);
|
||||
Ok(())
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
@ -13,6 +15,15 @@ pub struct AFCloudConfiguration {
|
||||
pub gotrue_url: String,
|
||||
}
|
||||
|
||||
impl Display for AFCloudConfiguration {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!(
|
||||
"base_url: {}, ws_base_url: {}, gotrue_url: {}",
|
||||
self.base_url, self.ws_base_url, self.gotrue_url,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl AFCloudConfiguration {
|
||||
pub fn from_env() -> Result<Self, FlowyError> {
|
||||
let base_url = std::env::var(APPFLOWY_CLOUD_BASE_URL).map_err(|_| {
|
||||
@ -32,6 +43,16 @@ impl AFCloudConfiguration {
|
||||
let gotrue_url = std::env::var(APPFLOWY_CLOUD_GOTRUE_URL)
|
||||
.map_err(|_| FlowyError::new(ErrorCode::InvalidAuthConfig, "Missing AF_CLOUD_GOTRUE_URL"))?;
|
||||
|
||||
if base_url.is_empty() || ws_base_url.is_empty() || gotrue_url.is_empty() {
|
||||
return Err(FlowyError::new(
|
||||
ErrorCode::InvalidAuthConfig,
|
||||
format!(
|
||||
"Invalid APPFLOWY_CLOUD_BASE_URL: {}, APPFLOWY_CLOUD_WS_BASE_URL: {}, APPFLOWY_CLOUD_GOTRUE_URL: {}",
|
||||
base_url, ws_base_url, gotrue_url,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
base_url,
|
||||
ws_base_url,
|
||||
|
@ -43,7 +43,7 @@ mime_guess = "2.0"
|
||||
url = "2.4"
|
||||
tokio-util = "0.7"
|
||||
tokio-stream = { version = "0.1.14", features = ["sync"] }
|
||||
client-api = { version = "0.1.0", features = ["collab-sync"] }
|
||||
client-api = { version = "0.1.0", features = ["collab-sync", "test_util"] }
|
||||
lib-dispatch = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -62,13 +62,27 @@ where
|
||||
let email = email.to_string();
|
||||
let try_get_client = self.server.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
// TODO(nathan): replace the admin_email and admin_password with encryption key
|
||||
let admin_email = std::env::var("GOTRUE_ADMIN_EMAIL").unwrap();
|
||||
let admin_password = std::env::var("GOTRUE_ADMIN_PASSWORD").unwrap();
|
||||
let url = try_get_client?
|
||||
.generate_sign_in_url_with_email(&admin_email, &admin_password, &email)
|
||||
.await?;
|
||||
Ok(url)
|
||||
let client = try_get_client?;
|
||||
let admin_email = std::env::var("GOTRUE_ADMIN_EMAIL").map_err(|_| {
|
||||
anyhow!(
|
||||
"GOTRUE_ADMIN_EMAIL is not set. Please set it to the admin email for the test server"
|
||||
)
|
||||
})?;
|
||||
let admin_password = std::env::var("GOTRUE_ADMIN_PASSWORD").map_err(|_| {
|
||||
anyhow!(
|
||||
"GOTRUE_ADMIN_PASSWORD is not set. Please set it to the admin password for the test server"
|
||||
)
|
||||
})?;
|
||||
let admin_client =
|
||||
client_api::Client::new(client.base_url(), client.ws_addr(), client.gotrue_url());
|
||||
admin_client
|
||||
.sign_in_password(&admin_email, &admin_password)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let action_link = admin_client.generate_sign_in_action_link(&email).await?;
|
||||
let sign_in_url = client.extract_sign_in_url(&action_link).await?;
|
||||
Ok(sign_in_url)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@ use client_api::entity::auth_dto::{UpdateUserParams, UserMetaData};
|
||||
use client_api::entity::{AFRole, AFUserProfile, AFWorkspaceMember};
|
||||
|
||||
use flowy_user_deps::entities::{
|
||||
AuthType, Role, UpdateUserProfileParams, UserProfile, WorkspaceMember, USER_METADATA_ICON_URL,
|
||||
USER_METADATA_OPEN_AI_KEY, USER_METADATA_STABILITY_AI_KEY,
|
||||
Authenticator, Role, UpdateUserProfileParams, UserProfile, WorkspaceMember,
|
||||
USER_METADATA_ICON_URL, USER_METADATA_OPEN_AI_KEY, USER_METADATA_STABILITY_AI_KEY,
|
||||
};
|
||||
|
||||
use crate::af_cloud::impls::user::util::encryption_type_from_profile;
|
||||
@ -57,7 +57,7 @@ pub fn user_profile_from_af_profile(
|
||||
openai_key: openai_key.unwrap_or_default(),
|
||||
stability_ai_key: stability_ai_key.unwrap_or_default(),
|
||||
workspace_id: profile.latest_workspace_id.to_string(),
|
||||
auth_type: AuthType::AFCloud,
|
||||
authenticator: Authenticator::AFCloud,
|
||||
encryption_type,
|
||||
uid: profile.uid,
|
||||
updated_at: profile.updated_at,
|
||||
|
@ -96,7 +96,7 @@ impl AppFlowyServer for AFCloudServer {
|
||||
while let Ok(token_state) = token_state_rx.recv().await {
|
||||
if let Some(client) = weak_client.upgrade() {
|
||||
match token_state {
|
||||
TokenState::Revoked => match client.get_token() {
|
||||
TokenState::Refresh => match client.get_token() {
|
||||
Ok(token) => {
|
||||
let _ = watch_tx.send(UserTokenState::Refresh { token });
|
||||
},
|
||||
@ -107,7 +107,6 @@ impl AppFlowyServer for AFCloudServer {
|
||||
TokenState::Invalid => {
|
||||
let _ = watch_tx.send(UserTokenState::Invalid);
|
||||
},
|
||||
TokenState::DidRefresh => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,7 +197,7 @@ fn spawn_ws_conn(
|
||||
while let Ok(state) = state_recv.recv().await {
|
||||
info!("[websocket] state: {:?}", state);
|
||||
match state {
|
||||
ConnectState::PingTimeout => {
|
||||
ConnectState::PingTimeout | ConnectState::Closed => {
|
||||
// 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())
|
||||
@ -234,7 +233,7 @@ fn spawn_ws_conn(
|
||||
af_spawn(async move {
|
||||
while let Ok(token_state) = token_state_rx.recv().await {
|
||||
match token_state {
|
||||
TokenState::Revoked => {
|
||||
TokenState::Refresh => {
|
||||
if let (Some(api_client), Some(ws_client), Some(device_id)) = (
|
||||
weak_api_client.upgrade(),
|
||||
weak_ws_client.upgrade(),
|
||||
@ -256,7 +255,6 @@ fn spawn_ws_conn(
|
||||
ws_client.disconnect().await;
|
||||
}
|
||||
},
|
||||
TokenState::DidRefresh => {},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -218,7 +218,7 @@ where
|
||||
openai_key: "".to_string(),
|
||||
stability_ai_key: "".to_string(),
|
||||
workspace_id: response.latest_workspace_id,
|
||||
auth_type: AuthType::Supabase,
|
||||
authenticator: Authenticator::Supabase,
|
||||
encryption_type: EncryptionType::from_sign(&response.encryption_sign),
|
||||
updated_at: response.updated_at.timestamp(),
|
||||
}),
|
||||
|
@ -10,6 +10,14 @@ use flowy_server_config::af_cloud_config::AFCloudConfiguration;
|
||||
|
||||
use crate::setup_log;
|
||||
|
||||
/// To run the test, create a .env.ci file in the 'flowy-server' directory and set the following environment variables:
|
||||
///
|
||||
/// - `APPFLOWY_CLOUD_BASE_URL=http://localhost:8000`
|
||||
/// - `APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws`
|
||||
/// - `APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998`
|
||||
///
|
||||
/// - `GOTRUE_ADMIN_EMAIL=admin@example.com`
|
||||
/// - `GOTRUE_ADMIN_PASSWORD=password`
|
||||
pub fn get_af_cloud_config() -> Option<AFCloudConfiguration> {
|
||||
dotenv::from_filename("./.env.ci").ok()?;
|
||||
setup_log();
|
||||
@ -23,15 +31,21 @@ pub fn af_cloud_server(config: AFCloudConfiguration) -> Arc<AFCloudServer> {
|
||||
}
|
||||
|
||||
pub async fn generate_sign_in_url(user_email: &str, config: &AFCloudConfiguration) -> String {
|
||||
let api_client =
|
||||
client_api::Client::new(&config.base_url, &config.ws_base_url, &config.gotrue_url);
|
||||
|
||||
let client = client_api::Client::new(&config.base_url, &config.ws_base_url, &config.gotrue_url);
|
||||
let admin_email = std::env::var("GOTRUE_ADMIN_EMAIL").unwrap();
|
||||
let admin_password = std::env::var("GOTRUE_ADMIN_PASSWORD").unwrap();
|
||||
api_client
|
||||
.generate_sign_in_url_with_email(&admin_email, &admin_password, user_email)
|
||||
let admin_client =
|
||||
client_api::Client::new(client.base_url(), client.ws_addr(), client.gotrue_url());
|
||||
admin_client
|
||||
.sign_in_password(&admin_email, &admin_password)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let action_link = admin_client
|
||||
.generate_sign_in_action_link(&user_email)
|
||||
.await
|
||||
.unwrap();
|
||||
client.extract_sign_in_url(&action_link).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn af_cloud_sign_up_param(
|
||||
|
@ -73,6 +73,7 @@ pub trait UserCloudService: Send + Sync + 'static {
|
||||
fn sign_out(&self, token: Option<String>) -> FutureResult<(), Error>;
|
||||
|
||||
/// Generate a sign in url for the user with the given email
|
||||
/// Currently, only use the admin client for testing
|
||||
fn generate_sign_in_url_with_email(&self, email: &str) -> FutureResult<String, Error>;
|
||||
|
||||
/// When the user opens the OAuth URL, it redirects to the corresponding provider's OAuth web page.
|
||||
|
@ -29,7 +29,7 @@ pub struct SignInParams {
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub name: String,
|
||||
pub auth_type: AuthType,
|
||||
pub auth_type: Authenticator,
|
||||
pub device_id: String,
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ pub struct SignUpParams {
|
||||
pub email: String,
|
||||
pub name: String,
|
||||
pub password: String,
|
||||
pub auth_type: AuthType,
|
||||
pub auth_type: Authenticator,
|
||||
pub device_id: String,
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ impl UserAuthResponse for AuthResponse {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserCredentials {
|
||||
/// Currently, the token is only used when the [AuthType] is AFCloud
|
||||
/// Currently, the token is only used when the [Authenticator] is AFCloud
|
||||
pub token: Option<String>,
|
||||
|
||||
/// The user id
|
||||
@ -165,7 +165,7 @@ pub struct UserProfile {
|
||||
pub openai_key: String,
|
||||
pub stability_ai_key: String,
|
||||
pub workspace_id: String,
|
||||
pub auth_type: AuthType,
|
||||
pub authenticator: Authenticator,
|
||||
// If the encryption_sign is not empty, which means the user has enabled the encryption.
|
||||
pub encryption_type: EncryptionType,
|
||||
pub updated_at: i64,
|
||||
@ -210,11 +210,11 @@ impl FromStr for EncryptionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<(&T, &AuthType)> for UserProfile
|
||||
impl<T> From<(&T, &Authenticator)> for UserProfile
|
||||
where
|
||||
T: UserAuthResponse,
|
||||
{
|
||||
fn from(params: (&T, &AuthType)) -> Self {
|
||||
fn from(params: (&T, &Authenticator)) -> Self {
|
||||
let (value, auth_type) = params;
|
||||
let (icon_url, openai_key, stability_ai_key) = {
|
||||
value
|
||||
@ -243,7 +243,7 @@ where
|
||||
icon_url,
|
||||
openai_key,
|
||||
workspace_id: value.latest_workspace().id.to_owned(),
|
||||
auth_type: auth_type.clone(),
|
||||
authenticator: auth_type.clone(),
|
||||
encryption_type: value.encryption_type(),
|
||||
stability_ai_key,
|
||||
updated_at: value.updated_at(),
|
||||
@ -329,7 +329,7 @@ impl UpdateUserProfileParams {
|
||||
|
||||
#[derive(Debug, Clone, Hash, Serialize_repr, Deserialize_repr, Eq, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum AuthType {
|
||||
pub enum Authenticator {
|
||||
/// It's a local server, we do fake sign in default.
|
||||
Local = 0,
|
||||
/// Currently not supported. It will be supported in the future when the
|
||||
@ -339,25 +339,25 @@ pub enum AuthType {
|
||||
Supabase = 2,
|
||||
}
|
||||
|
||||
impl Default for AuthType {
|
||||
impl Default for Authenticator {
|
||||
fn default() -> Self {
|
||||
Self::Local
|
||||
}
|
||||
}
|
||||
|
||||
impl AuthType {
|
||||
impl Authenticator {
|
||||
pub fn is_local(&self) -> bool {
|
||||
matches!(self, AuthType::Local)
|
||||
matches!(self, Authenticator::Local)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for AuthType {
|
||||
impl From<i32> for Authenticator {
|
||||
fn from(value: i32) -> Self {
|
||||
match value {
|
||||
0 => AuthType::Local,
|
||||
1 => AuthType::AFCloud,
|
||||
2 => AuthType::Supabase,
|
||||
_ => AuthType::Local,
|
||||
0 => Authenticator::Local,
|
||||
1 => Authenticator::AFCloud,
|
||||
2 => Authenticator::Supabase,
|
||||
_ => Authenticator::Local,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ pub fn migration_anon_user_on_sign_up(
|
||||
.with_write_txn(|new_collab_w_txn| {
|
||||
let old_collab_r_txn = old_collab_db.read_txn();
|
||||
let old_to_new_id_map = Arc::new(Mutex::new(OldToNewIdMap::new()));
|
||||
|
||||
migrate_user_awareness(old_to_new_id_map.lock().deref_mut(), old_user, new_user)?;
|
||||
|
||||
migrate_database_with_views_object(
|
||||
@ -216,9 +215,9 @@ where
|
||||
.map_err(|err| PersistenceError::InvalidData(err.to_string()))?;
|
||||
let mut folder_data = old_folder
|
||||
.get_folder_data()
|
||||
.ok_or(PersistenceError::Internal(
|
||||
anyhow!("Can't migrate the folder data").into(),
|
||||
))?;
|
||||
.ok_or(PersistenceError::Internal(anyhow!(
|
||||
"Can't migrate the folder data"
|
||||
)))?;
|
||||
|
||||
old_to_new_id_map
|
||||
.0
|
||||
@ -259,7 +258,7 @@ where
|
||||
|
||||
let origin = CollabOrigin::Client(CollabClient::new(new_uid, "phantom"));
|
||||
let new_folder_collab = Collab::new_with_raw_data(origin, new_workspace_id, vec![], vec![])
|
||||
.map_err(|err| PersistenceError::Internal(Box::new(err)))?;
|
||||
.map_err(|err| PersistenceError::Internal(err.into()))?;
|
||||
let mutex_collab = Arc::new(MutexCollab::from_collab(new_folder_collab));
|
||||
let new_user_id = UserId::from(new_uid);
|
||||
let _ = Folder::create(new_user_id, mutex_collab.clone(), None, folder_data);
|
||||
|
@ -67,6 +67,7 @@ pub async fn sync_user_data_to_cloud(
|
||||
tracing::error!("🔴sync {} failed: {:?}", view_id, err);
|
||||
}
|
||||
}
|
||||
tokio::task::yield_now().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl std::convert::From<UserProfile> for UserProfilePB {
|
||||
token: user_profile.token,
|
||||
icon_url: user_profile.icon_url,
|
||||
openai_key: user_profile.openai_key,
|
||||
auth_type: user_profile.auth_type.into(),
|
||||
auth_type: user_profile.authenticator.into(),
|
||||
encryption_sign,
|
||||
encryption_type: encryption_ty,
|
||||
workspace_id: user_profile.workspace_id,
|
||||
|
@ -100,7 +100,7 @@ pub async fn get_user_profile_handler(
|
||||
|
||||
// When the user is logged in with a local account, the email field is a placeholder and should
|
||||
// not be exposed to the client. So we set the email field to an empty string.
|
||||
if user_profile.auth_type == AuthType::Local {
|
||||
if user_profile.authenticator == Authenticator::Local {
|
||||
user_profile.email = "".to_string();
|
||||
}
|
||||
|
||||
@ -257,7 +257,7 @@ pub async fn oauth_handler(
|
||||
) -> DataResult<UserProfilePB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.into_inner();
|
||||
let auth_type: AuthType = params.auth_type.into();
|
||||
let auth_type: Authenticator = params.auth_type.into();
|
||||
let user_profile = manager.sign_up(auth_type, BoxAny::new(params.map)).await?;
|
||||
data_result_ok(user_profile.into())
|
||||
}
|
||||
@ -269,7 +269,7 @@ pub async fn get_sign_in_url_handler(
|
||||
) -> DataResult<SignInUrlPB, FlowyError> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params = data.into_inner();
|
||||
let auth_type: AuthType = params.auth_type.into();
|
||||
let auth_type: Authenticator = params.auth_type.into();
|
||||
let sign_in_url = manager
|
||||
.generate_sign_in_url_with_email(&auth_type, ¶ms.email)
|
||||
.await?;
|
||||
@ -469,7 +469,7 @@ pub async fn open_historical_users_handler(
|
||||
) -> Result<(), FlowyError> {
|
||||
let user = user.into_inner();
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let auth_type = AuthType::from(user.auth_type);
|
||||
let auth_type = Authenticator::from(user.auth_type);
|
||||
manager
|
||||
.open_historical_user(user.user_id, user.device_id, auth_type)
|
||||
.await?;
|
||||
|
@ -66,12 +66,12 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
||||
#[event_err = "FlowyError"]
|
||||
pub enum UserEvent {
|
||||
/// Only use when the [AuthType] is Local or SelfHosted
|
||||
/// Only use when the [Authenticator] is Local or SelfHosted
|
||||
/// Logging into an account using a register email and password
|
||||
#[event(input = "SignInPayloadPB", output = "UserProfilePB")]
|
||||
SignIn = 0,
|
||||
|
||||
/// Only use when the [AuthType] is Local or SelfHosted
|
||||
/// Only use when the [Authenticator] is Local or SelfHosted
|
||||
/// Creating a new account
|
||||
#[event(input = "SignUpPayloadPB", output = "UserProfilePB")]
|
||||
SignUp = 1,
|
||||
@ -109,7 +109,7 @@ pub enum UserEvent {
|
||||
OauthSignIn = 10,
|
||||
|
||||
/// Get the OAuth callback url
|
||||
/// Only use when the [AuthType] is AFCloud
|
||||
/// Only use when the [Authenticator] is AFCloud
|
||||
#[event(input = "SignInUrlPayloadPB", output = "SignInUrlPB")]
|
||||
GetSignInURL = 11,
|
||||
|
||||
@ -145,7 +145,7 @@ pub enum UserEvent {
|
||||
OpenHistoricalUser = 26,
|
||||
|
||||
/// Push a realtime event to the user. Currently, the realtime event
|
||||
/// is only used when the auth type is: [AuthType::Supabase].
|
||||
/// is only used when the auth type is: [Authenticator::Supabase].
|
||||
///
|
||||
#[event(input = "RealtimePayloadPB")]
|
||||
PushRealtimeEvent = 27,
|
||||
@ -201,9 +201,9 @@ pub struct SignUpContext {
|
||||
}
|
||||
|
||||
pub trait UserStatusCallback: Send + Sync + 'static {
|
||||
/// When the [AuthType] changed, this method will be called. Currently, the auth type
|
||||
/// When the [Authenticator] changed, this method will be called. Currently, the auth type
|
||||
/// will be changed when the user sign in or sign up.
|
||||
fn auth_type_did_changed(&self, _auth_type: AuthType) {}
|
||||
fn authenticator_did_changed(&self, _authenticator: Authenticator) {}
|
||||
/// This will be called after the application launches if the user is already signed in.
|
||||
/// If the user is not signed in, this method will not be called
|
||||
fn did_init(
|
||||
@ -244,7 +244,8 @@ pub trait UserCloudServiceProvider: Send + Sync + 'static {
|
||||
|
||||
fn set_enable_sync(&self, uid: i64, enable_sync: bool);
|
||||
fn set_encrypt_secret(&self, secret: String);
|
||||
fn set_auth_type(&self, auth_type: AuthType);
|
||||
fn set_authenticator(&self, authenticator: Authenticator);
|
||||
fn get_authenticator(&self) -> Authenticator;
|
||||
fn set_device_id(&self, device_id: &str);
|
||||
fn get_user_service(&self) -> Result<Arc<dyn UserCloudService>, FlowyError>;
|
||||
fn service_name(&self) -> String;
|
||||
@ -266,8 +267,12 @@ where
|
||||
(**self).set_encrypt_secret(secret)
|
||||
}
|
||||
|
||||
fn set_auth_type(&self, auth_type: AuthType) {
|
||||
(**self).set_auth_type(auth_type)
|
||||
fn set_authenticator(&self, authenticator: Authenticator) {
|
||||
(**self).set_authenticator(authenticator)
|
||||
}
|
||||
|
||||
fn get_authenticator(&self) -> Authenticator {
|
||||
(**self).get_authenticator()
|
||||
}
|
||||
|
||||
fn set_device_id(&self, device_id: &str) {
|
||||
|
@ -1,7 +1,11 @@
|
||||
use std::path::PathBuf;
|
||||
use std::string::ToString;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use base64::alphabet::URL_SAFE;
|
||||
use base64::engine::general_purpose::PAD;
|
||||
use base64::engine::GeneralPurpose;
|
||||
use collab_user::core::MutexUserAwareness;
|
||||
use serde_json::Value;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
@ -29,16 +33,16 @@ use crate::migrations::workspace_and_favorite_v1::FavoriteV1AndWorkspaceArrayMig
|
||||
use crate::migrations::MigrationUser;
|
||||
use crate::services::cloud_config::get_cloud_config;
|
||||
use crate::services::collab_interact::{CollabInteract, DefaultCollabInteract};
|
||||
use crate::services::database::UserDB;
|
||||
use crate::services::database::{UserDB, UserDBPath};
|
||||
use crate::services::entities::{ResumableSignUp, Session};
|
||||
use crate::services::user_awareness::UserAwarenessDataSource;
|
||||
use crate::services::user_sql::{UserTable, UserTableChangeset};
|
||||
use crate::services::user_workspace::save_user_workspaces;
|
||||
use crate::{errors::FlowyError, notification::*};
|
||||
|
||||
pub const URL_SAFE_ENGINE: GeneralPurpose = GeneralPurpose::new(&URL_SAFE, PAD);
|
||||
pub struct UserSessionConfig {
|
||||
root_dir: String,
|
||||
|
||||
/// Used as the key of `Session` when saving session information to KV.
|
||||
session_cache_key: String,
|
||||
}
|
||||
@ -57,6 +61,7 @@ impl UserSessionConfig {
|
||||
|
||||
pub struct UserManager {
|
||||
database: Arc<UserDB>,
|
||||
user_paths: UserPaths,
|
||||
session_config: UserSessionConfig,
|
||||
pub(crate) cloud_services: Arc<dyn UserCloudServiceProvider>,
|
||||
pub(crate) store_preferences: Arc<StorePreferences>,
|
||||
@ -76,13 +81,17 @@ impl UserManager {
|
||||
store_preferences: Arc<StorePreferences>,
|
||||
collab_builder: Weak<AppFlowyCollabBuilder>,
|
||||
) -> Arc<Self> {
|
||||
let database = Arc::new(UserDB::new(&session_config.root_dir));
|
||||
let user_paths = UserPaths {
|
||||
root: session_config.root_dir.clone(),
|
||||
};
|
||||
let database = Arc::new(UserDB::new(user_paths.clone()));
|
||||
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,
|
||||
user_paths,
|
||||
session_config,
|
||||
cloud_services,
|
||||
store_preferences,
|
||||
@ -249,9 +258,9 @@ impl UserManager {
|
||||
pub async fn sign_in(
|
||||
&self,
|
||||
params: BoxAny,
|
||||
auth_type: AuthType,
|
||||
authenticator: Authenticator,
|
||||
) -> Result<UserProfile, FlowyError> {
|
||||
self.update_auth_type(&auth_type).await;
|
||||
self.update_authenticator(&authenticator).await;
|
||||
let response: AuthResponse = self
|
||||
.cloud_services
|
||||
.get_user_service()?
|
||||
@ -261,8 +270,10 @@ impl UserManager {
|
||||
self.set_collab_config(&session);
|
||||
|
||||
let latest_workspace = response.latest_workspace.clone();
|
||||
let user_profile = UserProfile::from((&response, &auth_type));
|
||||
self.save_auth_data(&response, &auth_type, &session).await?;
|
||||
let user_profile = UserProfile::from((&response, &authenticator));
|
||||
self
|
||||
.save_auth_data(&response, &authenticator, &session)
|
||||
.await?;
|
||||
let _ = self
|
||||
.initialize_user_awareness(&session, UserAwarenessDataSource::Remote)
|
||||
.await;
|
||||
@ -284,13 +295,13 @@ impl UserManager {
|
||||
Ok(user_profile)
|
||||
}
|
||||
|
||||
pub(crate) async fn update_auth_type(&self, auth_type: &AuthType) {
|
||||
pub(crate) async fn update_authenticator(&self, authenticator: &Authenticator) {
|
||||
self
|
||||
.user_status_callback
|
||||
.read()
|
||||
.await
|
||||
.auth_type_did_changed(auth_type.clone());
|
||||
self.cloud_services.set_auth_type(auth_type.clone());
|
||||
.authenticator_did_changed(authenticator.clone());
|
||||
self.cloud_services.set_authenticator(authenticator.clone());
|
||||
}
|
||||
|
||||
/// Manages the user sign-up process, potentially migrating data if necessary.
|
||||
@ -303,15 +314,15 @@ impl UserManager {
|
||||
#[tracing::instrument(level = "info", skip(self, params))]
|
||||
pub async fn sign_up(
|
||||
&self,
|
||||
auth_type: AuthType,
|
||||
authenticator: Authenticator,
|
||||
params: BoxAny,
|
||||
) -> Result<UserProfile, FlowyError> {
|
||||
self.update_auth_type(&auth_type).await;
|
||||
self.update_authenticator(&authenticator).await;
|
||||
|
||||
let migration_user = self.get_migration_user(&auth_type).await;
|
||||
let migration_user = self.get_migration_user(&authenticator).await;
|
||||
let auth_service = self.cloud_services.get_user_service()?;
|
||||
let response: AuthResponse = auth_service.sign_up(params).await?;
|
||||
let user_profile = UserProfile::from((&response, &auth_type));
|
||||
let user_profile = UserProfile::from((&response, &authenticator));
|
||||
if user_profile.encryption_type.is_need_encrypt_secret() {
|
||||
self
|
||||
.resumable_sign_up
|
||||
@ -321,11 +332,11 @@ impl UserManager {
|
||||
user_profile: user_profile.clone(),
|
||||
migration_user,
|
||||
response,
|
||||
auth_type,
|
||||
authenticator,
|
||||
});
|
||||
} else {
|
||||
self
|
||||
.continue_sign_up(&user_profile, migration_user, response, &auth_type)
|
||||
.continue_sign_up(&user_profile, migration_user, response, &authenticator)
|
||||
.await?;
|
||||
}
|
||||
Ok(user_profile)
|
||||
@ -337,7 +348,7 @@ impl UserManager {
|
||||
user_profile,
|
||||
migration_user,
|
||||
response,
|
||||
auth_type,
|
||||
authenticator,
|
||||
} = self
|
||||
.resumable_sign_up
|
||||
.lock()
|
||||
@ -348,7 +359,7 @@ impl UserManager {
|
||||
"No resumable sign up data",
|
||||
))?;
|
||||
self
|
||||
.continue_sign_up(&user_profile, migration_user, response, &auth_type)
|
||||
.continue_sign_up(&user_profile, migration_user, response, &authenticator)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@ -359,7 +370,7 @@ impl UserManager {
|
||||
user_profile: &UserProfile,
|
||||
migration_user: Option<MigrationUser>,
|
||||
response: AuthResponse,
|
||||
auth_type: &AuthType,
|
||||
authenticator: &Authenticator,
|
||||
) -> FlowyResult<()> {
|
||||
let new_session = Session::from(&response);
|
||||
self.set_collab_config(&new_session);
|
||||
@ -383,7 +394,7 @@ impl UserManager {
|
||||
new_user.user_profile.uid
|
||||
);
|
||||
self
|
||||
.migrate_anon_user_to_cloud(&old_user, &new_user)
|
||||
.migrate_anon_user_data_to_cloud(&old_user, &new_user)
|
||||
.await?;
|
||||
let _ = self.database.close(old_user.session.user_id);
|
||||
}
|
||||
@ -393,7 +404,7 @@ impl UserManager {
|
||||
.await;
|
||||
|
||||
self
|
||||
.save_auth_data(&response, auth_type, &new_session)
|
||||
.save_auth_data(&response, authenticator, &new_session)
|
||||
.await?;
|
||||
|
||||
self
|
||||
@ -495,14 +506,14 @@ impl UserManager {
|
||||
// If the authentication type has changed, it indicates that the user has signed in
|
||||
// using a different release package but is sharing the same data folder.
|
||||
// In such cases, notify the frontend to log out.
|
||||
if old_user_profile.auth_type != AuthType::Local
|
||||
&& new_user_profile.auth_type != old_user_profile.auth_type
|
||||
if old_user_profile.authenticator != Authenticator::Local
|
||||
&& new_user_profile.authenticator != old_user_profile.authenticator
|
||||
{
|
||||
event!(
|
||||
tracing::Level::INFO,
|
||||
"User login with different cloud: {:?} -> {:?}",
|
||||
old_user_profile.auth_type,
|
||||
new_user_profile.auth_type
|
||||
"User login with different authenticator: {:?} -> {:?}",
|
||||
old_user_profile.authenticator,
|
||||
new_user_profile.authenticator
|
||||
);
|
||||
|
||||
send_auth_state_notification(AuthStateChangedPB {
|
||||
@ -541,8 +552,9 @@ impl UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all)]
|
||||
pub fn user_dir(&self, uid: i64) -> String {
|
||||
format!("{}/{}", self.session_config.root_dir, uid)
|
||||
self.user_paths.user_dir(uid)
|
||||
}
|
||||
|
||||
pub fn user_setting(&self) -> Result<UserSettingPB, FlowyError> {
|
||||
@ -646,10 +658,10 @@ impl UserManager {
|
||||
|
||||
pub(crate) async fn generate_sign_in_url_with_email(
|
||||
&self,
|
||||
auth_type: &AuthType,
|
||||
authenticator: &Authenticator,
|
||||
email: &str,
|
||||
) -> Result<String, FlowyError> {
|
||||
self.update_auth_type(auth_type).await;
|
||||
self.update_authenticator(authenticator).await;
|
||||
|
||||
let auth_service = self.cloud_services.get_user_service()?;
|
||||
let url = auth_service
|
||||
@ -663,7 +675,7 @@ impl UserManager {
|
||||
&self,
|
||||
oauth_provider: &str,
|
||||
) -> Result<String, FlowyError> {
|
||||
self.update_auth_type(&AuthType::AFCloud).await;
|
||||
self.update_authenticator(&Authenticator::AFCloud).await;
|
||||
let auth_service = self.cloud_services.get_user_service()?;
|
||||
let url = auth_service
|
||||
.generate_oauth_url_with_provider(oauth_provider)
|
||||
@ -675,24 +687,24 @@ impl UserManager {
|
||||
async fn save_auth_data(
|
||||
&self,
|
||||
response: &impl UserAuthResponse,
|
||||
auth_type: &AuthType,
|
||||
authenticator: &Authenticator,
|
||||
session: &Session,
|
||||
) -> Result<(), FlowyError> {
|
||||
let user_profile = UserProfile::from((response, auth_type));
|
||||
let user_profile = UserProfile::from((response, authenticator));
|
||||
let uid = user_profile.uid;
|
||||
event!(tracing::Level::DEBUG, "Save new history user: {:?}", uid);
|
||||
self.add_historical_user(
|
||||
uid,
|
||||
response.device_id(),
|
||||
response.user_name().to_string(),
|
||||
auth_type,
|
||||
authenticator,
|
||||
self.user_dir(uid),
|
||||
);
|
||||
event!(tracing::Level::DEBUG, "Save new history user workspace");
|
||||
save_user_workspaces(uid, self.db_pool(uid)?, response.user_workspaces())?;
|
||||
event!(tracing::Level::INFO, "Save new user profile to disk");
|
||||
self
|
||||
.save_user(uid, (user_profile, auth_type.clone()).into())
|
||||
.save_user(uid, (user_profile, authenticator.clone()).into())
|
||||
.await?;
|
||||
self.set_session(Some(session.clone()))?;
|
||||
Ok(())
|
||||
@ -725,7 +737,7 @@ impl UserManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn migrate_anon_user_to_cloud(
|
||||
async fn migrate_anon_user_data_to_cloud(
|
||||
&self,
|
||||
old_user: &MigrationUser,
|
||||
new_user: &MigrationUser,
|
||||
@ -797,3 +809,26 @@ fn save_user_token(uid: i64, pool: Arc<ConnectionPool>, token: String) -> FlowyR
|
||||
let changeset = UserTableChangeset::new(params);
|
||||
upsert_user_profile_change(uid, pool, changeset)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct UserPaths {
|
||||
root: String,
|
||||
}
|
||||
|
||||
impl UserPaths {
|
||||
fn user_dir(&self, uid: i64) -> String {
|
||||
format!("{}/{}", self.root, uid)
|
||||
}
|
||||
}
|
||||
|
||||
impl UserDBPath for UserPaths {
|
||||
fn user_db_path(&self, uid: i64) -> PathBuf {
|
||||
PathBuf::from(self.user_dir(uid))
|
||||
}
|
||||
|
||||
fn collab_db_path(&self, uid: i64) -> PathBuf {
|
||||
let mut path = PathBuf::from(self.user_dir(uid));
|
||||
path.push("collab_db");
|
||||
path
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
@ -18,14 +18,19 @@ use flowy_user_deps::entities::{UserProfile, UserWorkspace};
|
||||
use crate::services::user_sql::UserTable;
|
||||
use crate::services::user_workspace_sql::UserWorkspaceTable;
|
||||
|
||||
pub trait UserDBPath: Send + Sync + 'static {
|
||||
fn user_db_path(&self, uid: i64) -> PathBuf;
|
||||
fn collab_db_path(&self, uid: i64) -> PathBuf;
|
||||
}
|
||||
|
||||
pub struct UserDB {
|
||||
root: String,
|
||||
paths: Box<dyn UserDBPath>,
|
||||
}
|
||||
|
||||
impl UserDB {
|
||||
pub fn new(db_dir: &str) -> Self {
|
||||
pub fn new(paths: impl UserDBPath) -> Self {
|
||||
Self {
|
||||
root: db_dir.to_owned(),
|
||||
paths: Box::new(paths),
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,25 +56,27 @@ impl UserDB {
|
||||
}
|
||||
|
||||
pub(crate) fn get_pool(&self, user_id: i64) -> Result<Arc<ConnectionPool>, FlowyError> {
|
||||
let pool = open_user_db(&self.root, user_id)?;
|
||||
let pool = open_user_db(self.paths.user_db_path(user_id), user_id)?;
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
pub(crate) fn get_collab_db(&self, user_id: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
let collab_db = open_collab_db(&self.root, user_id)?;
|
||||
let collab_db = open_collab_db(self.paths.collab_db_path(user_id), user_id)?;
|
||||
Ok(collab_db)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_user_db(root: &str, user_id: i64) -> Result<Arc<ConnectionPool>, FlowyError> {
|
||||
pub fn open_user_db(
|
||||
db_path: impl AsRef<Path>,
|
||||
user_id: i64,
|
||||
) -> Result<Arc<ConnectionPool>, FlowyError> {
|
||||
if let Some(database) = DB_MAP.read().get(&user_id) {
|
||||
return Ok(database.get_pool());
|
||||
}
|
||||
|
||||
let mut write_guard = DB_MAP.write();
|
||||
let dir = user_db_path_from_uid(root, user_id);
|
||||
tracing::debug!("open sqlite db {} at path: {:?}", user_id, dir);
|
||||
let db = flowy_sqlite::init(&dir)
|
||||
tracing::debug!("open sqlite db {} at path: {:?}", user_id, db_path.as_ref());
|
||||
let db = flowy_sqlite::init(&db_path)
|
||||
.map_err(|e| FlowyError::internal().with_context(format!("open user db failed, {:?}", e)))?;
|
||||
let pool = db.get_pool();
|
||||
write_guard.insert(user_id.to_owned(), db);
|
||||
@ -98,24 +105,16 @@ pub fn get_user_workspace(
|
||||
Ok(Some(UserWorkspace::from(row)))
|
||||
}
|
||||
|
||||
pub fn user_db_path_from_uid(root: &str, uid: i64) -> PathBuf {
|
||||
let mut dir = PathBuf::new();
|
||||
dir.push(root);
|
||||
dir.push(uid.to_string());
|
||||
dir
|
||||
}
|
||||
|
||||
/// Open a collab db for the user. If the db is already opened, return the opened db.
|
||||
///
|
||||
pub fn open_collab_db(root: &str, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
fn open_collab_db(db_path: impl AsRef<Path>, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError> {
|
||||
if let Some(collab_db) = COLLAB_DB_MAP.read().get(&uid) {
|
||||
return Ok(collab_db.clone());
|
||||
}
|
||||
|
||||
let mut write_guard = COLLAB_DB_MAP.write();
|
||||
let dir = collab_db_path_from_uid(root, uid);
|
||||
tracing::trace!("open collab db {} at path: {:?}", uid, dir);
|
||||
let db = match RocksCollabDB::open(dir) {
|
||||
tracing::trace!("open collab db {} at path: {:?}", uid, db_path.as_ref());
|
||||
let db = match RocksCollabDB::open(db_path) {
|
||||
Ok(db) => Ok(db),
|
||||
Err(err) => {
|
||||
tracing::error!("open collab db failed, {:?}", err);
|
||||
@ -129,14 +128,6 @@ pub fn open_collab_db(root: &str, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyE
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
pub fn collab_db_path_from_uid(root: &str, uid: i64) -> PathBuf {
|
||||
let mut dir = PathBuf::new();
|
||||
dir.push(root);
|
||||
dir.push(uid.to_string());
|
||||
dir.push("collab_db");
|
||||
dir
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref DB_MAP: RwLock<HashMap<i64, Database>> = RwLock::new(HashMap::new());
|
||||
static ref COLLAB_DB_MAP: RwLock<HashMap<i64, Arc<RocksCollabDB>>> = RwLock::new(HashMap::new());
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use flowy_user_deps::entities::{AuthResponse, UserProfile, UserWorkspace};
|
||||
use flowy_user_deps::entities::{AuthType, UserAuthResponse};
|
||||
use flowy_user_deps::entities::{Authenticator, UserAuthResponse};
|
||||
|
||||
use crate::entities::AuthTypePB;
|
||||
use crate::migrations::MigrationUser;
|
||||
@ -157,22 +157,22 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuthTypePB> for AuthType {
|
||||
impl From<AuthTypePB> for Authenticator {
|
||||
fn from(pb: AuthTypePB) -> Self {
|
||||
match pb {
|
||||
AuthTypePB::Supabase => AuthType::Supabase,
|
||||
AuthTypePB::Local => AuthType::Local,
|
||||
AuthTypePB::AFCloud => AuthType::AFCloud,
|
||||
AuthTypePB::Supabase => Authenticator::Supabase,
|
||||
AuthTypePB::Local => Authenticator::Local,
|
||||
AuthTypePB::AFCloud => Authenticator::AFCloud,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuthType> for AuthTypePB {
|
||||
fn from(auth_type: AuthType) -> Self {
|
||||
impl From<Authenticator> for AuthTypePB {
|
||||
fn from(auth_type: Authenticator) -> Self {
|
||||
match auth_type {
|
||||
AuthType::Supabase => AuthTypePB::Supabase,
|
||||
AuthType::Local => AuthTypePB::Local,
|
||||
AuthType::AFCloud => AuthTypePB::AFCloud,
|
||||
Authenticator::Supabase => AuthTypePB::Supabase,
|
||||
Authenticator::Local => AuthTypePB::Local,
|
||||
Authenticator::AFCloud => AuthTypePB::AFCloud,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,18 +195,18 @@ pub struct HistoricalUser {
|
||||
#[serde(default = "flowy_user_deps::DEFAULT_USER_NAME")]
|
||||
pub user_name: String,
|
||||
#[serde(default = "DEFAULT_AUTH_TYPE")]
|
||||
pub auth_type: AuthType,
|
||||
pub auth_type: Authenticator,
|
||||
pub sign_in_timestamp: i64,
|
||||
pub storage_path: String,
|
||||
#[serde(default)]
|
||||
pub device_id: String,
|
||||
}
|
||||
const DEFAULT_AUTH_TYPE: fn() -> AuthType = || AuthType::Local;
|
||||
const DEFAULT_AUTH_TYPE: fn() -> Authenticator = || Authenticator::Local;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ResumableSignUp {
|
||||
pub user_profile: UserProfile,
|
||||
pub response: AuthResponse,
|
||||
pub auth_type: AuthType,
|
||||
pub authenticator: Authenticator,
|
||||
pub migration_user: Option<MigrationUser>,
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use diesel::RunQueryDsl;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_sqlite::schema::user_workspace_table;
|
||||
use flowy_sqlite::{query_dsl::*, ExpressionMethods};
|
||||
use flowy_user_deps::entities::{AuthType, UserWorkspace};
|
||||
use flowy_user_deps::entities::{Authenticator, UserWorkspace};
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use crate::manager::UserManager;
|
||||
@ -13,12 +13,12 @@ use crate::services::user_workspace_sql::UserWorkspaceTable;
|
||||
|
||||
const HISTORICAL_USER: &str = "af_historical_users";
|
||||
impl UserManager {
|
||||
pub async fn get_migration_user(&self, auth_type: &AuthType) -> Option<MigrationUser> {
|
||||
pub async fn get_migration_user(&self, auth_type: &Authenticator) -> Option<MigrationUser> {
|
||||
// Only migrate the data if the user is login in as a guest and sign up as a new user if the current
|
||||
// auth type is not [AuthType::Local].
|
||||
let session = self.get_session().ok()?;
|
||||
let user_profile = self.get_user_profile(session.user_id).await.ok()?;
|
||||
if user_profile.auth_type == AuthType::Local && !auth_type.is_local() {
|
||||
if user_profile.authenticator == Authenticator::Local && !auth_type.is_local() {
|
||||
Some(MigrationUser {
|
||||
user_profile,
|
||||
session,
|
||||
@ -44,7 +44,7 @@ impl UserManager {
|
||||
uid: i64,
|
||||
device_id: &str,
|
||||
user_name: String,
|
||||
auth_type: &AuthType,
|
||||
auth_type: &Authenticator,
|
||||
storage_path: String,
|
||||
) {
|
||||
let mut logger_users = self
|
||||
@ -86,10 +86,10 @@ impl UserManager {
|
||||
&self,
|
||||
uid: i64,
|
||||
device_id: String,
|
||||
auth_type: AuthType,
|
||||
auth_type: Authenticator,
|
||||
) -> FlowyResult<()> {
|
||||
debug_assert!(auth_type.is_local());
|
||||
self.update_auth_type(&auth_type).await;
|
||||
self.update_authenticator(&auth_type).await;
|
||||
let conn = self.db_connection(uid)?;
|
||||
let row = user_workspace_table::dsl::user_workspace_table
|
||||
.filter(user_workspace_table::uid.eq(uid))
|
||||
|
@ -29,8 +29,8 @@ impl UserTable {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(UserProfile, AuthType)> for UserTable {
|
||||
fn from(value: (UserProfile, AuthType)) -> Self {
|
||||
impl From<(UserProfile, Authenticator)> for UserTable {
|
||||
fn from(value: (UserProfile, Authenticator)) -> Self {
|
||||
let (user_profile, auth_type) = value;
|
||||
let encryption_type = serde_json::to_string(&user_profile.encryption_type).unwrap_or_default();
|
||||
UserTable {
|
||||
@ -59,7 +59,7 @@ impl From<UserTable> for UserProfile {
|
||||
icon_url: table.icon_url,
|
||||
openai_key: table.openai_key,
|
||||
workspace_id: table.workspace,
|
||||
auth_type: AuthType::from(table.auth_type),
|
||||
authenticator: Authenticator::from(table.auth_type),
|
||||
encryption_type: EncryptionType::from_str(&table.encryption_type).unwrap_or_default(),
|
||||
stability_ai_key: table.stability_ai_key,
|
||||
updated_at: table.updated_at,
|
||||
|
@ -25,13 +25,10 @@ pub struct Builder {
|
||||
|
||||
impl Builder {
|
||||
pub fn new(name: &str, directory: &str) -> Self {
|
||||
// let directory = directory.as_ref().to_str().unwrap().to_owned();
|
||||
let local_file_name = format!("{}.log", name);
|
||||
|
||||
Builder {
|
||||
name: name.to_owned(),
|
||||
env_filter: "Info".to_owned(),
|
||||
file_appender: tracing_appender::rolling::daily(directory, local_file_name),
|
||||
file_appender: tracing_appender::rolling::daily(directory, format!("{}", name)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ script = [
|
||||
cd rust-lib/
|
||||
rustup show
|
||||
echo RUSTFLAGS="-C target-cpu=native -C link-arg=-mmacosx-version-min=11.0" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
RUSTFLAGS="-C target-cpu=native -C link-arg=-mmacosx-version-min=11.0" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
RUSTFLAGS="--cfg tokio_unstable" cargo build --package=dart-ffi --target ${RUST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
cd ../
|
||||
""",
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user