mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: checking workspace state consistent after switching workspace (#5201)
* refactor: getting workspace id * refactor: check workspace id is match for http response * refactor: check http repsonse in valid by checing the workspace id * chore: update log * chore: fix test * chore: fix test * chore: add test * chore: update test
This commit is contained in:
parent
65a289648e
commit
cc66147bc0
@ -184,12 +184,6 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
(user, _) => UserListener(userProfile: user),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<WorkspaceBloc, UserProfilePB, void>(
|
||||
(user, _) => WorkspaceBloc(
|
||||
userService: UserBackendService(userId: user.id),
|
||||
),
|
||||
);
|
||||
|
||||
// share
|
||||
getIt.registerFactoryParam<DocumentShareBloc, ViewPB, void>(
|
||||
(view, _) => DocumentShareBloc(view: view),
|
||||
|
34
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
34
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -162,7 +162,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -740,7 +740,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@ -786,7 +786,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@ -860,7 +860,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -884,7 +884,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -914,7 +914,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -933,7 +933,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -948,7 +948,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -986,7 +986,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1025,7 +1025,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -1050,7 +1050,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -1064,7 +1064,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1404,7 +1404,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2770,7 +2770,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2787,7 +2787,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -3219,7 +3219,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -5707,7 +5707,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
|
@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fdaac9d4aa0db222d69d346b65bfd85d50bf3c00" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "54dfeb552752eb0e4d887af3a0affaa80863943d" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -97,10 +97,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fda
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
|
35
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
35
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
@ -112,6 +112,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"af-persistence",
|
||||
"af-user",
|
||||
"anyhow",
|
||||
"collab",
|
||||
"collab-integrate",
|
||||
"console_error_panic_hook",
|
||||
@ -215,7 +216,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -541,7 +542,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@ -587,7 +588,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@ -631,7 +632,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -655,7 +656,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -674,7 +675,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -689,7 +690,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -727,7 +728,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -765,7 +766,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -790,7 +791,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -804,7 +805,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1001,7 +1002,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -1774,7 +1775,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -1791,7 +1792,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2092,7 +2093,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -3718,7 +3719,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -4980,4 +4981,4 @@ dependencies = [
|
||||
[[patch.unused]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
|
@ -55,7 +55,7 @@ codegen-units = 1
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fdaac9d4aa0db222d69d346b65bfd85d50bf3c00" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "54dfeb552752eb0e4d887af3a0affaa80863943d" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -65,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fda
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
|
@ -36,7 +36,7 @@ wasm-bindgen-futures.workspace = true
|
||||
uuid.workspace = true
|
||||
serde-wasm-bindgen.workspace = true
|
||||
js-sys = "0.3.67"
|
||||
|
||||
anyhow = "1.0"
|
||||
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||
# compared to the default allocator's ~10K. However, it is slower than the default
|
||||
|
@ -4,7 +4,7 @@ use crate::integrate::server::ServerProviderWASM;
|
||||
use af_persistence::store::AppFlowyWASMStore;
|
||||
use af_user::authenticate_user::AuthenticateUser;
|
||||
use af_user::manager::UserManager;
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, WorkspaceCollabIntegrate};
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_folder::manager::FolderManager;
|
||||
@ -27,13 +27,13 @@ impl AppFlowyWASMCore {
|
||||
pub async fn new(device_id: &str, cloud_config: AFCloudConfiguration) -> FlowyResult<Self> {
|
||||
let runtime = Arc::new(AFPluginRuntime::new().unwrap());
|
||||
let server_provider = Rc::new(ServerProviderWASM::new(device_id, cloud_config));
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
server_provider.clone(),
|
||||
device_id.to_string(),
|
||||
));
|
||||
|
||||
let store = Rc::new(AppFlowyWASMStore::new().await?);
|
||||
let auth_user = Rc::new(AuthenticateUser::new(store.clone()).await?);
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
device_id.to_string(),
|
||||
server_provider.clone(),
|
||||
WorkspaceCollabIntegrateImpl(auth_user.clone()),
|
||||
));
|
||||
|
||||
let document_manager = DocumentDepsResolver::resolve(
|
||||
Rc::downgrade(&auth_user),
|
||||
@ -75,3 +75,15 @@ impl AppFlowyWASMCore {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct WorkspaceCollabIntegrateImpl(Rc<AuthenticateUser>);
|
||||
impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl {
|
||||
fn workspace_id(&self) -> Result<String, anyhow::Error> {
|
||||
let workspace_id = self.0.workspace_id()?;
|
||||
Ok(workspace_id)
|
||||
}
|
||||
|
||||
fn device_id(&self) -> Result<String, anyhow::Error> {
|
||||
Ok("fake device id".to_string())
|
||||
}
|
||||
}
|
||||
|
34
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
34
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
@ -153,7 +153,7 @@ checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -714,7 +714,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@ -760,7 +760,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@ -843,7 +843,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -867,7 +867,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -897,7 +897,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -916,7 +916,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -931,7 +931,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -969,7 +969,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1008,7 +1008,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -1033,7 +1033,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -1047,7 +1047,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1391,7 +1391,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2844,7 +2844,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2861,7 +2861,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -3298,7 +3298,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -5802,7 +5802,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
|
@ -86,7 +86,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
|
||||
# Run the script:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fdaac9d4aa0db222d69d346b65bfd85d50bf3c00" }
|
||||
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "54dfeb552752eb0e4d887af3a0affaa80863943d" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -96,10 +96,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fda
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
|
35
frontend/rust-lib/Cargo.lock
generated
35
frontend/rust-lib/Cargo.lock
generated
@ -163,7 +163,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
[[package]]
|
||||
name = "app-error"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -696,7 +696,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"again",
|
||||
"anyhow",
|
||||
@ -742,7 +742,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
@ -785,7 +785,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -809,7 +809,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -839,7 +839,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -858,7 +858,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -873,7 +873,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -911,7 +911,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -950,7 +950,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -975,7 +975,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-rt-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -989,7 +989,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=f8930ed1b19b65dd7b890df2b0db54048141e8c4#f8930ed1b19b65dd7b890df2b0db54048141e8c4"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86#9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1326,7 +1326,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
|
||||
[[package]]
|
||||
name = "database-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -1610,6 +1610,7 @@ dependencies = [
|
||||
"flowy-storage",
|
||||
"flowy-user",
|
||||
"flowy-user-pub",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
@ -2595,7 +2596,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
@ -2612,7 +2613,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gotrue-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
@ -2983,7 +2984,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "infra"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest",
|
||||
@ -5109,7 +5110,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "shared-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=fdaac9d4aa0db222d69d346b65bfd85d50bf3c00#fdaac9d4aa0db222d69d346b65bfd85d50bf3c00"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=54dfeb552752eb0e4d887af3a0affaa80863943d#54dfeb552752eb0e4d887af3a0affaa80863943d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-error",
|
||||
|
@ -115,7 +115,7 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1
|
||||
# Run the script.add_workspace_members:
|
||||
# scripts/tool/update_client_api_rev.sh new_rev_id
|
||||
# ⚠️⚠️⚠️️
|
||||
client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fdaac9d4aa0db222d69d346b65bfd85d50bf3c00" }
|
||||
client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "54dfeb552752eb0e4d887af3a0affaa80863943d" }
|
||||
# Please use the following script to update collab.
|
||||
# Working directory: frontend
|
||||
#
|
||||
@ -125,10 +125,10 @@ client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "fd
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "f8930ed1b19b65dd7b890df2b0db54048141e8c4" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "9efc5d6e13aca7d8ed3763bf57646bf2ddf1ff86" }
|
||||
|
@ -65,56 +65,32 @@ impl Display for CollabPluginProviderContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WorkspaceCollabIntegrate: Send + Sync {
|
||||
fn workspace_id(&self) -> Result<String, Error>;
|
||||
fn device_id(&self) -> Result<String, Error>;
|
||||
}
|
||||
|
||||
pub struct AppFlowyCollabBuilder {
|
||||
network_reachability: CollabConnectReachability,
|
||||
workspace_id: RwLock<Option<String>>,
|
||||
plugin_provider: RwLock<Arc<dyn CollabCloudPluginProvider>>,
|
||||
snapshot_persistence: Mutex<Option<Arc<dyn SnapshotPersistence>>>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
rocksdb_backup: Mutex<Option<Arc<dyn RocksdbBackup>>>,
|
||||
device_id: String,
|
||||
}
|
||||
|
||||
pub struct CollabBuilderConfig {
|
||||
pub sync_enable: bool,
|
||||
/// If auto_initialize is false, the collab object will not be initialized automatically.
|
||||
/// You need to call collab.initialize() manually.
|
||||
///
|
||||
/// Default is true.
|
||||
pub auto_initialize: bool,
|
||||
}
|
||||
|
||||
impl Default for CollabBuilderConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sync_enable: true,
|
||||
auto_initialize: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollabBuilderConfig {
|
||||
pub fn sync_enable(mut self, sync_enable: bool) -> Self {
|
||||
self.sync_enable = sync_enable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn auto_initialize(mut self, auto_initialize: bool) -> Self {
|
||||
self.auto_initialize = auto_initialize;
|
||||
self
|
||||
}
|
||||
workspace_integrate: Arc<dyn WorkspaceCollabIntegrate>,
|
||||
}
|
||||
|
||||
impl AppFlowyCollabBuilder {
|
||||
pub fn new<T: CollabCloudPluginProvider>(storage_provider: T, device_id: String) -> Self {
|
||||
pub fn new(
|
||||
storage_provider: impl CollabCloudPluginProvider + 'static,
|
||||
workspace_integrate: impl WorkspaceCollabIntegrate + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
network_reachability: CollabConnectReachability::new(),
|
||||
workspace_id: Default::default(),
|
||||
plugin_provider: RwLock::new(Arc::new(storage_provider)),
|
||||
snapshot_persistence: Default::default(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
rocksdb_backup: Default::default(),
|
||||
device_id,
|
||||
workspace_integrate: Arc::new(workspace_integrate),
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,10 +103,6 @@ impl AppFlowyCollabBuilder {
|
||||
*self.rocksdb_backup.lock() = Some(rocksdb_backup);
|
||||
}
|
||||
|
||||
pub fn initialize(&self, workspace_id: String) {
|
||||
*self.workspace_id.write() = Some(workspace_id);
|
||||
}
|
||||
|
||||
pub fn update_network(&self, reachable: bool) {
|
||||
if reachable {
|
||||
self
|
||||
@ -149,15 +121,14 @@ impl AppFlowyCollabBuilder {
|
||||
object_id: &str,
|
||||
collab_type: CollabType,
|
||||
) -> Result<CollabObject, Error> {
|
||||
let workspace_id = self.workspace_id.read().clone().ok_or_else(|| {
|
||||
anyhow::anyhow!("When using supabase plugin, the workspace_id should not be empty")
|
||||
})?;
|
||||
let device_id = self.workspace_integrate.device_id()?;
|
||||
let workspace_id = self.workspace_integrate.workspace_id()?;
|
||||
Ok(CollabObject::new(
|
||||
uid,
|
||||
object_id.to_string(),
|
||||
collab_type,
|
||||
workspace_id,
|
||||
self.device_id.clone(),
|
||||
device_id,
|
||||
))
|
||||
}
|
||||
|
||||
@ -175,8 +146,10 @@ impl AppFlowyCollabBuilder {
|
||||
/// - `raw_data`: The raw data of the collaboration object, defined by the [CollabDocState] type.
|
||||
/// - `collab_db`: A weak reference to the [CollabKVDB].
|
||||
///
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn build(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_type: CollabType,
|
||||
@ -184,14 +157,13 @@ impl AppFlowyCollabBuilder {
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
build_config: CollabBuilderConfig,
|
||||
) -> Result<Arc<MutexCollab>, Error> {
|
||||
let persistence_config = CollabPersistenceConfig::default();
|
||||
self.build_with_config(
|
||||
workspace_id,
|
||||
uid,
|
||||
object_id,
|
||||
object_type,
|
||||
collab_db,
|
||||
collab_doc_state,
|
||||
persistence_config,
|
||||
build_config,
|
||||
)
|
||||
}
|
||||
@ -211,25 +183,34 @@ impl AppFlowyCollabBuilder {
|
||||
/// - `collab_db`: A weak reference to the [CollabKVDB].
|
||||
///
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[instrument(
|
||||
level = "trace",
|
||||
skip(self, collab_db, collab_doc_state, persistence_config, build_config)
|
||||
)]
|
||||
#[instrument(level = "trace", skip(self, collab_db, collab_doc_state, build_config))]
|
||||
pub fn build_with_config(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_type: CollabType,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
collab_doc_state: DataSource,
|
||||
#[allow(unused_variables)] persistence_config: CollabPersistenceConfig,
|
||||
build_config: CollabBuilderConfig,
|
||||
) -> Result<Arc<MutexCollab>, Error> {
|
||||
let collab = CollabBuilder::new(uid, object_id)
|
||||
.with_doc_state(collab_doc_state)
|
||||
.with_device_id(self.device_id.clone())
|
||||
.with_device_id(self.workspace_integrate.device_id()?)
|
||||
.build()?;
|
||||
|
||||
// Compare the workspace_id with the currently opened workspace_id. Return an error if they do not match.
|
||||
// This check is crucial in asynchronous code contexts where the workspace_id might change during operation.
|
||||
let actual_workspace_id = self.workspace_integrate.workspace_id()?;
|
||||
if workspace_id != actual_workspace_id {
|
||||
return Err(anyhow::anyhow!(
|
||||
"workspace_id not match when build collab. expect workspace_id: {}, actual workspace_id: {}",
|
||||
workspace_id,
|
||||
actual_workspace_id
|
||||
));
|
||||
}
|
||||
let persistence_config = CollabPersistenceConfig::default();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
collab.lock().add_plugin(Box::new(IndexeddbDiskPlugin::new(
|
||||
@ -317,3 +298,33 @@ impl AppFlowyCollabBuilder {
|
||||
Ok(arc_collab)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CollabBuilderConfig {
|
||||
pub sync_enable: bool,
|
||||
/// If auto_initialize is false, the collab object will not be initialized automatically.
|
||||
/// You need to call collab.initialize() manually.
|
||||
///
|
||||
/// Default is true.
|
||||
pub auto_initialize: bool,
|
||||
}
|
||||
|
||||
impl Default for CollabBuilderConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sync_enable: true,
|
||||
auto_initialize: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollabBuilderConfig {
|
||||
pub fn sync_enable(mut self, sync_enable: bool) -> Self {
|
||||
self.sync_enable = sync_enable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn auto_initialize(mut self, auto_initialize: bool) -> Self {
|
||||
self.auto_initialize = auto_initialize;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::collab_builder::{CollabPluginProviderContext, CollabPluginProviderType};
|
||||
use collab::preclude::CollabPlugin;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub trait CollabCloudPluginProvider: 'static {
|
||||
fn provider_type(&self) -> CollabPluginProviderType;
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
|
||||
@ -10,7 +10,35 @@ pub trait CollabCloudPluginProvider: Send + Sync + 'static {
|
||||
fn is_sync_enabled(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T> CollabCloudPluginProvider for Arc<T>
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl<T> CollabCloudPluginProvider for std::rc::Rc<T>
|
||||
where
|
||||
T: CollabCloudPluginProvider,
|
||||
{
|
||||
fn provider_type(&self) -> CollabPluginProviderType {
|
||||
(**self).provider_type()
|
||||
}
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>> {
|
||||
(**self).get_plugins(context)
|
||||
}
|
||||
|
||||
fn is_sync_enabled(&self) -> bool {
|
||||
(**self).is_sync_enabled()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
|
||||
fn provider_type(&self) -> CollabPluginProviderType;
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
|
||||
|
||||
fn is_sync_enabled(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl<T> CollabCloudPluginProvider for std::sync::Arc<T>
|
||||
where
|
||||
T: CollabCloudPluginProvider,
|
||||
{
|
||||
|
@ -53,6 +53,7 @@ tokio-postgres = { version = "0.7.8" }
|
||||
chrono = "0.4.31"
|
||||
zip = "0.6.6"
|
||||
walkdir = "2.5.0"
|
||||
futures = "0.3.30"
|
||||
|
||||
[features]
|
||||
default = ["supabase_cloud_test"]
|
||||
|
@ -143,7 +143,8 @@ impl EventIntegrationTest {
|
||||
let mutex_folder = self.appflowy_core.folder_manager.get_mutex_folder().clone();
|
||||
let folder_lock_guard = mutex_folder.read();
|
||||
let folder = folder_lock_guard.as_ref().unwrap();
|
||||
folder.get_folder_data().clone().unwrap()
|
||||
let workspace_id = self.appflowy_core.user_manager.workspace_id().unwrap();
|
||||
folder.get_folder_data(&workspace_id).clone().unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
|
||||
|
@ -20,7 +20,7 @@ pub async fn get_synced_workspaces(
|
||||
&sub_id,
|
||||
UserNotification::DidUpdateUserWorkspaces as i32,
|
||||
);
|
||||
receive_with_timeout(rx, Duration::from_secs(30))
|
||||
receive_with_timeout(rx, Duration::from_secs(60))
|
||||
.await
|
||||
.unwrap()
|
||||
.items
|
||||
|
@ -1,5 +1,11 @@
|
||||
use collab::core::collab::DataSource::DocStateV1;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::Folder;
|
||||
use event_integration::user_event::user_localhost_af_cloud;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::user::af_cloud_test::util::get_synced_workspaces;
|
||||
|
||||
@ -94,16 +100,143 @@ async fn af_cloud_open_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
let default_document_name = "Getting started";
|
||||
|
||||
let workspace = test.create_workspace("my second workspace").await;
|
||||
test.open_workspace(&workspace.workspace_id).await;
|
||||
test.create_document("A").await;
|
||||
test.create_document("B").await;
|
||||
let first_workspace = test.get_current_workspace().await;
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
assert_eq!(views[0].name, default_document_name);
|
||||
assert_eq!(views[1].name, "A");
|
||||
assert_eq!(views[2].name, "B");
|
||||
|
||||
test.create_document("my first document").await;
|
||||
test.create_document("my second document").await;
|
||||
let user_workspace = test.create_workspace("second workspace").await;
|
||||
test.open_workspace(&user_workspace.workspace_id).await;
|
||||
let second_workspace = test.get_current_workspace().await;
|
||||
test.create_document("C").await;
|
||||
test.create_document("D").await;
|
||||
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 3);
|
||||
// the first view is the default get started view
|
||||
assert_eq!(views[1].name, "my first document".to_string());
|
||||
assert_eq!(views[2].name, "my second document".to_string());
|
||||
assert_eq!(views[0].name, default_document_name);
|
||||
assert_eq!(views[1].name, "C");
|
||||
assert_eq!(views[2].name, "D");
|
||||
|
||||
// simulate open workspace and check if the views are correct
|
||||
for i in 0..30 {
|
||||
if i % 2 == 0 {
|
||||
test.open_workspace(&first_workspace.id).await;
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
test
|
||||
.create_document(&uuid::Uuid::new_v4().to_string())
|
||||
.await;
|
||||
} else {
|
||||
test.open_workspace(&second_workspace.id).await;
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
test
|
||||
.create_document(&uuid::Uuid::new_v4().to_string())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
test.open_workspace(&first_workspace.id).await;
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views[0].name, default_document_name);
|
||||
assert_eq!(views[1].name, "A");
|
||||
assert_eq!(views[2].name, "B");
|
||||
|
||||
test.open_workspace(&second_workspace.id).await;
|
||||
let views = test.get_all_workspace_views().await;
|
||||
assert_eq!(views[0].name, default_document_name);
|
||||
assert_eq!(views[1].name, "C");
|
||||
assert_eq!(views[2].name, "D");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_different_open_same_workspace_test() {
|
||||
user_localhost_af_cloud().await;
|
||||
|
||||
// Set up the primary client and sign them up to the cloud.
|
||||
let client_1 = EventIntegrationTest::new().await;
|
||||
let owner_profile = client_1.af_cloud_sign_up().await;
|
||||
let shared_workspace_id = client_1.get_current_workspace().await.id.clone();
|
||||
|
||||
// Verify that the workspace ID from the profile matches the current session's workspace ID.
|
||||
assert_eq!(shared_workspace_id, owner_profile.workspace_id);
|
||||
|
||||
// Define the number of additional clients
|
||||
let num_clients = 5;
|
||||
let mut clients = Vec::new();
|
||||
|
||||
// Initialize and sign up additional clients
|
||||
for _ in 0..num_clients {
|
||||
let client = EventIntegrationTest::new().await;
|
||||
let client_profile = client.af_cloud_sign_up().await;
|
||||
|
||||
let views = client.get_all_workspace_views().await;
|
||||
// only the getting started view should be present
|
||||
assert_eq!(views.len(), 1);
|
||||
for view in views {
|
||||
client.delete_view(&view.id).await;
|
||||
}
|
||||
|
||||
client_1
|
||||
.add_workspace_member(&owner_profile.workspace_id, &client_profile.email)
|
||||
.await;
|
||||
clients.push((client, client_profile));
|
||||
}
|
||||
|
||||
// Verify that each client has exactly two workspaces: one from sign-up and another from invitation
|
||||
for (client, profile) in &clients {
|
||||
let all_workspaces = get_synced_workspaces(client, profile.id).await;
|
||||
assert_eq!(all_workspaces.len(), 2);
|
||||
}
|
||||
|
||||
// Simulate each client open different workspace 30 times
|
||||
let mut handles = vec![];
|
||||
for client in clients.clone() {
|
||||
let cloned_shared_workspace_id = shared_workspace_id.clone();
|
||||
let handle = tokio::spawn(async move {
|
||||
let (client, profile) = client;
|
||||
let all_workspaces = get_synced_workspaces(&client, profile.id).await;
|
||||
for i in 0..30 {
|
||||
let index = i % 2;
|
||||
let iter_workspace_id = &all_workspaces[index].workspace_id;
|
||||
client.open_workspace(iter_workspace_id).await;
|
||||
if iter_workspace_id == &cloned_shared_workspace_id {
|
||||
let views = client.get_all_workspace_views().await;
|
||||
assert_eq!(views.len(), 1);
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
} else {
|
||||
let views = client.get_all_workspace_views().await;
|
||||
assert!(views.is_empty());
|
||||
}
|
||||
}
|
||||
});
|
||||
handles.push(handle);
|
||||
}
|
||||
futures::future::join_all(handles).await;
|
||||
|
||||
// Retrieve and verify the collaborative document state for Client 1's workspace.
|
||||
let doc_state = client_1
|
||||
.get_collab_doc_state(&shared_workspace_id, CollabType::Folder)
|
||||
.await
|
||||
.unwrap();
|
||||
let folder = Folder::from_collab_doc_state(
|
||||
owner_profile.id,
|
||||
CollabOrigin::Empty,
|
||||
DocStateV1(doc_state),
|
||||
&shared_workspace_id,
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Retrieve and verify the views associated with the workspace.
|
||||
let views = folder.get_views_belong_to(&shared_workspace_id);
|
||||
let folder_workspace_id = folder.get_workspace_id();
|
||||
assert_eq!(folder_workspace_id, shared_workspace_id);
|
||||
|
||||
assert_eq!(views.len(), 1, "only get: {:?}", views); // Expecting two views.
|
||||
assert_eq!(views[0].name, "Getting started");
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ use flowy_sqlite::{
|
||||
};
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
|
||||
use collab_integrate::collab_builder::WorkspaceCollabIntegrate;
|
||||
use lib_infra::util::timestamp;
|
||||
use std::sync::Weak;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::debug;
|
||||
|
||||
pub struct SnapshotDBImpl(pub Weak<AuthenticateUser>);
|
||||
@ -207,3 +208,26 @@ impl CollabSnapshotSql {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WorkspaceCollabIntegrateImpl(pub Weak<AuthenticateUser>);
|
||||
|
||||
impl WorkspaceCollabIntegrateImpl {
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.0
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl {
|
||||
fn workspace_id(&self) -> Result<String, anyhow::Error> {
|
||||
let workspace_id = self.upgrade_user()?.workspace_id()?;
|
||||
Ok(workspace_id)
|
||||
}
|
||||
|
||||
fn device_id(&self) -> Result<String, anyhow::Error> {
|
||||
Ok(self.upgrade_user()?.user_config.device_id.clone())
|
||||
}
|
||||
}
|
||||
|
@ -27,20 +27,30 @@ impl DatabaseDepsResolver {
|
||||
}
|
||||
|
||||
struct DatabaseUserImpl(Weak<AuthenticateUser>);
|
||||
impl DatabaseUser for DatabaseUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self
|
||||
impl DatabaseUserImpl {
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.0
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?
|
||||
.user_id()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
impl DatabaseUser for DatabaseUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError> {
|
||||
self
|
||||
.0
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?
|
||||
.get_collab_db(uid)
|
||||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
fn workspace_database_object_id(&self) -> Result<String, FlowyError> {
|
||||
self.upgrade_user()?.workspace_database_object_id()
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use flowy_folder_pub::folder_builder::NestedViewBuilder;
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::future::FutureResult;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
@ -76,22 +75,27 @@ struct FolderUserImpl {
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FolderUser for FolderUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self
|
||||
impl FolderUserImpl {
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.authenticate_user
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?
|
||||
.user_id()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
impl FolderUser for FolderUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError> {
|
||||
self
|
||||
.authenticate_user
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?
|
||||
.get_collab_db(uid)
|
||||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ use parking_lot::RwLock;
|
||||
use serde_repr::*;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_server::af_cloud::define::ServerUser;
|
||||
use flowy_server::af_cloud::AppFlowyCloudServer;
|
||||
use flowy_server::local_server::{LocalServer, LocalServerDB};
|
||||
use flowy_server::supabase::SupabaseServer;
|
||||
@ -63,6 +64,7 @@ pub struct ServerProvider {
|
||||
|
||||
/// The authenticator type of the user.
|
||||
authenticator: RwLock<Authenticator>,
|
||||
user: Arc<dyn ServerUser>,
|
||||
pub(crate) uid: Arc<RwLock<Option<i64>>>,
|
||||
}
|
||||
|
||||
@ -71,7 +73,9 @@ impl ServerProvider {
|
||||
config: AppFlowyCoreConfig,
|
||||
server: Server,
|
||||
store_preferences: Weak<StorePreferences>,
|
||||
server_user: impl ServerUser + 'static,
|
||||
) -> Self {
|
||||
let user = Arc::new(server_user);
|
||||
let encryption = EncryptionImpl::new(None);
|
||||
Self {
|
||||
config,
|
||||
@ -81,6 +85,7 @@ impl ServerProvider {
|
||||
encryption: RwLock::new(Arc::new(encryption)),
|
||||
store_preferences,
|
||||
uid: Default::default(),
|
||||
user,
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,6 +134,7 @@ impl ServerProvider {
|
||||
*self.user_enable_sync.read(),
|
||||
self.config.device_id.clone(),
|
||||
&self.config.app_version,
|
||||
self.user.clone(),
|
||||
));
|
||||
|
||||
Ok::<Arc<dyn AppFlowyServer>, FlowyError>(server)
|
||||
|
@ -38,7 +38,6 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
) -> Fut<FlowyResult<()>> {
|
||||
let user_id = user_id.to_owned();
|
||||
let user_workspace = user_workspace.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
@ -59,7 +58,6 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
}
|
||||
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
@ -69,16 +67,8 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.workspace_database_object_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
document_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -104,19 +94,9 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
device_id
|
||||
);
|
||||
|
||||
folder_manager
|
||||
.initialize_with_workspace_id(user_id, &user_workspace.id)
|
||||
.await?;
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.workspace_database_object_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
folder_manager.initialize_with_workspace_id(user_id).await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
document_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -199,16 +179,12 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
.context("FolderManager error")?;
|
||||
|
||||
database_manager
|
||||
.initialize_with_new_user(
|
||||
user_profile.uid,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.workspace_database_object_id,
|
||||
)
|
||||
.initialize_with_new_user(user_profile.uid)
|
||||
.await
|
||||
.context("DatabaseManager error")?;
|
||||
|
||||
document_manager
|
||||
.initialize_with_new_user(user_profile.uid, user_workspace.id)
|
||||
.initialize_with_new_user(user_profile.uid)
|
||||
.await
|
||||
.context("DocumentManager error")?;
|
||||
Ok(())
|
||||
@ -223,29 +199,15 @@ impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
})
|
||||
}
|
||||
|
||||
fn open_workspace(&self, user_id: i64, user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
||||
let user_workspace = user_workspace.clone();
|
||||
let collab_builder = self.collab_builder.clone();
|
||||
fn open_workspace(&self, user_id: i64, _user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
let document_manager = self.document_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
collab_builder.initialize(user_workspace.id.clone());
|
||||
folder_manager
|
||||
.initialize_with_workspace_id(user_id, &user_workspace.id)
|
||||
.await?;
|
||||
|
||||
database_manager
|
||||
.initialize(
|
||||
user_id,
|
||||
user_workspace.id.clone(),
|
||||
user_workspace.workspace_database_object_id,
|
||||
)
|
||||
.await?;
|
||||
document_manager
|
||||
.initialize(user_id, user_workspace.id)
|
||||
.await?;
|
||||
folder_manager.initialize_with_workspace_id(user_id).await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
document_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use flowy_storage::ObjectStorageService;
|
||||
use semver::Version;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use sysinfo::System;
|
||||
use tokio::sync::RwLock;
|
||||
@ -13,7 +13,9 @@ use tracing::{debug, error, event, info, instrument};
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabPluginProviderType};
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_folder::manager::FolderManager;
|
||||
use flowy_server::af_cloud::define::ServerUser;
|
||||
|
||||
use flowy_sqlite::kv::StorePreferences;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
@ -104,14 +106,29 @@ impl AppFlowyCore {
|
||||
let task_dispatcher = Arc::new(RwLock::new(task_scheduler));
|
||||
runtime.spawn(TaskRunner::run(task_dispatcher.clone()));
|
||||
|
||||
let app_version = Version::parse(&config.app_version).unwrap_or_else(|_| Version::new(0, 5, 4));
|
||||
let user_config = UserConfig::new(
|
||||
&config.name,
|
||||
&config.storage_path,
|
||||
&config.application_path,
|
||||
&config.device_id,
|
||||
app_version,
|
||||
);
|
||||
|
||||
let authenticate_user = Arc::new(AuthenticateUser::new(
|
||||
user_config.clone(),
|
||||
store_preference.clone(),
|
||||
));
|
||||
|
||||
let server_type = current_server_type();
|
||||
debug!("🔥runtime:{}, server:{}", runtime, server_type);
|
||||
|
||||
let server_provider = Arc::new(ServerProvider::new(
|
||||
config.clone(),
|
||||
server_type,
|
||||
Arc::downgrade(&store_preference),
|
||||
ServerUserImpl(Arc::downgrade(&authenticate_user)),
|
||||
));
|
||||
let app_version = Version::parse(&config.app_version).unwrap_or_else(|_| Version::new(0, 5, 4));
|
||||
|
||||
event!(tracing::Level::DEBUG, "Init managers",);
|
||||
let (
|
||||
@ -127,20 +144,7 @@ impl AppFlowyCore {
|
||||
/// on demand based on the [CollabPluginConfig].
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
server_provider.clone(),
|
||||
config.device_id.clone(),
|
||||
));
|
||||
|
||||
let user_config = UserConfig::new(
|
||||
&config.name,
|
||||
&config.storage_path,
|
||||
&config.application_path,
|
||||
&config.device_id,
|
||||
app_version,
|
||||
);
|
||||
|
||||
let authenticate_user = Arc::new(AuthenticateUser::new(
|
||||
user_config.clone(),
|
||||
store_preference.clone(),
|
||||
WorkspaceCollabIntegrateImpl(Arc::downgrade(&authenticate_user)),
|
||||
));
|
||||
|
||||
collab_builder
|
||||
@ -260,3 +264,20 @@ impl From<Server> for CollabPluginProviderType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerUserImpl(Weak<AuthenticateUser>);
|
||||
|
||||
impl ServerUserImpl {
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.0
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
impl ServerUser for ServerUserImpl {
|
||||
fn workspace_id(&self) -> FlowyResult<String> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ use crate::services::share::csv::{CSVFormat, CSVImporter, ImportResult};
|
||||
pub trait DatabaseUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn workspace_database_object_id(&self) -> Result<String, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct DatabaseManager {
|
||||
@ -71,12 +73,7 @@ impl DatabaseManager {
|
||||
}
|
||||
|
||||
/// When initialize with new workspace, all the resources will be cleared.
|
||||
pub async fn initialize(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_id: String,
|
||||
workspace_database_object_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
pub async fn initialize(&self, uid: i64) -> FlowyResult<()> {
|
||||
// 1. Clear all existing tasks
|
||||
self.task_scheduler.write().await.clear_task();
|
||||
// 2. Release all existing editors
|
||||
@ -85,16 +82,21 @@ impl DatabaseManager {
|
||||
}
|
||||
self.editors.lock().await.clear();
|
||||
// 3. Clear the workspace database
|
||||
if let Some(old_workspace_database) = self.workspace_database.write().await.take() {
|
||||
old_workspace_database.close();
|
||||
}
|
||||
*self.workspace_database.write().await = None;
|
||||
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
let collab_builder = UserDatabaseCollabServiceImpl {
|
||||
workspace_id: workspace_id.clone(),
|
||||
user: self.user.clone(),
|
||||
collab_builder: self.collab_builder.clone(),
|
||||
cloud_service: self.cloud_service.clone(),
|
||||
};
|
||||
let config = CollabPersistenceConfig::new().snapshot_per_update(100);
|
||||
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let workspace_database_object_id = self.user.workspace_database_object_id()?;
|
||||
let mut workspace_database_doc_state = DataSource::Disk;
|
||||
// If the workspace database not exist in disk, try to fetch from remote.
|
||||
if !self.is_collab_exist(uid, &collab_db, &workspace_database_object_id) {
|
||||
@ -151,15 +153,8 @@ impl DatabaseManager {
|
||||
skip_all,
|
||||
err
|
||||
)]
|
||||
pub async fn initialize_with_new_user(
|
||||
&self,
|
||||
user_id: i64,
|
||||
workspace_id: String,
|
||||
workspace_database_object_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
self
|
||||
.initialize(user_id, workspace_id, workspace_database_object_id)
|
||||
.await?;
|
||||
pub async fn initialize_with_new_user(&self, user_id: i64) -> FlowyResult<()> {
|
||||
self.initialize(user_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -222,7 +217,7 @@ impl DatabaseManager {
|
||||
.await?
|
||||
.get_database(database_id)
|
||||
.await
|
||||
.ok_or_else(FlowyError::collab_not_sync)?;
|
||||
.ok_or_else(|| FlowyError::collab_not_sync().with_context("open database error"))?;
|
||||
|
||||
// Subscribe the [BlockEvent]
|
||||
subscribe_block_event(&database);
|
||||
@ -445,7 +440,7 @@ fn subscribe_block_event(database: &Arc<MutexDatabase>) {
|
||||
}
|
||||
|
||||
struct UserDatabaseCollabServiceImpl {
|
||||
workspace_id: String,
|
||||
user: Arc<dyn DatabaseUser>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
cloud_service: Arc<dyn DatabaseCloudService>,
|
||||
}
|
||||
@ -456,7 +451,7 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
object_id: &str,
|
||||
object_ty: CollabType,
|
||||
) -> CollabFuture<Result<DataSource, DatabaseError>> {
|
||||
let workspace_id = self.workspace_id.clone();
|
||||
let workspace_id = self.user.workspace_id().unwrap();
|
||||
let object_id = object_id.to_string();
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
Box::pin(async move {
|
||||
@ -480,9 +475,12 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
object_ids: Vec<String>,
|
||||
object_ty: CollabType,
|
||||
) -> CollabFuture<Result<CollabDocStateByOid, DatabaseError>> {
|
||||
let workspace_id = self.workspace_id.clone();
|
||||
let cloned_user = self.user.clone();
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
Box::pin(async move {
|
||||
let workspace_id = cloned_user
|
||||
.workspace_id()
|
||||
.map_err(|err| DatabaseError::Internal(err.into()))?;
|
||||
match weak_cloud_service.upgrade() {
|
||||
None => {
|
||||
tracing::warn!("Cloud service is dropped");
|
||||
@ -505,15 +503,19 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
object_type: CollabType,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
collab_raw_data: DataSource,
|
||||
persistence_config: CollabPersistenceConfig,
|
||||
_persistence_config: CollabPersistenceConfig,
|
||||
) -> Result<Arc<MutexCollab>, DatabaseError> {
|
||||
let workspace_id = self
|
||||
.user
|
||||
.workspace_id()
|
||||
.map_err(|err| DatabaseError::Internal(err.into()))?;
|
||||
let collab = self.collab_builder.build_with_config(
|
||||
&workspace_id,
|
||||
uid,
|
||||
object_id,
|
||||
object_type.clone(),
|
||||
collab_db.clone(),
|
||||
collab_raw_data,
|
||||
persistence_config,
|
||||
CollabBuilderConfig::default().sync_enable(true),
|
||||
)?;
|
||||
Ok(collab)
|
||||
|
@ -20,7 +20,6 @@ use tracing::{error, trace};
|
||||
use tracing::{event, instrument};
|
||||
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
|
||||
use collab_integrate::CollabPersistenceConfig;
|
||||
use flowy_document_pub::cloud::DocumentCloudService;
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_storage::ObjectStorageService;
|
||||
@ -77,7 +76,7 @@ impl DocumentManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, _uid: i64, _workspace_id: String) -> FlowyResult<()> {
|
||||
pub async fn initialize(&self, _uid: i64) -> FlowyResult<()> {
|
||||
self.documents.clear();
|
||||
Ok(())
|
||||
}
|
||||
@ -88,8 +87,8 @@ impl DocumentManager {
|
||||
skip_all,
|
||||
err
|
||||
)]
|
||||
pub async fn initialize_with_new_user(&self, uid: i64, workspace_id: String) -> FlowyResult<()> {
|
||||
self.initialize(uid, workspace_id).await?;
|
||||
pub async fn initialize_with_new_user(&self, uid: i64) -> FlowyResult<()> {
|
||||
self.initialize(uid).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -382,13 +381,14 @@ impl DocumentManager {
|
||||
sync_enable: bool,
|
||||
) -> FlowyResult<Arc<MutexCollab>> {
|
||||
let db = self.user_service.collab_db(uid)?;
|
||||
let workspace_id = self.user_service.workspace_id()?;
|
||||
let collab = self.collab_builder.build_with_config(
|
||||
&workspace_id,
|
||||
uid,
|
||||
doc_id,
|
||||
CollabType::Document,
|
||||
db,
|
||||
doc_state,
|
||||
CollabPersistenceConfig::default().snapshot_per_update(1000),
|
||||
CollabBuilderConfig::default().sync_enable(sync_enable),
|
||||
)?;
|
||||
Ok(collab)
|
||||
|
@ -9,11 +9,10 @@ use nanoid::nanoid;
|
||||
use parking_lot::Once;
|
||||
use tempfile::TempDir;
|
||||
use tracing_subscriber::{fmt::Subscriber, util::SubscriberInitExt, EnvFilter};
|
||||
use uuid::Uuid;
|
||||
|
||||
use collab_integrate::collab_builder::{
|
||||
AppFlowyCollabBuilder, CollabCloudPluginProvider, CollabPluginProviderContext,
|
||||
CollabPluginProviderType,
|
||||
CollabPluginProviderType, WorkspaceCollabIntegrate,
|
||||
};
|
||||
use collab_integrate::CollabKVDB;
|
||||
use flowy_document::document::MutexDocument;
|
||||
@ -35,9 +34,17 @@ impl DocumentTest {
|
||||
let cloud_service = Arc::new(LocalTestDocumentCloudServiceImpl());
|
||||
let file_storage = Arc::new(DocumentTestFileStorageService) as Arc<dyn ObjectStorageService>;
|
||||
let document_snapshot = Arc::new(DocumentTestSnapshot);
|
||||
|
||||
let builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
DefaultCollabStorageProvider(),
|
||||
WorkspaceCollabIntegrateImpl {
|
||||
workspace_id: user.workspace_id.clone(),
|
||||
},
|
||||
));
|
||||
|
||||
let manager = DocumentManager::new(
|
||||
Arc::new(user),
|
||||
default_collab_builder(),
|
||||
builder,
|
||||
cloud_service,
|
||||
Arc::downgrade(&file_storage),
|
||||
document_snapshot,
|
||||
@ -55,6 +62,7 @@ impl Deref for DocumentTest {
|
||||
}
|
||||
|
||||
pub struct FakeUser {
|
||||
workspace_id: String,
|
||||
collab_db: Arc<CollabKVDB>,
|
||||
}
|
||||
|
||||
@ -65,8 +73,12 @@ impl FakeUser {
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
let path = tempdir.into_path();
|
||||
let collab_db = Arc::new(CollabKVDB::open(path).unwrap());
|
||||
let workspace_id = uuid::Uuid::new_v4().to_string();
|
||||
|
||||
Self { collab_db }
|
||||
Self {
|
||||
collab_db,
|
||||
workspace_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +88,7 @@ impl DocumentUserService for FakeUser {
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
Ok(Uuid::new_v4().to_string())
|
||||
Ok(self.workspace_id.clone())
|
||||
}
|
||||
|
||||
fn collab_db(&self, _uid: i64) -> Result<std::sync::Weak<CollabKVDB>, FlowyError> {
|
||||
@ -100,13 +112,6 @@ pub fn setup_log() {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn default_collab_builder() -> Arc<AppFlowyCollabBuilder> {
|
||||
let builder =
|
||||
AppFlowyCollabBuilder::new(DefaultCollabStorageProvider(), "fake_device_id".to_string());
|
||||
builder.initialize(uuid::Uuid::new_v4().to_string());
|
||||
Arc::new(builder)
|
||||
}
|
||||
|
||||
pub async fn create_and_open_empty_document() -> (DocumentTest, Arc<MutexDocument>, String) {
|
||||
let test = DocumentTest::new();
|
||||
let doc_id: String = gen_document_id();
|
||||
@ -222,3 +227,16 @@ impl DocumentSnapshotService for DocumentTestSnapshot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct WorkspaceCollabIntegrateImpl {
|
||||
workspace_id: String,
|
||||
}
|
||||
impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl {
|
||||
fn workspace_id(&self) -> Result<String, Error> {
|
||||
Ok(self.workspace_id.clone())
|
||||
}
|
||||
|
||||
fn device_id(&self) -> Result<String, Error> {
|
||||
Ok("fake_device_id".to_string())
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ pub mod view_operation;
|
||||
|
||||
mod manager_init;
|
||||
mod manager_observer;
|
||||
#[cfg(debug_assertions)]
|
||||
pub mod manager_test_util;
|
||||
|
||||
pub mod share;
|
||||
#[cfg(feature = "test_helper")]
|
||||
mod test_helper;
|
||||
|
@ -21,34 +21,28 @@ use collab::core::collab::{DataSource, MutexCollab};
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::error::FolderError;
|
||||
use collab_folder::{
|
||||
Folder, FolderData, FolderNotify, Section, SectionItem, TrashInfo, UserId, View, ViewLayout,
|
||||
ViewUpdate, Workspace,
|
||||
Folder, FolderNotify, Section, SectionItem, TrashInfo, UserId, View, ViewLayout, ViewUpdate,
|
||||
Workspace,
|
||||
};
|
||||
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
|
||||
use collab_integrate::{CollabKVDB, CollabPersistenceConfig};
|
||||
use collab_integrate::CollabKVDB;
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService};
|
||||
use flowy_folder_pub::folder_builder::ParentChildViews;
|
||||
use flowy_search_pub::entities::FolderIndexManager;
|
||||
use lib_infra::conditional_send_sync_trait;
|
||||
use parking_lot::RwLock;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, info, instrument};
|
||||
|
||||
conditional_send_sync_trait! {
|
||||
"[crate::manager::FolderUser] represents the user for folder.";
|
||||
FolderUser {
|
||||
pub trait FolderUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn workspace_id(&self) -> Result<String, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError>;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FolderManager {
|
||||
/// workspace_id represents as the id of the Folder.
|
||||
pub(crate) workspace_id: RwLock<Option<String>>,
|
||||
|
||||
/// MutexFolder is the folder that is used to store the data.
|
||||
pub(crate) mutex_folder: Arc<MutexFolder>,
|
||||
pub(crate) collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
@ -73,7 +67,6 @@ impl FolderManager {
|
||||
collab_builder,
|
||||
operation_handlers,
|
||||
cloud_service,
|
||||
workspace_id: Default::default(),
|
||||
folder_indexer,
|
||||
};
|
||||
|
||||
@ -82,25 +75,20 @@ impl FolderManager {
|
||||
|
||||
#[instrument(level = "debug", skip(self), err)]
|
||||
pub async fn get_current_workspace(&self) -> FlowyResult<WorkspacePB> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
self.with_folder(
|
||||
|| {
|
||||
let uid = self.user.user_id()?;
|
||||
let workspace_id = self
|
||||
.workspace_id
|
||||
.read()
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.ok_or_else(|| FlowyError::from(ErrorCode::WorkspaceInitializeError))?;
|
||||
Err(workspace_data_not_sync_error(uid, &workspace_id))
|
||||
},
|
||||
|folder| {
|
||||
let workspace_pb_from_workspace = |workspace: Workspace, folder: &Folder| {
|
||||
let views = get_workspace_public_view_pbs(folder);
|
||||
let views = get_workspace_public_view_pbs(&workspace_id, folder);
|
||||
let workspace: WorkspacePB = (workspace, views).into();
|
||||
Ok::<WorkspacePB, FlowyError>(workspace)
|
||||
};
|
||||
|
||||
match folder.get_current_workspace() {
|
||||
match folder.get_workspace_info(&workspace_id) {
|
||||
None => Err(FlowyError::record_not_found().with_context("Can not find the workspace")),
|
||||
Some(workspace) => workspace_pb_from_workspace(workspace, folder),
|
||||
}
|
||||
@ -111,28 +99,25 @@ impl FolderManager {
|
||||
/// Return a list of views of the current workspace.
|
||||
/// Only the first level of child views are included.
|
||||
pub async fn get_current_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
let workspace_id = self
|
||||
.mutex_folder
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|folder| folder.get_workspace_id());
|
||||
|
||||
if workspace_id.is_some() {
|
||||
self.get_workspace_public_views().await
|
||||
} else {
|
||||
tracing::warn!("Can't get the workspace id from the folder. Return empty list.");
|
||||
Ok(vec![])
|
||||
}
|
||||
let views = self.get_workspace_public_views().await?;
|
||||
Ok(views)
|
||||
}
|
||||
|
||||
pub async fn get_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
Ok(self.with_folder(Vec::new, get_workspace_public_view_pbs))
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
Ok(self.with_folder(Vec::new, |folder| {
|
||||
get_workspace_public_view_pbs(&workspace_id, folder)
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn get_workspace_private_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
Ok(self.with_folder(Vec::new, get_workspace_private_view_pbs))
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
Ok(self.with_folder(Vec::new, |folder| {
|
||||
get_workspace_private_view_pbs(&workspace_id, folder)
|
||||
}))
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all, err)]
|
||||
pub(crate) async fn make_folder<T: Into<Option<FolderNotify>>>(
|
||||
&self,
|
||||
uid: i64,
|
||||
@ -142,11 +127,6 @@ impl FolderManager {
|
||||
folder_notifier: T,
|
||||
) -> Result<Folder, FlowyError> {
|
||||
let folder_notifier = folder_notifier.into();
|
||||
// snapshot_config will be deprecated in the future.
|
||||
let snapshot_config = CollabPersistenceConfig::new()
|
||||
.enable_snapshot(true)
|
||||
.snapshot_per_update(50);
|
||||
|
||||
// only need the check the workspace id when the doc state is not from the disk.
|
||||
let should_check_workspace_id = !matches!(doc_state, DataSource::Disk);
|
||||
let should_auto_initialize = !should_check_workspace_id;
|
||||
@ -154,13 +134,14 @@ impl FolderManager {
|
||||
.sync_enable(true)
|
||||
.auto_initialize(should_auto_initialize);
|
||||
|
||||
let object_id = workspace_id;
|
||||
let collab = self.collab_builder.build_with_config(
|
||||
uid,
|
||||
workspace_id,
|
||||
uid,
|
||||
object_id,
|
||||
CollabType::Folder,
|
||||
collab_db,
|
||||
doc_state,
|
||||
snapshot_config,
|
||||
config,
|
||||
)?;
|
||||
let (should_clear, err) = match Folder::open(UserId::from(uid), collab.clone(), folder_notifier)
|
||||
@ -172,7 +153,7 @@ impl FolderManager {
|
||||
let folder_workspace_id = folder.get_workspace_id();
|
||||
if folder_workspace_id != workspace_id {
|
||||
error!(
|
||||
"expected workspace id: {}, actual workspace id: {}",
|
||||
"expect workspace_id: {}, actual workspace_id: {}",
|
||||
workspace_id, folder_workspace_id
|
||||
);
|
||||
return Err(FlowyError::workspace_data_not_match());
|
||||
@ -203,15 +184,14 @@ impl FolderManager {
|
||||
workspace_id: &str,
|
||||
collab_db: Weak<CollabKVDB>,
|
||||
) -> Result<Arc<MutexCollab>, FlowyError> {
|
||||
let object_id = workspace_id;
|
||||
let collab = self.collab_builder.build_with_config(
|
||||
uid,
|
||||
workspace_id,
|
||||
uid,
|
||||
object_id,
|
||||
CollabType::Folder,
|
||||
collab_db,
|
||||
DataSource::Disk,
|
||||
CollabPersistenceConfig::new()
|
||||
.enable_snapshot(true)
|
||||
.snapshot_per_update(50),
|
||||
CollabBuilderConfig::default().sync_enable(true),
|
||||
)?;
|
||||
Ok(collab)
|
||||
@ -220,19 +200,17 @@ impl FolderManager {
|
||||
/// Initialize the folder with the given workspace id.
|
||||
/// Fetch the folder updates from the cloud service and initialize the folder.
|
||||
#[tracing::instrument(skip(self, user_id), err)]
|
||||
pub async fn initialize_with_workspace_id(
|
||||
&self,
|
||||
user_id: i64,
|
||||
workspace_id: &str,
|
||||
) -> FlowyResult<()> {
|
||||
pub async fn initialize_with_workspace_id(&self, user_id: i64) -> FlowyResult<()> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let object_id = &workspace_id;
|
||||
let folder_doc_state = self
|
||||
.cloud_service
|
||||
.get_folder_doc_state(workspace_id, user_id, CollabType::Folder, workspace_id)
|
||||
.get_folder_doc_state(&workspace_id, user_id, CollabType::Folder, object_id)
|
||||
.await?;
|
||||
if let Err(err) = self
|
||||
.initialize(
|
||||
user_id,
|
||||
workspace_id,
|
||||
&workspace_id,
|
||||
FolderInitDataSource::Cloud(folder_doc_state),
|
||||
)
|
||||
.await
|
||||
@ -243,7 +221,7 @@ impl FolderManager {
|
||||
self
|
||||
.initialize(
|
||||
user_id,
|
||||
workspace_id,
|
||||
&workspace_id,
|
||||
FolderInitDataSource::LocalDisk {
|
||||
create_if_not_exist: false,
|
||||
},
|
||||
@ -278,17 +256,17 @@ impl FolderManager {
|
||||
.map_err(FlowyError::from);
|
||||
|
||||
match result {
|
||||
Ok(folder_updates) => {
|
||||
Ok(folder_doc_state) => {
|
||||
info!(
|
||||
"Get folder updates via {}, doc state len: {}",
|
||||
self.cloud_service.service_name(),
|
||||
folder_updates.len()
|
||||
folder_doc_state.len()
|
||||
);
|
||||
self
|
||||
.initialize(
|
||||
user_id,
|
||||
workspace_id,
|
||||
FolderInitDataSource::Cloud(folder_updates),
|
||||
FolderInitDataSource::Cloud(folder_doc_state),
|
||||
)
|
||||
.await?;
|
||||
},
|
||||
@ -318,12 +296,8 @@ impl FolderManager {
|
||||
Ok(new_workspace)
|
||||
}
|
||||
|
||||
pub async fn get_workspace(&self, _workspace_id: &str) -> Option<Workspace> {
|
||||
self.with_folder(|| None, |folder| folder.get_current_workspace())
|
||||
}
|
||||
|
||||
pub async fn get_workspace_setting_pb(&self) -> FlowyResult<WorkspaceSettingPB> {
|
||||
let workspace_id = self.get_current_workspace_id().await?;
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let latest_view = self.get_current_view().await;
|
||||
Ok(WorkspaceSettingPB {
|
||||
workspace_id,
|
||||
@ -349,14 +323,14 @@ impl FolderManager {
|
||||
}
|
||||
|
||||
pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> {
|
||||
let workspace_pb = {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let guard = self.mutex_folder.read();
|
||||
let folder = guard
|
||||
.as_ref()
|
||||
.ok_or(FlowyError::internal().with_context("folder is not initialized"))?;
|
||||
let workspace = folder.get_current_workspace().ok_or(
|
||||
FlowyError::record_not_found().with_context("Can't find the current workspace id "),
|
||||
)?;
|
||||
let workspace = folder
|
||||
.get_workspace_info(&workspace_id)
|
||||
.ok_or_else(|| FlowyError::record_not_found().with_context("Can not find the workspace"))?;
|
||||
|
||||
let views = folder
|
||||
.views
|
||||
@ -364,25 +338,14 @@ impl FolderManager {
|
||||
.into_iter()
|
||||
.map(|view| view_pb_without_child_views(view.as_ref().clone()))
|
||||
.collect::<Vec<ViewPB>>();
|
||||
drop(guard);
|
||||
|
||||
WorkspacePB {
|
||||
Ok(WorkspacePB {
|
||||
id: workspace.id,
|
||||
name: workspace.name,
|
||||
views,
|
||||
create_time: workspace.created_at,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(workspace_pb)
|
||||
}
|
||||
|
||||
async fn get_current_workspace_id(&self) -> FlowyResult<String> {
|
||||
self
|
||||
.mutex_folder
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|folder| folder.get_workspace_id())
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected empty workspace id"))
|
||||
})
|
||||
}
|
||||
|
||||
/// This function acquires a lock on the `mutex_folder` and checks its state.
|
||||
@ -404,17 +367,8 @@ impl FolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_all_workspaces(&self) -> Vec<Workspace> {
|
||||
self.with_folder(Vec::new, |folder| {
|
||||
let mut workspaces = vec![];
|
||||
if let Some(workspace) = folder.get_current_workspace() {
|
||||
workspaces.push(workspace);
|
||||
}
|
||||
workspaces
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_view_with_params(&self, params: CreateViewParams) -> FlowyResult<View> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let view_layout: ViewLayout = params.layout.clone().into();
|
||||
let handler = self.get_handler(&view_layout)?;
|
||||
let user_id = self.user.user_id()?;
|
||||
@ -453,12 +407,10 @@ impl FolderManager {
|
||||
},
|
||||
);
|
||||
|
||||
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||
let folder = &self.mutex_folder.read();
|
||||
if let Some(folder) = folder.as_ref() {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(view)
|
||||
}
|
||||
@ -659,6 +611,7 @@ impl FolderManager {
|
||||
///
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn move_nested_view(&self, params: MoveNestedViewParams) -> FlowyResult<()> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let view_id = params.view_id;
|
||||
let new_parent_id = params.new_parent_id;
|
||||
let prev_view_id = params.prev_view_id;
|
||||
@ -681,6 +634,7 @@ impl FolderManager {
|
||||
},
|
||||
);
|
||||
notify_parent_view_did_change(
|
||||
&workspace_id,
|
||||
self.mutex_folder.clone(),
|
||||
vec![new_parent_id, old_parent_id],
|
||||
);
|
||||
@ -693,6 +647,7 @@ impl FolderManager {
|
||||
/// We need to convert the index to the real index of the view in the parent view.
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
if let Some((is_workspace, parent_view_id, child_views)) = self.get_view_relation(view_id).await
|
||||
{
|
||||
// The display parent view is the view that is displayed in the UI
|
||||
@ -729,7 +684,11 @@ impl FolderManager {
|
||||
folder.move_view(view_id, actual_from_index as u32, actual_to_index as u32);
|
||||
},
|
||||
);
|
||||
notify_parent_view_did_change(self.mutex_folder.clone(), vec![parent_view_id]);
|
||||
notify_parent_view_did_change(
|
||||
&workspace_id,
|
||||
self.mutex_folder.clone(),
|
||||
vec![parent_view_id],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -819,12 +778,12 @@ impl FolderManager {
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub(crate) async fn set_current_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
let workspace_id = self.with_folder(
|
||||
self.with_folder(
|
||||
|| Err(FlowyError::record_not_found()),
|
||||
|folder| {
|
||||
folder.set_current_view(view_id);
|
||||
folder.add_recent_view_ids(vec![view_id.to_string()]);
|
||||
Ok(folder.get_workspace_id())
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
@ -836,6 +795,7 @@ impl FolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
send_workspace_setting_notification(workspace_id, view);
|
||||
Ok(())
|
||||
}
|
||||
@ -992,6 +952,7 @@ impl FolderManager {
|
||||
}
|
||||
|
||||
pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult<View> {
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
if import_data.data.is_none() && import_data.file_path.is_none() {
|
||||
return Err(FlowyError::new(
|
||||
ErrorCode::InvalidParams,
|
||||
@ -1040,7 +1001,11 @@ impl FolderManager {
|
||||
folder.insert_view(view.clone(), None);
|
||||
},
|
||||
);
|
||||
notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id.clone()]);
|
||||
notify_parent_view_did_change(
|
||||
&workspace_id,
|
||||
self.mutex_folder.clone(),
|
||||
vec![view.parent_view_id.clone()],
|
||||
);
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
@ -1049,6 +1014,7 @@ impl FolderManager {
|
||||
where
|
||||
F: FnOnce(ViewUpdate) -> Option<View>,
|
||||
{
|
||||
let workspace_id = self.user.workspace_id()?;
|
||||
let value = self.with_folder(
|
||||
|| None,
|
||||
|folder| {
|
||||
@ -1070,13 +1036,11 @@ impl FolderManager {
|
||||
.payload(view_pb)
|
||||
.send();
|
||||
|
||||
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||
let folder = &self.mutex_folder.read();
|
||||
if let Some(folder) = folder.as_ref() {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1100,12 +1064,13 @@ impl FolderManager {
|
||||
/// Otherwise, the parent_view_id is the parent view id of the view. The child_view_ids is the
|
||||
/// child view ids of the view.
|
||||
async fn get_view_relation(&self, view_id: &str) -> Option<(bool, String, Vec<String>)> {
|
||||
let workspace_id = self.user.workspace_id().ok()?;
|
||||
self.with_folder(
|
||||
|| None,
|
||||
|folder| {
|
||||
let view = folder.views.get_view(view_id)?;
|
||||
match folder.views.get_view(&view.parent_view_id) {
|
||||
None => folder.get_current_workspace().map(|workspace| {
|
||||
None => folder.get_workspace_info(&workspace_id).map(|workspace| {
|
||||
(
|
||||
true,
|
||||
workspace.id,
|
||||
@ -1154,18 +1119,6 @@ impl FolderManager {
|
||||
Ok(snapshots)
|
||||
}
|
||||
|
||||
/// Only expose this method for testing
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn get_mutex_folder(&self) -> &Arc<MutexFolder> {
|
||||
&self.mutex_folder
|
||||
}
|
||||
|
||||
/// Only expose this method for testing
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn get_cloud_service(&self) -> &Arc<dyn FolderCloudService> {
|
||||
&self.cloud_service
|
||||
}
|
||||
|
||||
pub fn set_views_visibility(&self, view_ids: Vec<String>, is_public: bool) {
|
||||
self.with_folder(
|
||||
|| (),
|
||||
@ -1239,7 +1192,7 @@ impl FolderManager {
|
||||
}
|
||||
|
||||
/// Return the views that belong to the workspace. The views are filtered by the trash and all the private views.
|
||||
pub(crate) fn get_workspace_public_view_pbs(folder: &Folder) -> Vec<ViewPB> {
|
||||
pub(crate) fn get_workspace_public_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
@ -1254,8 +1207,7 @@ pub(crate) fn get_workspace_public_view_pbs(folder: &Folder) -> Vec<ViewPB> {
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut views = folder.get_workspace_views();
|
||||
|
||||
let mut views = folder.views.get_views_belong_to(workspace_id);
|
||||
// filter the views that are in the trash and all the private views
|
||||
views.retain(|view| !trash_ids.contains(&view.id) && !private_view_ids.contains(&view.id));
|
||||
|
||||
@ -1289,7 +1241,7 @@ fn get_all_child_view_ids(folder: &Folder, view_id: &str) -> Vec<String> {
|
||||
}
|
||||
|
||||
/// Get the current private views of the user.
|
||||
pub(crate) fn get_workspace_private_view_pbs(folder: &Folder) -> Vec<ViewPB> {
|
||||
pub(crate) fn get_workspace_private_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
@ -1304,8 +1256,7 @@ pub(crate) fn get_workspace_private_view_pbs(folder: &Folder) -> Vec<ViewPB> {
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut views = folder.get_workspace_views();
|
||||
|
||||
let mut views = folder.views.get_views_belong_to(workspace_id);
|
||||
// filter the views that are in the trash and not in the private view ids
|
||||
views.retain(|view| !trash_ids.contains(&view.id) && private_view_ids.contains(&view.id));
|
||||
|
||||
@ -1342,8 +1293,6 @@ pub enum FolderInitDataSource {
|
||||
LocalDisk { create_if_not_exist: bool },
|
||||
/// If there is no data stored on local disk, we will use the data from the server to initialize the folder
|
||||
Cloud(Vec<u8>),
|
||||
/// If the user is new, we use the [DefaultFolderBuilder] to create the default folder.
|
||||
FolderData(FolderData),
|
||||
}
|
||||
|
||||
impl Display for FolderInitDataSource {
|
||||
@ -1351,7 +1300,6 @@ impl Display for FolderInitDataSource {
|
||||
match self {
|
||||
FolderInitDataSource::LocalDisk { .. } => f.write_fmt(format_args!("LocalDisk")),
|
||||
FolderInitDataSource::Cloud(_) => f.write_fmt(format_args!("Cloud")),
|
||||
FolderInitDataSource::FolderData(_) => f.write_fmt(format_args!("Custom FolderData")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,14 @@
|
||||
use collab_entity::CollabType;
|
||||
|
||||
use collab_folder::{Folder, FolderNotify, UserId};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{event, Level};
|
||||
|
||||
use collab_integrate::CollabKVDB;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
|
||||
use collab::core::collab::DataSource;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::manager::{FolderInitDataSource, FolderManager};
|
||||
use crate::manager_observer::{
|
||||
subscribe_folder_snapshot_state_changed, subscribe_folder_sync_state_changed,
|
||||
subscribe_folder_trash_changed, subscribe_folder_view_changed,
|
||||
};
|
||||
use crate::manager_observer::*;
|
||||
use crate::user_default::DefaultFolderBuilder;
|
||||
use collab::core::collab::DataSource;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::{Folder, FolderNotify, UserId};
|
||||
use collab_integrate::CollabKVDB;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{event, info, Level};
|
||||
|
||||
impl FolderManager {
|
||||
/// Called immediately after the application launched if the user already sign in/sign up.
|
||||
@ -34,9 +26,13 @@ impl FolderManager {
|
||||
workspace_id,
|
||||
initial_data
|
||||
);
|
||||
*self.workspace_id.write() = Some(workspace_id.to_string());
|
||||
let workspace_id = workspace_id.to_string();
|
||||
|
||||
if let Some(old_folder) = self.mutex_folder.write().take() {
|
||||
old_folder.close();
|
||||
info!("remove old folder: {}", old_folder.get_workspace_id());
|
||||
}
|
||||
|
||||
let workspace_id = workspace_id.to_string();
|
||||
// Get the collab db for the user with given user id.
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
|
||||
@ -115,22 +111,6 @@ impl FolderManager {
|
||||
.await?
|
||||
}
|
||||
},
|
||||
FolderInitDataSource::FolderData(folder_data) => {
|
||||
if folder_data.workspace.id != workspace_id {
|
||||
return Err(FlowyError::workspace_data_not_match());
|
||||
}
|
||||
|
||||
event!(Level::INFO, "Restore folder with passed-in folder data");
|
||||
let collab = self
|
||||
.create_empty_collab(uid, &workspace_id, collab_db)
|
||||
.await?;
|
||||
Folder::create(
|
||||
UserId::from(uid),
|
||||
collab,
|
||||
Some(folder_notifier),
|
||||
folder_data,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
let folder_state_rx = folder.subscribe_sync_state();
|
||||
@ -154,10 +134,28 @@ impl FolderManager {
|
||||
*self.mutex_folder.write() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder);
|
||||
subscribe_folder_snapshot_state_changed(workspace_id, &weak_mutex_folder);
|
||||
subscribe_folder_trash_changed(section_change_rx, &weak_mutex_folder);
|
||||
subscribe_folder_view_changed(view_rx, &weak_mutex_folder);
|
||||
subscribe_folder_sync_state_changed(
|
||||
workspace_id.clone(),
|
||||
folder_state_rx,
|
||||
Arc::downgrade(&self.user),
|
||||
);
|
||||
subscribe_folder_snapshot_state_changed(
|
||||
workspace_id.clone(),
|
||||
&weak_mutex_folder,
|
||||
Arc::downgrade(&self.user),
|
||||
);
|
||||
subscribe_folder_trash_changed(
|
||||
workspace_id.clone(),
|
||||
section_change_rx,
|
||||
&weak_mutex_folder,
|
||||
Arc::downgrade(&self.user),
|
||||
);
|
||||
subscribe_folder_view_changed(
|
||||
workspace_id.clone(),
|
||||
view_rx,
|
||||
&weak_mutex_folder,
|
||||
Arc::downgrade(&self.user),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,32 +1,43 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::entities::{
|
||||
view_pb_with_child_views, view_pb_without_child_views, ChildViewUpdatePB, FolderSnapshotStatePB,
|
||||
FolderSyncStatePB, RepeatedTrashPB, RepeatedViewPB, SectionViewsPB, ViewPB, ViewSectionPB,
|
||||
};
|
||||
use crate::manager::{
|
||||
get_workspace_private_view_pbs, get_workspace_public_view_pbs, FolderUser, MutexFolder,
|
||||
};
|
||||
use crate::notification::{send_notification, FolderNotification};
|
||||
use collab::core::collab_state::SyncState;
|
||||
use collab_folder::{
|
||||
Folder, SectionChange, SectionChangeReceiver, TrashSectionChange, View, ViewChange,
|
||||
ViewChangeReceiver,
|
||||
};
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{event, Level};
|
||||
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
|
||||
use crate::entities::{
|
||||
view_pb_with_child_views, view_pb_without_child_views, ChildViewUpdatePB, FolderSnapshotStatePB,
|
||||
FolderSyncStatePB, RepeatedTrashPB, RepeatedViewPB, SectionViewsPB, ViewPB, ViewSectionPB,
|
||||
};
|
||||
use crate::manager::{get_workspace_private_view_pbs, get_workspace_public_view_pbs, MutexFolder};
|
||||
use crate::notification::{send_notification, FolderNotification};
|
||||
use tracing::{event, trace, Level};
|
||||
|
||||
/// Listen on the [ViewChange] after create/delete/update events happened
|
||||
pub(crate) fn subscribe_folder_view_changed(
|
||||
workspace_id: String,
|
||||
mut rx: ViewChangeReceiver,
|
||||
weak_mutex_folder: &Weak<MutexFolder>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
af_spawn(async move {
|
||||
while let Ok(value) = rx.recv().await {
|
||||
if let Some(user) = user.upgrade() {
|
||||
if let Ok(actual_workspace_id) = user.workspace_id() {
|
||||
if actual_workspace_id != workspace_id {
|
||||
trace!("Did break the loop when the workspace id is not matched");
|
||||
// break the loop when the workspace id is not matched.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(folder) = weak_mutex_folder.upgrade() {
|
||||
tracing::trace!("Did receive view change: {:?}", value);
|
||||
match value {
|
||||
@ -35,7 +46,7 @@ pub(crate) fn subscribe_folder_view_changed(
|
||||
view_pb_without_child_views(view.clone()),
|
||||
ChildViewChangeReason::Create,
|
||||
);
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id]);
|
||||
notify_parent_view_did_change(&workspace_id, folder.clone(), vec![view.parent_view_id]);
|
||||
},
|
||||
ViewChange::DidDeleteView { views } => {
|
||||
for view in views {
|
||||
@ -51,7 +62,11 @@ pub(crate) fn subscribe_folder_view_changed(
|
||||
view_pb_without_child_views(view.clone()),
|
||||
ChildViewChangeReason::Update,
|
||||
);
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.parent_view_id.clone()]);
|
||||
notify_parent_view_did_change(
|
||||
&workspace_id,
|
||||
folder.clone(),
|
||||
vec![view.parent_view_id.clone()],
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -62,6 +77,7 @@ pub(crate) fn subscribe_folder_view_changed(
|
||||
pub(crate) fn subscribe_folder_snapshot_state_changed(
|
||||
workspace_id: String,
|
||||
weak_mutex_folder: &Weak<MutexFolder>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
af_spawn(async move {
|
||||
@ -72,6 +88,14 @@ pub(crate) fn subscribe_folder_snapshot_state_changed(
|
||||
.map(|folder| folder.subscribe_snapshot_state());
|
||||
if let Some(mut state_stream) = stream {
|
||||
while let Some(snapshot_state) = state_stream.next().await {
|
||||
if let Some(user) = user.upgrade() {
|
||||
if let Ok(actual_workspace_id) = user.workspace_id() {
|
||||
if actual_workspace_id != workspace_id {
|
||||
// break the loop when the workspace id is not matched.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(new_snapshot_id) = snapshot_state.snapshot_id() {
|
||||
tracing::debug!("Did create folder remote snapshot: {}", new_snapshot_id);
|
||||
send_notification(
|
||||
@ -90,10 +114,19 @@ pub(crate) fn subscribe_folder_snapshot_state_changed(
|
||||
pub(crate) fn subscribe_folder_sync_state_changed(
|
||||
workspace_id: String,
|
||||
mut folder_sync_state_rx: WatchStream<SyncState>,
|
||||
_weak_mutex_folder: &Weak<MutexFolder>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
) {
|
||||
af_spawn(async move {
|
||||
while let Some(state) = folder_sync_state_rx.next().await {
|
||||
if let Some(user) = user.upgrade() {
|
||||
if let Ok(actual_workspace_id) = user.workspace_id() {
|
||||
if actual_workspace_id != workspace_id {
|
||||
// break the loop when the workspace id is not matched.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_notification(&workspace_id, FolderNotification::DidUpdateFolderSyncUpdate)
|
||||
.payload(FolderSyncStatePB::from(state))
|
||||
.send();
|
||||
@ -103,12 +136,23 @@ pub(crate) fn subscribe_folder_sync_state_changed(
|
||||
|
||||
/// Listen on the [TrashChange]s and notify the frontend some views were changed.
|
||||
pub(crate) fn subscribe_folder_trash_changed(
|
||||
workspace_id: String,
|
||||
mut rx: SectionChangeReceiver,
|
||||
weak_mutex_folder: &Weak<MutexFolder>,
|
||||
user: Weak<dyn FolderUser>,
|
||||
) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
af_spawn(async move {
|
||||
while let Ok(value) = rx.recv().await {
|
||||
if let Some(user) = user.upgrade() {
|
||||
if let Ok(actual_workspace_id) = user.workspace_id() {
|
||||
if actual_workspace_id != workspace_id {
|
||||
// break the loop when the workspace id is not matched.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(folder) = weak_mutex_folder.upgrade() {
|
||||
let mut unique_ids = HashSet::new();
|
||||
tracing::trace!("Did receive trash change: {:?}", value);
|
||||
@ -132,7 +176,7 @@ pub(crate) fn subscribe_folder_trash_changed(
|
||||
}
|
||||
|
||||
let parent_view_ids = unique_ids.into_iter().collect();
|
||||
notify_parent_view_did_change(folder.clone(), parent_view_ids);
|
||||
notify_parent_view_did_change(&workspace_id, folder.clone(), parent_view_ids);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -143,12 +187,12 @@ pub(crate) fn subscribe_folder_trash_changed(
|
||||
/// Notify the list of parent view ids that its child views were changed.
|
||||
#[tracing::instrument(level = "debug", skip(folder, parent_view_ids))]
|
||||
pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
workspace_id: &str,
|
||||
folder: Arc<MutexFolder>,
|
||||
parent_view_ids: Vec<T>,
|
||||
) -> Option<()> {
|
||||
let folder = folder.read();
|
||||
let folder = folder.as_ref()?;
|
||||
let workspace_id = folder.get_workspace_id();
|
||||
let trash_ids = folder
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
@ -161,8 +205,8 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
// if the view's parent id equal to workspace id. Then it will fetch the current
|
||||
// workspace views. Because the workspace is not a view stored in the views map.
|
||||
if parent_view_id == workspace_id {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
notify_did_update_section_views(&workspace_id, folder);
|
||||
notify_did_update_workspace(workspace_id, folder);
|
||||
notify_did_update_section_views(workspace_id, folder);
|
||||
} else {
|
||||
// Parent view can contain a list of child views. Currently, only get the first level
|
||||
// child views.
|
||||
@ -183,8 +227,8 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
}
|
||||
|
||||
pub(crate) fn notify_did_update_section_views(workspace_id: &str, folder: &Folder) {
|
||||
let public_views = get_workspace_public_view_pbs(folder);
|
||||
let private_views = get_workspace_private_view_pbs(folder);
|
||||
let public_views = get_workspace_public_view_pbs(workspace_id, folder);
|
||||
let private_views = get_workspace_private_view_pbs(workspace_id, folder);
|
||||
tracing::trace!(
|
||||
"Did update section views: public len = {}, private len = {}",
|
||||
public_views.len(),
|
||||
@ -210,7 +254,7 @@ pub(crate) fn notify_did_update_section_views(workspace_id: &str, folder: &Folde
|
||||
}
|
||||
|
||||
pub(crate) fn notify_did_update_workspace(workspace_id: &str, folder: &Folder) {
|
||||
let repeated_view: RepeatedViewPB = get_workspace_public_view_pbs(folder).into();
|
||||
let repeated_view: RepeatedViewPB = get_workspace_public_view_pbs(workspace_id, folder).into();
|
||||
send_notification(workspace_id, FolderNotification::DidUpdateWorkspaceViews)
|
||||
.payload(repeated_view)
|
||||
.send();
|
||||
|
32
frontend/rust-lib/flowy-folder/src/manager_test_util.rs
Normal file
32
frontend/rust-lib/flowy-folder/src/manager_test_util.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use crate::manager::{FolderManager, FolderUser, MutexFolder};
|
||||
use crate::view_operation::FolderOperationHandlers;
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use flowy_folder_pub::cloud::FolderCloudService;
|
||||
use flowy_search_pub::entities::FolderIndexManager;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl FolderManager {
|
||||
pub fn get_mutex_folder(&self) -> Arc<MutexFolder> {
|
||||
self.mutex_folder.clone()
|
||||
}
|
||||
|
||||
pub fn get_cloud_service(&self) -> Arc<dyn FolderCloudService> {
|
||||
self.cloud_service.clone()
|
||||
}
|
||||
|
||||
pub fn get_user(&self) -> Arc<dyn FolderUser> {
|
||||
self.user.clone()
|
||||
}
|
||||
|
||||
pub fn get_indexer(&self) -> Arc<dyn FolderIndexManager> {
|
||||
self.folder_indexer.clone()
|
||||
}
|
||||
|
||||
pub fn get_collab_builder(&self) -> Arc<AppFlowyCollabBuilder> {
|
||||
self.collab_builder.clone()
|
||||
}
|
||||
|
||||
pub fn get_operation_handlers(&self) -> FolderOperationHandlers {
|
||||
self.operation_handlers.clone()
|
||||
}
|
||||
}
|
@ -1,14 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::notifier::{SearchNotifier, SearchResultChanged, SearchResultReceiverRunner};
|
||||
use crate::entities::{SearchFilterPB, SearchResultNotificationPB, SearchResultPB};
|
||||
use flowy_error::FlowyResult;
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use tokio::{sync::broadcast, task::spawn_blocking};
|
||||
|
||||
use crate::entities::{SearchFilterPB, SearchResultNotificationPB, SearchResultPB};
|
||||
|
||||
use super::notifier::{SearchNotifier, SearchResultChanged, SearchResultReceiverRunner};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum SearchType {
|
||||
Folder,
|
||||
|
@ -1,4 +1,12 @@
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
pub const USER_SIGN_IN_URL: &str = "sign_in_url";
|
||||
pub const USER_UUID: &str = "uuid";
|
||||
pub const USER_EMAIL: &str = "email";
|
||||
pub const USER_DEVICE_ID: &str = "device_id";
|
||||
|
||||
/// Represents a user that is currently using the server.
|
||||
pub trait ServerUser: Send + Sync {
|
||||
/// different user might return different workspace id.
|
||||
fn workspace_id(&self) -> FlowyResult<String>;
|
||||
}
|
||||
|
@ -5,19 +5,26 @@ use client_api::error::ErrorCode::RecordNotFound;
|
||||
use collab::core::collab::DataSource;
|
||||
use collab::entity::EncodedCollab;
|
||||
use collab_entity::CollabType;
|
||||
use tracing::error;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, instrument};
|
||||
|
||||
use flowy_database_pub::cloud::{CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot};
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::AFServer;
|
||||
|
||||
pub(crate) struct AFCloudDatabaseCloudServiceImpl<T>(pub T);
|
||||
pub(crate) struct AFCloudDatabaseCloudServiceImpl<T> {
|
||||
pub inner: T,
|
||||
pub user: Arc<dyn ServerUser>,
|
||||
}
|
||||
|
||||
impl<T> DatabaseCloudService for AFCloudDatabaseCloudServiceImpl<T>
|
||||
where
|
||||
T: AFServer,
|
||||
{
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_database_object_doc_state(
|
||||
&self,
|
||||
object_id: &str,
|
||||
@ -26,17 +33,25 @@ where
|
||||
) -> FutureResult<Option<Vec<u8>>, Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let object_id = object_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab {
|
||||
object_id,
|
||||
collab_type,
|
||||
object_id: object_id.clone(),
|
||||
collab_type: collab_type.clone(),
|
||||
},
|
||||
};
|
||||
match try_get_client?.get_collab(params).await {
|
||||
Ok(data) => Ok(Some(data.encode_collab.doc_state.to_vec())),
|
||||
Ok(data) => {
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
&cloned_user,
|
||||
format!("get database object: {}:{}", object_id, collab_type),
|
||||
)?;
|
||||
Ok(Some(data.encode_collab.doc_state.to_vec()))
|
||||
},
|
||||
Err(err) => {
|
||||
if err.code == RecordNotFound {
|
||||
Ok(None)
|
||||
@ -48,6 +63,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn batch_get_database_object_doc_state(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
@ -55,7 +71,8 @@ where
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<CollabDocStateByOid, Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let params = object_ids
|
||||
@ -66,6 +83,11 @@ where
|
||||
})
|
||||
.collect();
|
||||
let results = client.batch_get_collab(&workspace_id, params).await?;
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
&cloned_user,
|
||||
"batch get database object",
|
||||
)?;
|
||||
Ok(
|
||||
results
|
||||
.0
|
||||
|
@ -4,30 +4,39 @@ use collab::core::collab::DataSource;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab_document::document::Document;
|
||||
use collab_entity::CollabType;
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_document_pub::cloud::*;
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::AFServer;
|
||||
|
||||
pub(crate) struct AFCloudDocumentCloudServiceImpl<T>(pub T);
|
||||
pub(crate) struct AFCloudDocumentCloudServiceImpl<T> {
|
||||
pub inner: T,
|
||||
pub user: Arc<dyn ServerUser>,
|
||||
}
|
||||
|
||||
impl<T> DocumentCloudService for AFCloudDocumentCloudServiceImpl<T>
|
||||
where
|
||||
T: AFServer,
|
||||
{
|
||||
#[instrument(level = "debug", skip_all, fields(document_id = %document_id))]
|
||||
fn get_document_doc_state(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Vec<u8>, FlowyError> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let document_id = document_id.to_string();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab {
|
||||
object_id: document_id.to_string(),
|
||||
collab_type: CollabType::Document,
|
||||
@ -40,6 +49,13 @@ where
|
||||
.encode_collab
|
||||
.doc_state
|
||||
.to_vec();
|
||||
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
&cloned_user,
|
||||
format!("get document doc state:{}", document_id),
|
||||
)?;
|
||||
|
||||
Ok(doc_state)
|
||||
})
|
||||
}
|
||||
@ -53,17 +69,19 @@ where
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_document_data(
|
||||
&self,
|
||||
document_id: &str,
|
||||
workspace_id: &str,
|
||||
) -> FutureResult<Option<DocumentData>, Error> {
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let document_id = document_id.to_string();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab {
|
||||
object_id: document_id.clone(),
|
||||
collab_type: CollabType::Document,
|
||||
@ -76,6 +94,11 @@ where
|
||||
.encode_collab
|
||||
.doc_state
|
||||
.to_vec();
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
&cloned_user,
|
||||
format!("Get {} document", document_id),
|
||||
)?;
|
||||
let document = Document::from_doc_state(
|
||||
CollabOrigin::Empty,
|
||||
DataSource::DocStateV1(doc_state),
|
||||
|
@ -6,6 +6,8 @@ use collab::core::collab::DataSource;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::RepeatedViewIdentifier;
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder_pub::cloud::{
|
||||
@ -14,16 +16,21 @@ use flowy_folder_pub::cloud::{
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::AFServer;
|
||||
|
||||
pub(crate) struct AFCloudFolderCloudServiceImpl<T>(pub T);
|
||||
pub(crate) struct AFCloudFolderCloudServiceImpl<T> {
|
||||
pub inner: T,
|
||||
pub user: Arc<dyn ServerUser>,
|
||||
}
|
||||
|
||||
impl<T> FolderCloudService for AFCloudFolderCloudServiceImpl<T>
|
||||
where
|
||||
T: AFServer,
|
||||
{
|
||||
fn create_workspace(&self, _uid: i64, name: &str) -> FutureResult<Workspace, Error> {
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_name = name.to_string();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
@ -47,7 +54,7 @@ where
|
||||
|
||||
fn open_workspace(&self, workspace_id: &str) -> FutureResult<(), Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let _ = client.open_workspace(&workspace_id).await?;
|
||||
@ -56,7 +63,7 @@ where
|
||||
}
|
||||
|
||||
fn get_all_workspace(&self) -> FutureResult<Vec<WorkspaceRecord>, Error> {
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let client = try_get_client?;
|
||||
let records = client
|
||||
@ -73,7 +80,7 @@ where
|
||||
Ok(records)
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_folder_data(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
@ -81,7 +88,8 @@ where
|
||||
) -> FutureResult<Option<FolderData>, Error> {
|
||||
let uid = *uid;
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id: workspace_id.clone(),
|
||||
@ -97,6 +105,7 @@ where
|
||||
.encode_collab
|
||||
.doc_state
|
||||
.to_vec();
|
||||
check_request_workspace_id_is_match(&workspace_id, &cloned_user, "get folder data")?;
|
||||
let folder = Folder::from_collab_doc_state(
|
||||
uid,
|
||||
CollabOrigin::Empty,
|
||||
@ -104,7 +113,7 @@ where
|
||||
&workspace_id,
|
||||
vec![],
|
||||
)?;
|
||||
Ok(folder.get_folder_data())
|
||||
Ok(folder.get_folder_data(&workspace_id))
|
||||
})
|
||||
}
|
||||
|
||||
@ -116,6 +125,7 @@ where
|
||||
FutureResult::new(async move { Ok(vec![]) })
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_folder_doc_state(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
@ -125,10 +135,11 @@ where
|
||||
) -> FutureResult<Vec<u8>, Error> {
|
||||
let object_id = object_id.to_string();
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab {
|
||||
object_id,
|
||||
collab_type,
|
||||
@ -141,6 +152,7 @@ where
|
||||
.encode_collab
|
||||
.doc_state
|
||||
.to_vec();
|
||||
check_request_workspace_id_is_match(&workspace_id, &cloned_user, "get folder doc state")?;
|
||||
Ok(doc_state)
|
||||
})
|
||||
}
|
||||
@ -151,7 +163,7 @@ where
|
||||
objects: Vec<FolderCollabParams>,
|
||||
) -> FutureResult<(), Error> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let try_get_client = self.0.try_get_client();
|
||||
let try_get_client = self.inner.try_get_client();
|
||||
FutureResult::new(async move {
|
||||
let params = objects
|
||||
.into_iter()
|
||||
|
@ -9,3 +9,4 @@ mod document;
|
||||
mod file_storage;
|
||||
mod folder;
|
||||
mod user;
|
||||
mod util;
|
||||
|
@ -13,6 +13,7 @@ use client_api::entity::{QueryCollab, QueryCollabParams};
|
||||
use client_api::{Client, ClientConfiguration};
|
||||
use collab_entity::{CollabObject, CollabType};
|
||||
use parking_lot::RwLock;
|
||||
use tracing::instrument;
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_user_pub::cloud::{UserCloudService, UserCollabParams, UserUpdate, UserUpdateReceiver};
|
||||
@ -24,11 +25,12 @@ use lib_infra::box_any::BoxAny;
|
||||
use lib_infra::future::FutureResult;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::af_cloud::define::USER_SIGN_IN_URL;
|
||||
use crate::af_cloud::define::{ServerUser, USER_SIGN_IN_URL};
|
||||
use crate::af_cloud::impls::user::dto::{
|
||||
af_update_from_update_params, from_af_workspace_member, to_af_role, user_profile_from_af_profile,
|
||||
};
|
||||
use crate::af_cloud::impls::user::util::encryption_type_from_profile;
|
||||
use crate::af_cloud::impls::util::check_request_workspace_id_is_match;
|
||||
use crate::af_cloud::{AFCloudClient, AFServer};
|
||||
|
||||
use super::dto::{from_af_workspace_invitation_status, to_workspace_invitation_status};
|
||||
@ -36,13 +38,19 @@ use super::dto::{from_af_workspace_invitation_status, to_workspace_invitation_st
|
||||
pub(crate) struct AFCloudUserAuthServiceImpl<T> {
|
||||
server: T,
|
||||
user_change_recv: RwLock<Option<tokio::sync::mpsc::Receiver<UserUpdate>>>,
|
||||
user: Arc<dyn ServerUser>,
|
||||
}
|
||||
|
||||
impl<T> AFCloudUserAuthServiceImpl<T> {
|
||||
pub(crate) fn new(server: T, user_change_recv: tokio::sync::mpsc::Receiver<UserUpdate>) -> Self {
|
||||
pub(crate) fn new(
|
||||
server: T,
|
||||
user_change_recv: tokio::sync::mpsc::Receiver<UserUpdate>,
|
||||
user: Arc<dyn ServerUser>,
|
||||
) -> Self {
|
||||
Self {
|
||||
server,
|
||||
user_change_recv: RwLock::new(Some(user_change_recv)),
|
||||
user,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,16 +174,27 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_user_profile(
|
||||
&self,
|
||||
_credential: UserCredentials,
|
||||
) -> FutureResult<UserProfile, FlowyError> {
|
||||
let try_get_client = self.server.try_get_client();
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let expected_workspace_id = cloned_user.workspace_id()?;
|
||||
let client = try_get_client?;
|
||||
let profile = client.get_profile().await?;
|
||||
let token = client.get_token()?;
|
||||
let profile = user_profile_from_af_profile(token, profile)?;
|
||||
|
||||
// Discard the response if the user has switched to a new workspace. This avoids updating the
|
||||
// user profile with potentially outdated information when the workspace ID no longer matches.
|
||||
check_request_workspace_id_is_match(
|
||||
&expected_workspace_id,
|
||||
&cloned_user,
|
||||
"get user profile",
|
||||
)?;
|
||||
Ok(profile)
|
||||
})
|
||||
}
|
||||
@ -315,6 +334,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn get_user_awareness_doc_state(
|
||||
&self,
|
||||
_uid: i64,
|
||||
@ -324,16 +344,21 @@ where
|
||||
let workspace_id = workspace_id.to_string();
|
||||
let object_id = object_id.to_string();
|
||||
let try_get_client = self.server.try_get_client();
|
||||
FutureResult::new(async {
|
||||
let cloned_user = self.user.clone();
|
||||
FutureResult::new(async move {
|
||||
let params = QueryCollabParams {
|
||||
workspace_id,
|
||||
workspace_id: workspace_id.clone(),
|
||||
inner: QueryCollab {
|
||||
object_id,
|
||||
collab_type: CollabType::UserAwareness,
|
||||
},
|
||||
};
|
||||
|
||||
let resp = try_get_client?.get_collab(params).await?;
|
||||
check_request_workspace_id_is_match(
|
||||
&workspace_id,
|
||||
&cloned_user,
|
||||
"get user awareness object",
|
||||
)?;
|
||||
Ok(resp.encode_collab.doc_state.to_vec())
|
||||
})
|
||||
}
|
||||
|
29
frontend/rust-lib/flowy-server/src/af_cloud/impls/util.rs
Normal file
29
frontend/rust-lib/flowy-server/src/af_cloud/impls/util.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
|
||||
/// Validates the workspace_id provided in the request.
|
||||
/// It checks that the workspace_id from the request matches the current user's active workspace_id.
|
||||
/// This ensures that the operation is being performed in the correct workspace context, enhancing security.
|
||||
pub fn check_request_workspace_id_is_match(
|
||||
expected_workspace_id: &str,
|
||||
user: &Arc<dyn ServerUser>,
|
||||
action: impl AsRef<str>,
|
||||
) -> FlowyResult<()> {
|
||||
let actual_workspace_id = user.workspace_id()?;
|
||||
if expected_workspace_id != actual_workspace_id {
|
||||
warn!(
|
||||
"{}, expect workspace_id: {}, actual workspace_id: {}",
|
||||
action.as_ref(),
|
||||
expected_workspace_id,
|
||||
actual_workspace_id
|
||||
);
|
||||
|
||||
return Err(
|
||||
FlowyError::internal()
|
||||
.with_context("Current workspace was changed when processing the request"),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -17,6 +17,7 @@ use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::{error, event, info, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::af_cloud::define::ServerUser;
|
||||
use flowy_database_pub::cloud::DatabaseCloudService;
|
||||
use flowy_document_pub::cloud::DocumentCloudService;
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
@ -42,6 +43,7 @@ pub struct AppFlowyCloudServer {
|
||||
network_reachable: Arc<AtomicBool>,
|
||||
pub device_id: String,
|
||||
ws_client: Arc<WSClient>,
|
||||
user: Arc<dyn ServerUser>,
|
||||
}
|
||||
|
||||
impl AppFlowyCloudServer {
|
||||
@ -50,6 +52,7 @@ impl AppFlowyCloudServer {
|
||||
enable_sync: bool,
|
||||
mut device_id: String,
|
||||
client_version: &str,
|
||||
user: Arc<dyn ServerUser>,
|
||||
) -> Self {
|
||||
// The device id can't be empty, so we generate a new one if it is.
|
||||
if device_id.is_empty() {
|
||||
@ -83,6 +86,7 @@ impl AppFlowyCloudServer {
|
||||
network_reachable,
|
||||
device_id,
|
||||
ws_client,
|
||||
user,
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,28 +163,41 @@ impl AppFlowyServer for AppFlowyCloudServer {
|
||||
}
|
||||
});
|
||||
|
||||
Arc::new(AFCloudUserAuthServiceImpl::new(server, rx))
|
||||
Arc::new(AFCloudUserAuthServiceImpl::new(
|
||||
server,
|
||||
rx,
|
||||
self.user.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
fn folder_service(&self) -> Arc<dyn FolderCloudService> {
|
||||
let server = AFServerImpl {
|
||||
client: self.get_client(),
|
||||
};
|
||||
Arc::new(AFCloudFolderCloudServiceImpl(server))
|
||||
Arc::new(AFCloudFolderCloudServiceImpl {
|
||||
inner: server,
|
||||
user: self.user.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn database_service(&self) -> Arc<dyn DatabaseCloudService> {
|
||||
let server = AFServerImpl {
|
||||
client: self.get_client(),
|
||||
};
|
||||
Arc::new(AFCloudDatabaseCloudServiceImpl(server))
|
||||
Arc::new(AFCloudDatabaseCloudServiceImpl {
|
||||
inner: server,
|
||||
user: self.user.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
|
||||
let server = AFServerImpl {
|
||||
client: self.get_client(),
|
||||
};
|
||||
Arc::new(AFCloudDocumentCloudServiceImpl(server))
|
||||
Arc::new(AFCloudDocumentCloudServiceImpl {
|
||||
inner: server,
|
||||
user: self.user.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn subscribe_ws_state(&self) -> Option<WSConnectStateReceiver> {
|
||||
|
@ -109,7 +109,7 @@ where
|
||||
&workspace_id,
|
||||
vec![],
|
||||
)?;
|
||||
Ok(folder.get_folder_data())
|
||||
Ok(folder.get_folder_data(&workspace_id))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,10 @@ use client_api::ClientConfiguration;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
use uuid::Uuid;
|
||||
|
||||
use flowy_server::af_cloud::define::ServerUser;
|
||||
use flowy_server::af_cloud::AppFlowyCloudServer;
|
||||
use flowy_server::supabase::define::{USER_DEVICE_ID, USER_SIGN_IN_URL};
|
||||
use flowy_server_pub::af_cloud_config::AFCloudConfiguration;
|
||||
@ -31,9 +33,17 @@ pub fn af_cloud_server(config: AFCloudConfiguration) -> Arc<AppFlowyCloudServer>
|
||||
true,
|
||||
fake_device_id,
|
||||
"0.5.1",
|
||||
Arc::new(FakeServerUserImpl),
|
||||
))
|
||||
}
|
||||
|
||||
struct FakeServerUserImpl;
|
||||
impl ServerUser for FakeServerUserImpl {
|
||||
fn workspace_id(&self) -> FlowyResult<String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn generate_sign_in_url(user_email: &str, config: &AFCloudConfiguration) -> String {
|
||||
let client = client_api::Client::new(
|
||||
&config.base_url,
|
||||
|
@ -134,7 +134,7 @@ pub async fn print_encryption_folder_snapshot(
|
||||
));
|
||||
let folder_data = Folder::open(uid, collab, None)
|
||||
.unwrap()
|
||||
.get_folder_data()
|
||||
.get_folder_data(folder_id)
|
||||
.unwrap();
|
||||
let json = serde_json::to_value(folder_data).unwrap();
|
||||
println!("{}", serde_json::to_string_pretty(&json).unwrap());
|
||||
|
@ -226,8 +226,9 @@ where
|
||||
None,
|
||||
)
|
||||
.map_err(|err| PersistenceError::InvalidData(err.to_string()))?;
|
||||
let mut folder_data = old_folder
|
||||
.get_folder_data()
|
||||
let mut folder_data =
|
||||
old_folder
|
||||
.get_folder_data(old_workspace_id)
|
||||
.ok_or(PersistenceError::Internal(anyhow!(
|
||||
"Can't migrate the folder data"
|
||||
)))?;
|
||||
|
@ -49,7 +49,7 @@ pub async fn sync_supabase_user_data_to_cloud(
|
||||
)
|
||||
.await;
|
||||
|
||||
let views = folder.lock().get_current_workspace_views();
|
||||
let views = folder.lock().get_views_belong_to(&workspace_id);
|
||||
for view in views {
|
||||
let view_id = view.id.clone();
|
||||
if let Err(err) = sync_view(
|
||||
|
@ -53,8 +53,8 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration {
|
||||
|
||||
let folder = Folder::open(session.user_id, folder_collab, None)
|
||||
.map_err(|err| PersistenceError::Internal(err.into()))?;
|
||||
let migration_views = folder.get_workspace_views();
|
||||
|
||||
if let Ok(workspace_id) = folder.try_get_workspace_id() {
|
||||
let migration_views = folder.views.get_views_belong_to(&workspace_id);
|
||||
// For historical reasons, the first level documents are empty. So migrate them by inserting
|
||||
// the default document data.
|
||||
for view in migration_views {
|
||||
@ -66,6 +66,7 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -16,7 +16,7 @@ use tracing::{error, info};
|
||||
const SQLITE_VACUUM_042: &str = "sqlite_vacuum_042_version";
|
||||
|
||||
pub struct AuthenticateUser {
|
||||
pub(crate) user_config: UserConfig,
|
||||
pub user_config: UserConfig,
|
||||
pub(crate) database: Arc<UserDB>,
|
||||
pub(crate) user_paths: UserPaths,
|
||||
store_preferences: Arc<StorePreferences>,
|
||||
@ -67,6 +67,11 @@ impl AuthenticateUser {
|
||||
Ok(session.user_workspace.id)
|
||||
}
|
||||
|
||||
pub fn workspace_database_object_id(&self) -> FlowyResult<String> {
|
||||
let session = self.get_session()?;
|
||||
Ok(session.user_workspace.workspace_database_object_id.clone())
|
||||
}
|
||||
|
||||
pub fn get_collab_db(&self, uid: i64) -> FlowyResult<Weak<CollabKVDB>> {
|
||||
self
|
||||
.database
|
||||
|
@ -509,7 +509,7 @@ where
|
||||
.map_err(|err| PersistenceError::InvalidData(err.to_string()))?;
|
||||
|
||||
let other_folder_data = other_folder
|
||||
.get_folder_data()
|
||||
.get_folder_data(&other_session.user_workspace.id)
|
||||
.ok_or(PersistenceError::Internal(anyhow!(
|
||||
"Can't read the folder data"
|
||||
)))?;
|
||||
|
@ -518,7 +518,6 @@ impl UserManager {
|
||||
|
||||
pub async fn prepare_user(&self, session: &Session) {
|
||||
let _ = self.authenticate_user.database.close(session.user_id);
|
||||
self.prepare_collab(session);
|
||||
}
|
||||
|
||||
pub async fn prepare_backup(&self, session: &Session) {
|
||||
@ -724,11 +723,6 @@ impl UserManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prepare_collab(&self, session: &Session) {
|
||||
let collab_builder = self.collab_builder.upgrade().unwrap();
|
||||
collab_builder.initialize(session.user_workspace.id.clone());
|
||||
}
|
||||
|
||||
async fn handler_user_update(&self, user_update: UserUpdate) -> FlowyResult<()> {
|
||||
let session = self.get_session()?;
|
||||
if session.user_id == user_update.uid {
|
||||
|
@ -136,6 +136,7 @@ impl UserManager {
|
||||
let weak_builder = self.collab_builder.clone();
|
||||
let cloned_is_loading = self.is_loading_awareness.clone();
|
||||
let session = session.clone();
|
||||
let workspace_id = session.user_workspace.id.clone();
|
||||
tokio::spawn(async move {
|
||||
if cloned_is_loading.load(Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
@ -160,6 +161,7 @@ impl UserManager {
|
||||
Ok(data) => {
|
||||
trace!("Get user awareness collab from remote: {}", data.len());
|
||||
let collab = Self::collab_for_user_awareness(
|
||||
&workspace_id,
|
||||
&weak_builder,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
@ -173,6 +175,7 @@ impl UserManager {
|
||||
if err.is_record_not_found() {
|
||||
info!("User awareness not found, creating new");
|
||||
let collab = Self::collab_for_user_awareness(
|
||||
&workspace_id,
|
||||
&weak_builder,
|
||||
session.user_id,
|
||||
&object_id,
|
||||
@ -206,6 +209,7 @@ impl UserManager {
|
||||
/// using a collaboration builder. This instance is specifically geared towards handling
|
||||
/// user awareness.
|
||||
async fn collab_for_user_awareness(
|
||||
workspace_id: &str,
|
||||
collab_builder: &Weak<AppFlowyCollabBuilder>,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
@ -218,6 +222,7 @@ impl UserManager {
|
||||
))?;
|
||||
let collab = collab_builder
|
||||
.build(
|
||||
workspace_id,
|
||||
uid,
|
||||
object_id,
|
||||
CollabType::UserAwareness,
|
||||
|
@ -136,7 +136,6 @@ impl UserManager {
|
||||
#[instrument(skip(self), err)]
|
||||
pub async fn open_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||
info!("open workspace: {}", workspace_id);
|
||||
let uid = self.user_id()?;
|
||||
let user_workspace = self
|
||||
.cloud_services
|
||||
.get_user_service()?
|
||||
@ -146,6 +145,8 @@ impl UserManager {
|
||||
self
|
||||
.authenticate_user
|
||||
.set_user_workspace(user_workspace.clone())?;
|
||||
|
||||
let uid = self.user_id()?;
|
||||
if let Err(err) = self
|
||||
.user_status_callback
|
||||
.read()
|
||||
|
Loading…
Reference in New Issue
Block a user