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