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:
Nathan.fooo 2023-11-12 18:00:07 +08:00 committed by GitHub
parent 3c7e636b65
commit 7eb20b232a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 559 additions and 386 deletions

View File

@ -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"
}
}
]
}

View File

@ -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=

View File

@ -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;

View File

@ -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

View File

@ -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());
}
}

View File

@ -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",

View File

@ -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" }

View File

@ -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",

View File

@ -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" }

View File

@ -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)
}
}

View File

@ -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" }

View File

@ -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();

View File

@ -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);
}

View File

@ -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(

View File

@ -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()

View File

@ -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"]

View File

@ -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);

View File

@ -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();
}

View File

@ -3,3 +3,4 @@ pub(crate) mod log;
pub(crate) mod server;
mod trait_impls;
pub(crate) mod user;
pub(crate) mod util;

View File

@ -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,

View File

@ -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,

View File

@ -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,

View 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(())
}

View File

@ -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),
));

View File

@ -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,
}
}
}

View File

@ -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>>> {

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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(())

View File

@ -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,

View File

@ -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]

View File

@ -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)
})
}

View File

@ -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,

View File

@ -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 => {},
}
}
});

View File

@ -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(),
}),

View File

@ -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(

View File

@ -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.

View File

@ -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,
}
}
}

View File

@ -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);

View File

@ -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(())
}

View File

@ -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,

View File

@ -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, &params.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?;

View File

@ -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) {

View File

@ -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
}
}

View File

@ -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());

View File

@ -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>,
}

View File

@ -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))

View File

@ -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,

View File

@ -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)),
}
}

View File

@ -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 ../
""",
]